mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 07:36:15 +00:00
Allow array size to be a module-scope constant
Change ast::Array to use an ast::Expression for its `size` field. The WGSL frontend now parses the array size as an `primary_expression`, and the Resolver is responsible for validating the expression is a signed or unsigned integer, and either a literal or a non-overridable module-scope constant. The Resolver evaluates the constant value of the size expression, and so the resolved sem::Array type still has a constant size as before. Fixed: tint:1068 Fixed: tint:1117 Change-Id: Icfa141482ea1e47ea8c21a25e9eb48221f176e9a Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/63061 Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: James Price <jrprice@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
committed by
Tint LUCI CQ
parent
69ce5f74ed
commit
4cc4315d6c
@@ -23,10 +23,32 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Array);
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
namespace {
|
||||
// Returns the string representation of an array size expression.
|
||||
std::string SizeExprToString(const ast::Expression* size,
|
||||
const SymbolTable* symbols = nullptr) {
|
||||
if (auto* ident = size->As<ast::IdentifierExpression>()) {
|
||||
if (symbols) {
|
||||
return symbols->NameFor(ident->symbol());
|
||||
} else {
|
||||
return ident->symbol().to_str();
|
||||
}
|
||||
} else if (auto* scalar = size->As<ast::ScalarConstructorExpression>()) {
|
||||
auto* literal = scalar->literal()->As<ast::IntLiteral>();
|
||||
if (literal) {
|
||||
return std::to_string(literal->value_as_u32());
|
||||
}
|
||||
}
|
||||
// This will never be exposed to the user as the Resolver will reject this
|
||||
// expression for array size.
|
||||
return "<invalid>";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Array::Array(ProgramID program_id,
|
||||
const Source& source,
|
||||
Type* subtype,
|
||||
uint32_t size,
|
||||
ast::Expression* size,
|
||||
ast::DecorationList decorations)
|
||||
: Base(program_id, source),
|
||||
subtype_(subtype),
|
||||
@@ -42,7 +64,7 @@ std::string Array::type_name() const {
|
||||
|
||||
std::string type_name = "__array" + subtype_->type_name();
|
||||
if (!IsRuntimeArray()) {
|
||||
type_name += "_" + std::to_string(size_);
|
||||
type_name += "_" + SizeExprToString(size_);
|
||||
}
|
||||
for (auto* deco : decos_) {
|
||||
if (auto* stride = deco->As<ast::StrideDecoration>()) {
|
||||
@@ -62,7 +84,7 @@ std::string Array::FriendlyName(const SymbolTable& symbols) const {
|
||||
}
|
||||
out << "array<" << subtype_->FriendlyName(symbols);
|
||||
if (!IsRuntimeArray()) {
|
||||
out << ", " << size_;
|
||||
out << ", " << SizeExprToString(size_, &symbols);
|
||||
}
|
||||
out << ">";
|
||||
return out.str();
|
||||
@@ -72,8 +94,9 @@ Array* Array::Clone(CloneContext* ctx) const {
|
||||
// Clone arguments outside of create() call to have deterministic ordering
|
||||
auto src = ctx->Clone(source());
|
||||
auto* ty = ctx->Clone(type());
|
||||
auto* size = ctx->Clone(Size());
|
||||
auto decos = ctx->Clone(decorations());
|
||||
return ctx->dst->create<Array>(src, ty, size_, decos);
|
||||
return ctx->dst->create<Array>(src, ty, size, decos);
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
// Forward declarations.
|
||||
class Expression;
|
||||
|
||||
/// An array type. If size is zero then it is a runtime array.
|
||||
class Array : public Castable<Array, Type> {
|
||||
public:
|
||||
@@ -30,13 +33,13 @@ class Array : public Castable<Array, Type> {
|
||||
/// @param program_id the identifier of the program that owns this node
|
||||
/// @param source the source of this node
|
||||
/// @param subtype the type of the array elements
|
||||
/// @param size the number of elements in the array. `0` represents a
|
||||
/// @param size the number of elements in the array. nullptr represents a
|
||||
/// runtime-sized array.
|
||||
/// @param decorations the array decorations
|
||||
Array(ProgramID program_id,
|
||||
const Source& source,
|
||||
Type* subtype,
|
||||
uint32_t size,
|
||||
ast::Expression* size,
|
||||
ast::DecorationList decorations);
|
||||
/// Move constructor
|
||||
Array(Array&&);
|
||||
@@ -44,15 +47,16 @@ class Array : public Castable<Array, Type> {
|
||||
|
||||
/// @returns true if this is a runtime array.
|
||||
/// i.e. the size is determined at runtime
|
||||
bool IsRuntimeArray() const { return size_ == 0; }
|
||||
bool IsRuntimeArray() const { return size_ == nullptr; }
|
||||
|
||||
/// @returns the array decorations
|
||||
const ast::DecorationList& decorations() const { return decos_; }
|
||||
|
||||
/// @returns the array type
|
||||
Type* type() const { return subtype_; }
|
||||
/// @returns the array size. Size is 0 for a runtime array
|
||||
uint32_t size() const { return size_; }
|
||||
|
||||
/// @returns the array size, or nullptr for a runtime array
|
||||
ast::Expression* Size() const { return size_; }
|
||||
|
||||
/// @returns the name for the type
|
||||
std::string type_name() const override;
|
||||
@@ -69,7 +73,7 @@ class Array : public Castable<Array, Type> {
|
||||
|
||||
private:
|
||||
Type* const subtype_;
|
||||
uint32_t const size_;
|
||||
ast::Expression* const size_;
|
||||
ast::DecorationList const decos_;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,57 +24,76 @@ using AstArrayTest = TestHelper;
|
||||
|
||||
TEST_F(AstArrayTest, CreateSizedArray) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* arr = create<Array>(u32, 3, DecorationList{});
|
||||
auto* size = Expr(3);
|
||||
auto* arr = create<Array>(u32, size, DecorationList{});
|
||||
EXPECT_EQ(arr->type(), u32);
|
||||
EXPECT_EQ(arr->size(), 3u);
|
||||
EXPECT_EQ(arr->Size(), size);
|
||||
EXPECT_TRUE(arr->Is<Array>());
|
||||
EXPECT_FALSE(arr->IsRuntimeArray());
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, CreateRuntimeArray) {
|
||||
auto* u32 = create<U32>();
|
||||
auto* arr = create<Array>(u32, 0, DecorationList{});
|
||||
auto* arr = create<Array>(u32, nullptr, DecorationList{});
|
||||
EXPECT_EQ(arr->type(), u32);
|
||||
EXPECT_EQ(arr->size(), 0u);
|
||||
EXPECT_EQ(arr->Size(), nullptr);
|
||||
EXPECT_TRUE(arr->Is<Array>());
|
||||
EXPECT_TRUE(arr->IsRuntimeArray());
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, TypeName) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, 0, DecorationList{});
|
||||
auto* arr = create<Array>(i32, nullptr, DecorationList{});
|
||||
EXPECT_EQ(arr->type_name(), "__array__i32");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, FriendlyNameRuntimeSized) {
|
||||
TEST_F(AstArrayTest, FriendlyName_RuntimeSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, 0, DecorationList{});
|
||||
auto* arr = create<Array>(i32, nullptr, DecorationList{});
|
||||
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, FriendlyNameStaticSized) {
|
||||
TEST_F(AstArrayTest, FriendlyName_LiteralSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, 5, DecorationList{});
|
||||
auto* arr = create<Array>(i32, Expr(5), DecorationList{});
|
||||
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, FriendlyNameWithStride) {
|
||||
TEST_F(AstArrayTest, FriendlyName_ConstantSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, Expr("size"), DecorationList{});
|
||||
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, FriendlyName_WithStride) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr =
|
||||
create<Array>(i32, 5, DecorationList{create<StrideDecoration>(32)});
|
||||
create<Array>(i32, Expr(5), DecorationList{create<StrideDecoration>(32)});
|
||||
EXPECT_EQ(arr->FriendlyName(Symbols()), "[[stride(32)]] array<i32, 5>");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, TypeName_RuntimeArray) {
|
||||
TEST_F(AstArrayTest, TypeName_RuntimeSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, 3, DecorationList{});
|
||||
auto* arr = create<Array>(i32, nullptr, DecorationList{});
|
||||
EXPECT_EQ(arr->type_name(), "__array__i32");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, TypeName_LiteralSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, Expr(3), DecorationList{});
|
||||
EXPECT_EQ(arr->type_name(), "__array__i32_3");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, TypeName_ConstantSized) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr = create<Array>(i32, Expr("size"), DecorationList{});
|
||||
EXPECT_EQ(arr->type_name(), "__array__i32_$1");
|
||||
}
|
||||
|
||||
TEST_F(AstArrayTest, TypeName_WithStride) {
|
||||
auto* i32 = create<I32>();
|
||||
auto* arr =
|
||||
create<Array>(i32, 3, DecorationList{create<StrideDecoration>(16)});
|
||||
create<Array>(i32, Expr(3), DecorationList{create<StrideDecoration>(16)});
|
||||
EXPECT_EQ(arr->type_name(), "__array__i32_3_stride_16");
|
||||
}
|
||||
|
||||
|
||||
@@ -622,66 +622,85 @@ class ProgramBuilder {
|
||||
}
|
||||
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param n the array size. nullptr represents a runtime-array
|
||||
/// @param decos the optional decorations for the array
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
template <typename EXPR = ast::Expression*>
|
||||
ast::Array* array(ast::Type* subtype,
|
||||
uint32_t n = 0,
|
||||
EXPR&& n = nullptr,
|
||||
ast::DecorationList decos = {}) const {
|
||||
return builder->create<ast::Array>(subtype, n, decos);
|
||||
return builder->create<ast::Array>(
|
||||
subtype, builder->Expr(std::forward<EXPR>(n)), decos);
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param n the array size. nullptr represents a runtime-array
|
||||
/// @param decos the optional decorations for the array
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
template <typename EXPR = ast::Expression*>
|
||||
ast::Array* array(const Source& source,
|
||||
ast::Type* subtype,
|
||||
uint32_t n = 0,
|
||||
EXPR&& n = nullptr,
|
||||
ast::DecorationList decos = {}) const {
|
||||
return builder->create<ast::Array>(source, subtype, n, decos);
|
||||
return builder->create<ast::Array>(
|
||||
source, subtype, builder->Expr(std::forward<EXPR>(n)), decos);
|
||||
}
|
||||
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param n the array size. nullptr represents a runtime-array
|
||||
/// @param stride the array stride. 0 represents implicit stride
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
ast::Array* array(ast::Type* subtype, uint32_t n, uint32_t stride) const {
|
||||
template <typename EXPR>
|
||||
ast::Array* array(ast::Type* subtype, EXPR&& n, uint32_t stride) const {
|
||||
ast::DecorationList decos;
|
||||
if (stride) {
|
||||
decos.emplace_back(builder->create<ast::StrideDecoration>(stride));
|
||||
}
|
||||
return array(subtype, n, std::move(decos));
|
||||
return array(subtype, std::forward<EXPR>(n), std::move(decos));
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param n the array size. nullptr represents a runtime-array
|
||||
/// @param stride the array stride. 0 represents implicit stride
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
template <typename EXPR>
|
||||
ast::Array* array(const Source& source,
|
||||
ast::Type* subtype,
|
||||
uint32_t n,
|
||||
EXPR&& n,
|
||||
uint32_t stride) const {
|
||||
ast::DecorationList decos;
|
||||
if (stride) {
|
||||
decos.emplace_back(builder->create<ast::StrideDecoration>(stride));
|
||||
}
|
||||
return array(source, subtype, n, std::move(decos));
|
||||
return array(source, subtype, std::forward<EXPR>(n), std::move(decos));
|
||||
}
|
||||
|
||||
/// @return the tint AST type for a runtime-sized array of type `T`
|
||||
template <typename T>
|
||||
ast::Array* array() const {
|
||||
return array(Of<T>(), nullptr);
|
||||
}
|
||||
|
||||
/// @return the tint AST type for an array of size `N` of type `T`
|
||||
template <typename T, int N = 0>
|
||||
template <typename T, int N>
|
||||
ast::Array* array() const {
|
||||
return array(Of<T>(), N);
|
||||
return array(Of<T>(), builder->Expr(N));
|
||||
}
|
||||
|
||||
/// @param stride the array stride
|
||||
/// @return the tint AST type for a runtime-sized array of type `T`
|
||||
template <typename T>
|
||||
ast::Array* array(uint32_t stride) const {
|
||||
return array(Of<T>(), nullptr, stride);
|
||||
}
|
||||
|
||||
/// @param stride the array stride
|
||||
/// @return the tint AST type for an array of size `N` of type `T`
|
||||
template <typename T, int N = 0>
|
||||
template <typename T, int N>
|
||||
ast::Array* array(uint32_t stride) const {
|
||||
return array(Of<T>(), N, stride);
|
||||
return array(Of<T>(), builder->Expr(N), stride);
|
||||
}
|
||||
|
||||
/// Creates a type name
|
||||
@@ -1273,22 +1292,23 @@ class ProgramBuilder {
|
||||
|
||||
/// @param args the arguments for the array constructor
|
||||
/// @return an `ast::TypeConstructorExpression` of an array with element type
|
||||
/// `T`, constructed with the values `args`.
|
||||
template <typename T, int N = 0, typename... ARGS>
|
||||
/// `T` and size `N`, constructed with the values `args`.
|
||||
template <typename T, int N, typename... ARGS>
|
||||
ast::TypeConstructorExpression* array(ARGS&&... args) {
|
||||
return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array.
|
||||
/// @param n the array size. nullptr represents a runtime-array.
|
||||
/// @param args the arguments for the array constructor
|
||||
/// @return an `ast::TypeConstructorExpression` of an array with element type
|
||||
/// `subtype`, constructed with the values `args`.
|
||||
template <typename... ARGS>
|
||||
template <typename EXPR, typename... ARGS>
|
||||
ast::TypeConstructorExpression* array(ast::Type* subtype,
|
||||
uint32_t n,
|
||||
EXPR&& n,
|
||||
ARGS&&... args) {
|
||||
return Construct(ty.array(subtype, n), std::forward<ARGS>(args)...);
|
||||
return Construct(ty.array(subtype, std::forward<EXPR>(n)),
|
||||
std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
/// @param name the variable name
|
||||
|
||||
@@ -187,7 +187,11 @@ Array::Array(const Type* t, uint32_t sz, uint32_t st)
|
||||
Array::Array(const Array&) = default;
|
||||
|
||||
ast::Type* Array::Build(ProgramBuilder& b) const {
|
||||
return b.ty.array(type->Build(b), size, stride);
|
||||
if (size > 0) {
|
||||
return b.ty.array(type->Build(b), size, stride);
|
||||
} else {
|
||||
return b.ty.array(type->Build(b), nullptr, stride);
|
||||
}
|
||||
}
|
||||
|
||||
Sampler::Sampler(ast::SamplerKind k) : kind(k) {}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ Expect<ast::Type*> ParserImpl::expect_type_decl_array(
|
||||
ast::DecorationList decos) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
uint32_t size = 0;
|
||||
ast::Expression* size = nullptr;
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<ast::Type*> {
|
||||
auto type = expect_type(use);
|
||||
@@ -1195,10 +1195,14 @@ Expect<ast::Type*> ParserImpl::expect_type_decl_array(
|
||||
return Failure::kErrored;
|
||||
|
||||
if (match(Token::Type::kComma)) {
|
||||
auto val = expect_nonzero_positive_sint("array size");
|
||||
if (val.errored)
|
||||
auto expr = primary_expression();
|
||||
if (expr.errored) {
|
||||
return Failure::kErrored;
|
||||
size = val.value;
|
||||
} else if (!expr.matched) {
|
||||
return add_error(peek(), "expected array size expression");
|
||||
}
|
||||
|
||||
size = std::move(expr.value);
|
||||
}
|
||||
|
||||
return type.value;
|
||||
|
||||
@@ -862,19 +862,18 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
|
||||
EXPECT(
|
||||
"var i : array<u32, x>;",
|
||||
"test.wgsl:1:20 error: expected signed integer literal for array size\n"
|
||||
"var i : array<u32, x>;\n"
|
||||
" ^\n");
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingSize) {
|
||||
EXPECT("var i : array<u32, >;",
|
||||
"test.wgsl:1:20 error: expected array size expression\n"
|
||||
"var i : array<u32, >;\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayNegativeSize) {
|
||||
EXPECT("var i : array<u32, -3>;",
|
||||
"test.wgsl:1:20 error: array size must be greater than 0\n"
|
||||
"var i : array<u32, -3>;\n"
|
||||
" ^^\n");
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
|
||||
EXPECT("var i : array<u32, !>;",
|
||||
"test.wgsl:1:20 error: expected array size expression\n"
|
||||
"var i : array<u32, !>;\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListEmpty) {
|
||||
|
||||
@@ -440,7 +440,7 @@ TEST_F(ParserImplTest, TypeDecl_Atomic_MissingType) {
|
||||
ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array) {
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_SintLiteralSize) {
|
||||
auto p = parser("array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
@@ -451,10 +451,57 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_EQ(a->size(), 5u);
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 14u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::SintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 5);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_UintLiteralSize) {
|
||||
auto p = parser("array<f32, 5u>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 15u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::UintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_u32(), 5u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
|
||||
auto p = parser("array<f32, size>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::IdentifierExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
EXPECT_EQ(p->builder().Symbols().NameFor(size_expr->symbol()), "size");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
@@ -468,9 +515,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_EQ(a->size(), 5u);
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::SintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 5);
|
||||
|
||||
ASSERT_EQ(a->decorations().size(), 1u);
|
||||
auto* stride = a->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
@@ -664,34 +716,24 @@ TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
|
||||
ASSERT_EQ(p->error(), "1:7: unknown type 'unknown'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
|
||||
auto p = parser("array<f32, 0>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
|
||||
auto p = parser("array<f32, -1>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
|
||||
auto p = parser("array<f32, invalid>");
|
||||
auto p = parser("array<f32, !>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size");
|
||||
ASSERT_EQ(p->error(), "1:12: expected array size expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MissingSize) {
|
||||
auto p = parser("array<f32,>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected array size expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
|
||||
|
||||
@@ -62,6 +62,49 @@ TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypes) {
|
||||
EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
|
||||
}
|
||||
|
||||
TEST_F(ResolverAssignmentValidationTest,
|
||||
AssignArraysWithDifferentSizeExpressions_Pass) {
|
||||
// let len = 4u;
|
||||
// {
|
||||
// var a : array<f32, 4>;
|
||||
// var b : array<f32, len>;
|
||||
// a = b;
|
||||
// }
|
||||
|
||||
GlobalConst("len", nullptr, Expr(4u));
|
||||
|
||||
auto* a = Var("a", ty.array(ty.f32(), 4));
|
||||
auto* b = Var("b", ty.array(ty.f32(), "len"));
|
||||
|
||||
auto* assign = Assign(Source{{12, 34}}, "a", "b");
|
||||
WrapInFunction(a, b, assign);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverAssignmentValidationTest,
|
||||
AssignArraysWithDifferentSizeExpressions_Fail) {
|
||||
// let len = 5u;
|
||||
// {
|
||||
// var a : array<f32, 4>;
|
||||
// var b : array<f32, len>;
|
||||
// a = b;
|
||||
// }
|
||||
|
||||
GlobalConst("len", nullptr, Expr(5u));
|
||||
|
||||
auto* a = Var("a", ty.array(ty.f32(), 4));
|
||||
auto* b = Var("b", ty.array(ty.f32(), "len"));
|
||||
|
||||
auto* assign = Assign(Source{{12, 34}}, "a", "b");
|
||||
WrapInFunction(a, b, assign);
|
||||
|
||||
ASSERT_FALSE(r()->Resolve());
|
||||
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: cannot assign 'array<f32, len>' to 'array<f32, 4>'");
|
||||
}
|
||||
|
||||
TEST_F(ResolverAssignmentValidationTest,
|
||||
AssignCompatibleTypesInBlockStatement_Pass) {
|
||||
// {
|
||||
|
||||
@@ -681,7 +681,7 @@ using ArrayDecorationTest = TestWithParams;
|
||||
TEST_P(ArrayDecorationTest, IsValid) {
|
||||
auto& params = GetParam();
|
||||
|
||||
auto* arr = ty.array(ty.f32(), 0,
|
||||
auto* arr = ty.array(ty.f32(), nullptr,
|
||||
createDecorations(Source{{12, 34}}, *this, params.kind));
|
||||
Structure("mystruct",
|
||||
{
|
||||
|
||||
@@ -698,7 +698,7 @@ TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
|
||||
}
|
||||
|
||||
TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_RuntimeArray) {
|
||||
auto* ret_type = ty.array(Source{{12, 34}}, ty.i32(), 0);
|
||||
auto* ret_type = ty.array(Source{{12, 34}}, ty.i32());
|
||||
Func("f", {}, ret_type, {});
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
|
||||
@@ -3868,11 +3868,68 @@ sem::Array* Resolver::Array(const ast::Array* arr) {
|
||||
|
||||
auto stride = explicit_stride ? explicit_stride : implicit_stride;
|
||||
|
||||
// WebGPU requires runtime arrays have at least one element, but the AST
|
||||
// records an element count of 0 for it.
|
||||
auto size = std::max<uint32_t>(arr->size(), 1) * stride;
|
||||
auto* out = builder_->create<sem::Array>(elem_type, arr->size(), el_align,
|
||||
size, stride, implicit_stride);
|
||||
// Evaluate the constant array size expression.
|
||||
// sem::Array uses a size of 0 for a runtime-sized array.
|
||||
uint32_t count = 0;
|
||||
if (auto* count_expr = arr->Size()) {
|
||||
Mark(count_expr);
|
||||
if (!Expression(count_expr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto size_source = count_expr->source();
|
||||
|
||||
auto* ty = TypeOf(count_expr)->UnwrapRef();
|
||||
if (!ty->is_integer_scalar()) {
|
||||
AddError("array size must be integer scalar", size_source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto* ident = count_expr->As<ast::IdentifierExpression>()) {
|
||||
// Make sure the identifier is a non-overridable module-scope constant.
|
||||
VariableInfo* var = nullptr;
|
||||
bool is_global = false;
|
||||
if (!variable_stack_.get(ident->symbol(), &var, &is_global) ||
|
||||
!is_global || !var->declaration->is_const()) {
|
||||
AddError("array size identifier must be a module-scope constant",
|
||||
size_source);
|
||||
return nullptr;
|
||||
}
|
||||
if (ast::HasDecoration<ast::OverrideDecoration>(
|
||||
var->declaration->decorations())) {
|
||||
AddError("array size expression must not be pipeline-overridable",
|
||||
size_source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
count_expr = var->declaration->constructor();
|
||||
} else if (!count_expr->Is<ast::ScalarConstructorExpression>()) {
|
||||
AddError(
|
||||
"array size expression must be either a literal or a module-scope "
|
||||
"constant",
|
||||
size_source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto count_val = ConstantValueOf(count_expr);
|
||||
if (!count_val) {
|
||||
TINT_ICE(Resolver, diagnostics_)
|
||||
<< "could not resolve array size expression";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ty->is_signed_integer_scalar() ? count_val.Elements()[0].i32 < 1
|
||||
: count_val.Elements()[0].u32 < 1u) {
|
||||
AddError("array size must be at least 1", size_source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
count = count_val.Elements()[0].u32;
|
||||
}
|
||||
|
||||
auto size = std::max<uint32_t>(count, 1) * stride;
|
||||
auto* out = builder_->create<sem::Array>(elem_type, count, el_align, size,
|
||||
stride, implicit_stride);
|
||||
|
||||
if (!ValidateArray(out, source)) {
|
||||
return nullptr;
|
||||
|
||||
@@ -431,6 +431,66 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
|
||||
EXPECT_EQ(VarOf(fn_f32->constructor())->Declaration(), mod_f32);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
|
||||
// var<private> a : array<f32, 10u>;
|
||||
auto* a =
|
||||
Global("a", ty.array(ty.f32(), Expr(10u)), ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(a), nullptr);
|
||||
auto* ref = TypeOf(a)->As<sem::Reference>();
|
||||
ASSERT_NE(ref, nullptr);
|
||||
auto* ary = ref->StoreType()->As<sem::Array>();
|
||||
EXPECT_EQ(ary->Count(), 10u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTest, ArraySize_SignedLiteral) {
|
||||
// var<private> a : array<f32, 10>;
|
||||
auto* a =
|
||||
Global("a", ty.array(ty.f32(), Expr(10)), ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(a), nullptr);
|
||||
auto* ref = TypeOf(a)->As<sem::Reference>();
|
||||
ASSERT_NE(ref, nullptr);
|
||||
auto* ary = ref->StoreType()->As<sem::Array>();
|
||||
EXPECT_EQ(ary->Count(), 10u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTest, ArraySize_UnsignedConstant) {
|
||||
// let size = 0u;
|
||||
// var<private> a : array<f32, 10u>;
|
||||
GlobalConst("size", nullptr, Expr(10u));
|
||||
auto* a = Global("a", ty.array(ty.f32(), Expr("size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(a), nullptr);
|
||||
auto* ref = TypeOf(a)->As<sem::Reference>();
|
||||
ASSERT_NE(ref, nullptr);
|
||||
auto* ary = ref->StoreType()->As<sem::Array>();
|
||||
EXPECT_EQ(ary->Count(), 10u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTest, ArraySize_SignedConstant) {
|
||||
// let size = 0;
|
||||
// var<private> a : array<f32, 10>;
|
||||
GlobalConst("size", nullptr, Expr(10));
|
||||
auto* a = Global("a", ty.array(ty.f32(), Expr("size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(a), nullptr);
|
||||
auto* ref = TypeOf(a)->As<sem::Reference>();
|
||||
ASSERT_NE(ref, nullptr);
|
||||
auto* ary = ref->StoreType()->As<sem::Array>();
|
||||
EXPECT_EQ(ary->Count(), 10u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTest, Expr_ArrayAccessor_Array) {
|
||||
auto* idx = Expr(2);
|
||||
Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
|
||||
|
||||
@@ -584,8 +584,9 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_Runtime) {
|
||||
// array<f32>(1);
|
||||
auto* tc = array<i32>(
|
||||
// array<i32>(1);
|
||||
auto* tc = array(
|
||||
ty.i32(), nullptr,
|
||||
create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)));
|
||||
WrapInFunction(tc);
|
||||
|
||||
@@ -595,8 +596,8 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_Runtime) {
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
Expr_Constructor_Array_RuntimeZeroValue) {
|
||||
// array<f32>();
|
||||
auto* tc = array<i32>();
|
||||
// array<i32>();
|
||||
auto* tc = array(ty.i32(), nullptr);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
|
||||
@@ -201,6 +201,180 @@ TEST_F(ResolverTypeValidationTest,
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
|
||||
// var<private> a : array<f32, 4u>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4u)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
|
||||
// var<private> a : array<f32, 4>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Pass) {
|
||||
// let size = 4u;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(4u));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Pass) {
|
||||
// let size = 4;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(4));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
|
||||
// var<private> a : array<f32, 0u>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0u)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
|
||||
// var<private> a : array<f32, 0>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
|
||||
// var<private> a : array<f32, -10>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Zero) {
|
||||
// let size = 0u;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(0u));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Zero) {
|
||||
// let size = 0;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(0));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Negative) {
|
||||
// let size = -10;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(-10));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
|
||||
// var<private> a : array<f32, 10.0>;
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10.f)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
|
||||
// var<private> a : array<f32, vec2<i32>(10, 10)>;
|
||||
Global(
|
||||
"a",
|
||||
ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10, 10)),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_FloatConstant) {
|
||||
// let size = 10.0;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(10.f));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_IVecConstant) {
|
||||
// let size = vec2<i32>(100, 100);
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Construct(ty.vec2<i32>(), 100, 100));
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_OverridableConstant) {
|
||||
// [[override]] let size = 10;
|
||||
// var<private> a : array<f32, size>;
|
||||
GlobalConst("size", nullptr, Expr(10), {Override()});
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
r()->error(),
|
||||
"12:34 error: array size expression must not be pipeline-overridable");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
|
||||
// var<private> size : i32 = 10;
|
||||
// var<private> a : array<f32, size>;
|
||||
Global("size", ty.i32(), Expr(10), ast::StorageClass::kPrivate);
|
||||
Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
|
||||
ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
r()->error(),
|
||||
"12:34 error: array size identifier must be a module-scope constant");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_FunctionConstant) {
|
||||
// {
|
||||
// let size = 10;
|
||||
// var a : array<f32, size>;
|
||||
// }
|
||||
auto* size = Const("size", nullptr, Expr(10));
|
||||
auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
|
||||
WrapInFunction(Block(Decl(size), Decl(a)));
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
r()->error(),
|
||||
"12:34 error: array size identifier must be a module-scope constant");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, ArraySize_InvalidExpr) {
|
||||
// var a : array<f32, i32(4)>;
|
||||
auto* size = Const("size", nullptr, Expr(10));
|
||||
auto* a =
|
||||
Var("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.i32(), 4)));
|
||||
WrapInFunction(Block(Decl(size), Decl(a)));
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: array size expression must be either a literal or a "
|
||||
"module-scope constant");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
|
||||
/// [[stage(vertex)]]
|
||||
// fn func() { var a : array<i32>; }
|
||||
|
||||
@@ -81,7 +81,7 @@ fn main() {
|
||||
auto* expect = R"(
|
||||
[[block]]
|
||||
struct tint_symbol {
|
||||
buffer_size : array<vec4<u32>, 1>;
|
||||
buffer_size : array<vec4<u32>, 1u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(30)]] var<uniform> tint_symbol_1 : tint_symbol;
|
||||
@@ -134,7 +134,7 @@ fn main() {
|
||||
auto* expect = R"(
|
||||
[[block]]
|
||||
struct tint_symbol {
|
||||
buffer_size : array<vec4<u32>, 1>;
|
||||
buffer_size : array<vec4<u32>, 1u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(30)]] var<uniform> tint_symbol_1 : tint_symbol;
|
||||
@@ -216,7 +216,7 @@ fn main() {
|
||||
auto* expect = R"(
|
||||
[[block]]
|
||||
struct tint_symbol {
|
||||
buffer_size : array<vec4<u32>, 2>;
|
||||
buffer_size : array<vec4<u32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(30)]] var<uniform> tint_symbol_1 : tint_symbol;
|
||||
|
||||
@@ -180,8 +180,8 @@ fn tint_symbol_20([[internal(disable_validation__ignore_constructible_function_p
|
||||
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
|
||||
}
|
||||
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32) -> array<vec3<f32>, 2> {
|
||||
var arr : array<vec3<f32>, 2>;
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
|
||||
var arr : array<vec3<f32>, 2u>;
|
||||
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
|
||||
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
|
||||
}
|
||||
@@ -378,8 +378,8 @@ fn tint_symbol_20([[internal(disable_validation__ignore_constructible_function_p
|
||||
return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
|
||||
}
|
||||
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : UB, offset : u32) -> array<vec3<f32>, 2> {
|
||||
var arr : array<vec3<f32>, 2>;
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : UB, offset : u32) -> array<vec3<f32>, 2u> {
|
||||
var arr : array<vec3<f32>, 2u>;
|
||||
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
|
||||
arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
|
||||
}
|
||||
@@ -594,7 +594,7 @@ fn tint_symbol_20([[internal(disable_validation__ignore_constructible_function_p
|
||||
tint_symbol_11(buffer, (offset + 48u), value[3u]);
|
||||
}
|
||||
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32, value : array<vec3<f32>, 2>) {
|
||||
fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
|
||||
var array = value;
|
||||
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
|
||||
tint_symbol_8(buffer, (offset + (i_1 * 16u)), array[i_1]);
|
||||
@@ -770,8 +770,8 @@ fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_p
|
||||
return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
|
||||
}
|
||||
|
||||
fn tint_symbol_22([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32) -> array<vec3<f32>, 2> {
|
||||
var arr : array<vec3<f32>, 2>;
|
||||
fn tint_symbol_22([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
|
||||
var arr : array<vec3<f32>, 2u>;
|
||||
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
|
||||
arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 16u)));
|
||||
}
|
||||
@@ -948,7 +948,7 @@ fn tint_symbol_21([[internal(disable_validation__ignore_constructible_function_p
|
||||
tint_symbol_12(buffer, (offset + 48u), value[3u]);
|
||||
}
|
||||
|
||||
fn tint_symbol_22([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32, value : array<vec3<f32>, 2>) {
|
||||
fn tint_symbol_22([[internal(disable_validation__ignore_constructible_function_parameter)]] buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
|
||||
var array = value;
|
||||
for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
|
||||
tint_symbol_9(buffer, (offset + (i_1 * 16u)), array[i_1]);
|
||||
|
||||
@@ -106,12 +106,12 @@ TEST_F(DecomposeStridedMatrixTest, ReadUniformMatrix) {
|
||||
struct S {
|
||||
[[size(16)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<uniform> s : S;
|
||||
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2>) -> mat2x2<f32> {
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2u>) -> mat2x2<f32> {
|
||||
return mat2x2<f32>(arr[0u], arr[1u]);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ TEST_F(DecomposeStridedMatrixTest, ReadUniformColumn) {
|
||||
struct S {
|
||||
[[size(16)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<uniform> s : S;
|
||||
@@ -300,12 +300,12 @@ TEST_F(DecomposeStridedMatrixTest, ReadStorageMatrix) {
|
||||
struct S {
|
||||
[[size(8)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<storage, read_write> s : S;
|
||||
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2>) -> mat2x2<f32> {
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2u>) -> mat2x2<f32> {
|
||||
return mat2x2<f32>(arr[0u], arr[1u]);
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ TEST_F(DecomposeStridedMatrixTest, ReadStorageColumn) {
|
||||
struct S {
|
||||
[[size(16)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<storage, read_write> s : S;
|
||||
@@ -431,13 +431,13 @@ TEST_F(DecomposeStridedMatrixTest, WriteStorageMatrix) {
|
||||
struct S {
|
||||
[[size(8)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<storage, read_write> s : S;
|
||||
|
||||
fn mat2x2_stride_32_to_arr(mat : mat2x2<f32>) -> [[stride(32)]] array<vec2<f32>, 2> {
|
||||
return [[stride(32)]] array<vec2<f32>, 2>(mat[0u], mat[1u]);
|
||||
fn mat2x2_stride_32_to_arr(mat : mat2x2<f32>) -> [[stride(32)]] array<vec2<f32>, 2u> {
|
||||
return [[stride(32)]] array<vec2<f32>, 2u>(mat[0u], mat[1u]);
|
||||
}
|
||||
|
||||
[[stage(compute), workgroup_size(1)]]
|
||||
@@ -498,7 +498,7 @@ TEST_F(DecomposeStridedMatrixTest, WriteStorageColumn) {
|
||||
struct S {
|
||||
[[size(8)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<storage, read_write> s : S;
|
||||
@@ -576,17 +576,17 @@ TEST_F(DecomposeStridedMatrixTest, ReadWriteViaPointerLets) {
|
||||
struct S {
|
||||
[[size(8)]]
|
||||
padding : u32;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2>;
|
||||
m : [[stride(32)]] array<vec2<f32>, 2u>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]] var<storage, read_write> s : S;
|
||||
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2>) -> mat2x2<f32> {
|
||||
fn arr_to_mat2x2_stride_32(arr : [[stride(32)]] array<vec2<f32>, 2u>) -> mat2x2<f32> {
|
||||
return mat2x2<f32>(arr[0u], arr[1u]);
|
||||
}
|
||||
|
||||
fn mat2x2_stride_32_to_arr(mat : mat2x2<f32>) -> [[stride(32)]] array<vec2<f32>, 2> {
|
||||
return [[stride(32)]] array<vec2<f32>, 2>(mat[0u], mat[1u]);
|
||||
fn mat2x2_stride_32_to_arr(mat : mat2x2<f32>) -> [[stride(32)]] array<vec2<f32>, 2u> {
|
||||
return [[stride(32)]] array<vec2<f32>, 2u>(mat[0u], mat[1u]);
|
||||
}
|
||||
|
||||
[[stage(compute), workgroup_size(1)]]
|
||||
|
||||
@@ -80,7 +80,11 @@ ArrayBuilder PadArray(
|
||||
|
||||
auto* dst = ctx.dst;
|
||||
return [=] {
|
||||
return dst->ty.array(dst->create<ast::TypeName>(name), array->Count());
|
||||
if (array->IsRuntimeSized()) {
|
||||
return dst->ty.array(dst->create<ast::TypeName>(name));
|
||||
} else {
|
||||
return dst->ty.array(dst->create<ast::TypeName>(name), array->Count());
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,7 +54,31 @@ struct tint_padded_array_element {
|
||||
el : i32;
|
||||
};
|
||||
|
||||
var<private> arr : array<tint_padded_array_element, 4>;
|
||||
var<private> arr : array<tint_padded_array_element, 4u>;
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(PadArrayElementsTest, RuntimeArray) {
|
||||
auto* src = R"(
|
||||
[[block]]
|
||||
struct S {
|
||||
rta : [[stride(8)]] array<i32>;
|
||||
};
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_padded_array_element {
|
||||
[[size(8)]]
|
||||
el : i32;
|
||||
};
|
||||
|
||||
[[block]]
|
||||
struct S {
|
||||
rta : array<tint_padded_array_element>;
|
||||
};
|
||||
)";
|
||||
|
||||
auto got = Run<PadArrayElements>(src);
|
||||
@@ -78,9 +102,9 @@ struct tint_padded_array_element {
|
||||
};
|
||||
|
||||
fn f() {
|
||||
var arr : array<tint_padded_array_element, 4>;
|
||||
arr = array<tint_padded_array_element, 4>();
|
||||
arr = array<tint_padded_array_element, 4>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
var arr : array<tint_padded_array_element, 4u>;
|
||||
arr = array<tint_padded_array_element, 4u>();
|
||||
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let x = arr[3].el;
|
||||
}
|
||||
)";
|
||||
@@ -102,7 +126,7 @@ struct tint_padded_array_element {
|
||||
el : i32;
|
||||
};
|
||||
|
||||
fn f(a : array<tint_padded_array_element, 4>) -> i32 {
|
||||
fn f(a : array<tint_padded_array_element, 4u>) -> i32 {
|
||||
return a[2].el;
|
||||
}
|
||||
)";
|
||||
@@ -155,13 +179,13 @@ struct tint_padded_array_element {
|
||||
el : i32;
|
||||
};
|
||||
|
||||
type Array = array<tint_padded_array_element, 4>;
|
||||
type Array = array<tint_padded_array_element, 4u>;
|
||||
|
||||
fn f() {
|
||||
var arr : array<tint_padded_array_element, 4>;
|
||||
arr = array<tint_padded_array_element, 4>();
|
||||
arr = array<tint_padded_array_element, 4>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let vals : array<tint_padded_array_element, 4> = array<tint_padded_array_element, 4>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
var arr : array<tint_padded_array_element, 4u>;
|
||||
arr = array<tint_padded_array_element, 4u>();
|
||||
arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
|
||||
arr = vals;
|
||||
let x = arr[3].el;
|
||||
}
|
||||
@@ -198,10 +222,10 @@ struct tint_padded_array_element_2 {
|
||||
};
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4>;
|
||||
b : array<tint_padded_array_element_1, 8>;
|
||||
c : array<tint_padded_array_element, 4>;
|
||||
d : array<tint_padded_array_element_2, 8>;
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 8u>;
|
||||
c : array<tint_padded_array_element, 4u>;
|
||||
d : array<tint_padded_array_element_2, 8u>;
|
||||
};
|
||||
)";
|
||||
|
||||
@@ -231,7 +255,7 @@ struct tint_padded_array_element_2 {
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
[[size(512)]]
|
||||
el : array<tint_padded_array_element_2, 4>;
|
||||
el : array<tint_padded_array_element_2, 4u>;
|
||||
};
|
||||
|
||||
struct tint_padded_array_element_5 {
|
||||
@@ -241,18 +265,18 @@ struct tint_padded_array_element_5 {
|
||||
|
||||
struct tint_padded_array_element_4 {
|
||||
[[size(64)]]
|
||||
el : array<tint_padded_array_element_5, 4>;
|
||||
el : array<tint_padded_array_element_5, 4u>;
|
||||
};
|
||||
|
||||
struct tint_padded_array_element_3 {
|
||||
[[size(512)]]
|
||||
el : array<tint_padded_array_element_4, 4>;
|
||||
el : array<tint_padded_array_element_4, 4u>;
|
||||
};
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4>;
|
||||
b : array<tint_padded_array_element_1, 4>;
|
||||
c : array<tint_padded_array_element_3, 4>;
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 4u>;
|
||||
c : array<tint_padded_array_element_3, 4u>;
|
||||
};
|
||||
)";
|
||||
|
||||
@@ -286,7 +310,7 @@ struct tint_padded_array_element_2 {
|
||||
|
||||
struct tint_padded_array_element_1 {
|
||||
[[size(512)]]
|
||||
el : array<tint_padded_array_element_2, 4>;
|
||||
el : array<tint_padded_array_element_2, 4u>;
|
||||
};
|
||||
|
||||
struct tint_padded_array_element_5 {
|
||||
@@ -296,18 +320,18 @@ struct tint_padded_array_element_5 {
|
||||
|
||||
struct tint_padded_array_element_4 {
|
||||
[[size(64)]]
|
||||
el : array<tint_padded_array_element_5, 4>;
|
||||
el : array<tint_padded_array_element_5, 4u>;
|
||||
};
|
||||
|
||||
struct tint_padded_array_element_3 {
|
||||
[[size(512)]]
|
||||
el : array<tint_padded_array_element_4, 4>;
|
||||
el : array<tint_padded_array_element_4, 4u>;
|
||||
};
|
||||
|
||||
struct S {
|
||||
a : array<tint_padded_array_element, 4>;
|
||||
b : array<tint_padded_array_element_1, 4>;
|
||||
c : array<tint_padded_array_element_3, 4>;
|
||||
a : array<tint_padded_array_element, 4u>;
|
||||
b : array<tint_padded_array_element_1, 4u>;
|
||||
c : array<tint_padded_array_element_3, 4u>;
|
||||
};
|
||||
|
||||
fn f(s : S) -> i32 {
|
||||
@@ -345,7 +369,7 @@ struct tint_padded_array_element {
|
||||
el : i32;
|
||||
};
|
||||
|
||||
type T1 = array<tint_padded_array_element, 1>;
|
||||
type T1 = array<tint_padded_array_element, 1u>;
|
||||
|
||||
type T2 = i32;
|
||||
|
||||
@@ -354,7 +378,7 @@ struct tint_padded_array_element_1 {
|
||||
el : i32;
|
||||
};
|
||||
|
||||
fn f1(a : array<tint_padded_array_element_1, 2>) {
|
||||
fn f1(a : array<tint_padded_array_element_1, 2u>) {
|
||||
}
|
||||
|
||||
type T3 = i32;
|
||||
@@ -365,7 +389,7 @@ struct tint_padded_array_element_2 {
|
||||
};
|
||||
|
||||
fn f2() {
|
||||
var v : array<tint_padded_array_element_2, 3>;
|
||||
var v : array<tint_padded_array_element_2, 3u>;
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ fn main([[builtin(sample_index)]] sample_index : u32,
|
||||
auto* expect = R"(
|
||||
[[builtin(sample_index), internal(disable_validation__ignore_storage_class)]] var<in> sample_index_1 : u32;
|
||||
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1u>;
|
||||
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value : array<u32, 1u>;
|
||||
|
||||
fn main_inner(sample_index : u32, mask_in : u32) -> u32 {
|
||||
return mask_in;
|
||||
@@ -73,9 +73,9 @@ fn main([[builtin(sample_mask)]] mask_in : u32
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1u>;
|
||||
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value : array<u32, 1u>;
|
||||
|
||||
fn filter(mask : u32) -> u32 {
|
||||
return (mask & 3u);
|
||||
@@ -138,9 +138,9 @@ fn frag_main([[builtin(sample_index)]] sample_index : u32,
|
||||
|
||||
[[builtin(sample_index), internal(disable_validation__ignore_storage_class)]] var<in> sample_index_1 : u32;
|
||||
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> mask_in_1 : array<u32, 1u>;
|
||||
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value_1 : array<u32, 1>;
|
||||
[[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> value_1 : array<u32, 1u>;
|
||||
|
||||
fn vert_main_inner() -> vec4<f32> {
|
||||
return vec4<f32>();
|
||||
|
||||
@@ -120,7 +120,11 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const sem::Type* ty) {
|
||||
if (!a->IsStrideImplicit()) {
|
||||
decos.emplace_back(ctx.dst->create<ast::StrideDecoration>(a->Stride()));
|
||||
}
|
||||
return ctx.dst->create<ast::Array>(el, a->Count(), std::move(decos));
|
||||
if (a->IsRuntimeSized()) {
|
||||
return ctx.dst->ty.array(el, nullptr, std::move(decos));
|
||||
} else {
|
||||
return ctx.dst->ty.array(el, a->Count(), std::move(decos));
|
||||
}
|
||||
}
|
||||
if (auto* s = ty->As<sem::Struct>()) {
|
||||
return ctx.dst->create<ast::TypeName>(ctx.Clone(s->Declaration()->name()));
|
||||
|
||||
@@ -82,8 +82,14 @@ TEST_F(CreateASTTypeForTest, ArrayImplicitStride) {
|
||||
});
|
||||
ASSERT_TRUE(arr->Is<ast::Array>());
|
||||
ASSERT_TRUE(arr->As<ast::Array>()->type()->Is<ast::F32>());
|
||||
ASSERT_EQ(arr->As<ast::Array>()->size(), 2u);
|
||||
ASSERT_EQ(arr->As<ast::Array>()->decorations().size(), 0u);
|
||||
|
||||
auto* size_expr =
|
||||
arr->As<ast::Array>()->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::IntLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 2);
|
||||
}
|
||||
|
||||
TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
|
||||
@@ -92,7 +98,6 @@ TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
|
||||
});
|
||||
ASSERT_TRUE(arr->Is<ast::Array>());
|
||||
ASSERT_TRUE(arr->As<ast::Array>()->type()->Is<ast::F32>());
|
||||
ASSERT_EQ(arr->As<ast::Array>()->size(), 2u);
|
||||
ASSERT_EQ(arr->As<ast::Array>()->decorations().size(), 1u);
|
||||
ASSERT_TRUE(
|
||||
arr->As<ast::Array>()->decorations()[0]->Is<ast::StrideDecoration>());
|
||||
@@ -101,6 +106,13 @@ TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
|
||||
->As<ast::StrideDecoration>()
|
||||
->stride(),
|
||||
64u);
|
||||
|
||||
auto* size_expr =
|
||||
arr->As<ast::Array>()->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::IntLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 2);
|
||||
}
|
||||
|
||||
TEST_F(CreateASTTypeForTest, Struct) {
|
||||
|
||||
@@ -259,7 +259,7 @@ struct State {
|
||||
ctx.dst->Symbols().New(kStructName),
|
||||
{
|
||||
ctx.dst->Member(GetStructBufferName(),
|
||||
ctx.dst->ty.array<ProgramBuilder::u32, 0>(4)),
|
||||
ctx.dst->ty.array<ProgramBuilder::u32>(4)),
|
||||
},
|
||||
{
|
||||
ctx.dst->create<ast::StructBlockDecoration>(),
|
||||
|
||||
@@ -132,8 +132,7 @@ WrapArraysInStructs::WrappedArrayInfo WrapArraysInStructs::WrapArray(
|
||||
decos.emplace_back(
|
||||
c.dst->create<ast::StrideDecoration>(array->Stride()));
|
||||
}
|
||||
return c.dst->create<ast::Array>(el_type(c), array->Count(),
|
||||
std::move(decos));
|
||||
return c.dst->ty.array(el_type(c), array->Count(), std::move(decos));
|
||||
};
|
||||
|
||||
// Structure() will create and append the ast::Struct to the
|
||||
|
||||
@@ -40,7 +40,7 @@ var<private> arr : array<i32, 4>;
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
var<private> arr : tint_array_wrapper;
|
||||
@@ -60,7 +60,7 @@ fn f() {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
fn f() {
|
||||
@@ -82,7 +82,7 @@ fn f(a : array<i32, 4>) -> i32 {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
fn f(a : tint_array_wrapper) -> i32 {
|
||||
@@ -103,11 +103,11 @@ fn f() -> array<i32, 4> {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
fn f() -> tint_array_wrapper {
|
||||
return tint_array_wrapper(array<i32, 4>(1, 2, 3, 4));
|
||||
return tint_array_wrapper(array<i32, 4u>(1, 2, 3, 4));
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -132,22 +132,22 @@ fn f() {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 2>;
|
||||
arr : array<i32, 2u>;
|
||||
};
|
||||
|
||||
type Inner = tint_array_wrapper;
|
||||
|
||||
struct tint_array_wrapper_1 {
|
||||
arr : array<tint_array_wrapper, 2>;
|
||||
arr : array<tint_array_wrapper, 2u>;
|
||||
};
|
||||
|
||||
type Array = tint_array_wrapper_1;
|
||||
|
||||
fn f() {
|
||||
var arr : tint_array_wrapper_1;
|
||||
arr = tint_array_wrapper_1(array<tint_array_wrapper, 2>());
|
||||
arr = tint_array_wrapper_1(array<tint_array_wrapper, 2>(tint_array_wrapper(array<i32, 2>(1, 2)), tint_array_wrapper(array<i32, 2>(3, 4))));
|
||||
let vals : tint_array_wrapper_1 = tint_array_wrapper_1(array<tint_array_wrapper, 2>(tint_array_wrapper(array<i32, 2>(1, 2)), tint_array_wrapper(array<i32, 2>(3, 4))));
|
||||
arr = tint_array_wrapper_1(array<tint_array_wrapper, 2u>());
|
||||
arr = tint_array_wrapper_1(array<tint_array_wrapper, 2u>(tint_array_wrapper(array<i32, 2u>(1, 2)), tint_array_wrapper(array<i32, 2u>(3, 4))));
|
||||
let vals : tint_array_wrapper_1 = tint_array_wrapper_1(array<tint_array_wrapper, 2u>(tint_array_wrapper(array<i32, 2u>(1, 2)), tint_array_wrapper(array<i32, 2u>(3, 4))));
|
||||
arr = vals;
|
||||
let x = arr.arr[3];
|
||||
}
|
||||
@@ -168,11 +168,11 @@ struct S {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
struct tint_array_wrapper_1 {
|
||||
arr : array<i32, 8>;
|
||||
arr : array<i32, 8u>;
|
||||
};
|
||||
|
||||
struct S {
|
||||
@@ -197,15 +197,15 @@ struct S {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
struct tint_array_wrapper_1 {
|
||||
arr : array<tint_array_wrapper, 4>;
|
||||
arr : array<tint_array_wrapper, 4u>;
|
||||
};
|
||||
|
||||
struct tint_array_wrapper_2 {
|
||||
arr : array<tint_array_wrapper_1, 4>;
|
||||
arr : array<tint_array_wrapper_1, 4u>;
|
||||
};
|
||||
|
||||
struct S {
|
||||
@@ -234,15 +234,15 @@ fn f(s : S) -> i32 {
|
||||
)";
|
||||
auto* expect = R"(
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 4>;
|
||||
arr : array<i32, 4u>;
|
||||
};
|
||||
|
||||
struct tint_array_wrapper_1 {
|
||||
arr : array<tint_array_wrapper, 4>;
|
||||
arr : array<tint_array_wrapper, 4u>;
|
||||
};
|
||||
|
||||
struct tint_array_wrapper_2 {
|
||||
arr : array<tint_array_wrapper_1, 4>;
|
||||
arr : array<tint_array_wrapper_1, 4u>;
|
||||
};
|
||||
|
||||
struct S {
|
||||
@@ -282,7 +282,7 @@ fn f2() {
|
||||
type T0 = i32;
|
||||
|
||||
struct tint_array_wrapper {
|
||||
arr : array<i32, 1>;
|
||||
arr : array<i32, 1u>;
|
||||
};
|
||||
|
||||
type T1 = tint_array_wrapper;
|
||||
@@ -290,7 +290,7 @@ type T1 = tint_array_wrapper;
|
||||
type T2 = i32;
|
||||
|
||||
struct tint_array_wrapper_1 {
|
||||
arr : array<i32, 2>;
|
||||
arr : array<i32, 2u>;
|
||||
};
|
||||
|
||||
fn f1(a : tint_array_wrapper_1) {
|
||||
@@ -299,7 +299,7 @@ fn f1(a : tint_array_wrapper_1) {
|
||||
type T3 = i32;
|
||||
|
||||
struct tint_array_wrapper_2 {
|
||||
arr : array<i32, 3>;
|
||||
arr : array<i32, 3u>;
|
||||
};
|
||||
|
||||
fn f2() {
|
||||
|
||||
@@ -61,7 +61,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
|
||||
// TODO(dsinclair): Is this possible? What order should it output in?
|
||||
TEST_F(HlslGeneratorImplTest_Type,
|
||||
DISABLED_EmitType_ArrayOfArrayOfRuntimeArray) {
|
||||
auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5), 0);
|
||||
auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5));
|
||||
Global("G", arr, ast::StorageClass::kPrivate);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace {
|
||||
using BuilderTest_Type = TestHelper;
|
||||
|
||||
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
||||
auto* ary = ty.array(ty.i32(), 0);
|
||||
auto* ary = ty.array(ty.i32());
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||
@@ -48,7 +48,7 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
||||
}
|
||||
|
||||
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
|
||||
auto* ary = ty.array(ty.i32(), 0);
|
||||
auto* ary = ty.array(ty.i32());
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||
@@ -413,7 +413,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
|
||||
// in levels of arrays.
|
||||
auto* arr_mat2x2 = ty.array(ty.mat2x2<f32>(), 1); // Singly nested array
|
||||
auto* arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1); // Doubly nested array
|
||||
auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>(), 0); // Runtime array
|
||||
auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>()); // Runtime array
|
||||
|
||||
auto* s =
|
||||
Structure("S",
|
||||
|
||||
@@ -399,8 +399,12 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ary->IsRuntimeArray())
|
||||
out << ", " << ary->size();
|
||||
if (!ary->IsRuntimeArray()) {
|
||||
out << ", ";
|
||||
if (!EmitExpression(out, ary->Size())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
out << ">";
|
||||
} else if (ty->Is<ast::Bool>()) {
|
||||
|
||||
@@ -60,7 +60,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Array_Decoration) {
|
||||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_RuntimeArray) {
|
||||
auto* a = ty.array(ty.bool_(), 0);
|
||||
auto* a = ty.array(ty.bool_());
|
||||
Alias("make_type_reachable", a);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
Reference in New Issue
Block a user