diff --git a/src/tint/ast/struct_member_align_attribute.cc b/src/tint/ast/struct_member_align_attribute.cc index d8ed4fcf3c..e188e7bdc9 100644 --- a/src/tint/ast/struct_member_align_attribute.cc +++ b/src/tint/ast/struct_member_align_attribute.cc @@ -26,7 +26,7 @@ namespace tint::ast { StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid, NodeID nid, const Source& src, - uint32_t a) + const ast::Expression* a) : Base(pid, nid, src), align(a) {} StructMemberAlignAttribute::~StructMemberAlignAttribute() = default; @@ -38,7 +38,8 @@ std::string StructMemberAlignAttribute::Name() const { const StructMemberAlignAttribute* StructMemberAlignAttribute::Clone(CloneContext* ctx) const { // Clone arguments outside of create() call to have deterministic ordering auto src = ctx->Clone(source); - return ctx->dst->create(src, align); + auto* align_ = ctx->Clone(align); + return ctx->dst->create(src, align_); } } // namespace tint::ast diff --git a/src/tint/ast/struct_member_align_attribute.h b/src/tint/ast/struct_member_align_attribute.h index efff21b203..2043b01cba 100644 --- a/src/tint/ast/struct_member_align_attribute.h +++ b/src/tint/ast/struct_member_align_attribute.h @@ -19,6 +19,7 @@ #include #include "src/tint/ast/attribute.h" +#include "src/tint/ast/expression.h" namespace tint::ast { @@ -29,8 +30,11 @@ class StructMemberAlignAttribute final : public Castable(2u); - EXPECT_EQ(2u, d->align); + auto* val = Expr("ident"); + auto* d = create(val); + EXPECT_EQ(val, d->align); + EXPECT_TRUE(d->align->Is()); } } // namespace diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc index 1d044650bf..5f0013f70e 100644 --- a/src/tint/inspector/inspector_test.cc +++ b/src/tint/inspector/inspector_test.cc @@ -1811,7 +1811,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) { "foo_type", utils::Vector{ Member("0i32", ty.i32()), - Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), utils::Vector{MemberAlign(16)}), + Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), utils::Vector{MemberAlign(16_u)}), }); AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0); @@ -3238,11 +3238,9 @@ TEST_F(InspectorGetWorkgroupStorageSizeTest, StructAlignment) { // of its last member, rounded up to the alignment of its largest member. So // here the struct is expected to occupy 1024 bytes of workgroup storage. const auto* wg_struct_type = MakeStructTypeFromMembers( - "WgStruct", - utils::Vector{ - MakeStructMember(0, ty.f32(), - utils::Vector{create(1024u)}), - }); + "WgStruct", utils::Vector{ + MakeStructMember(0, ty.f32(), utils::Vector{MemberAlign(1024_u)}), + }); AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type)); MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index 42e428ae37..5da80d68ab 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -2274,17 +2274,19 @@ class ProgramBuilder { /// Creates a ast::StructMemberAlignAttribute /// @param source the source information - /// @param val the align value + /// @param val the align value expression /// @returns the align attribute pointer - const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, uint32_t val) { - return create(source, val); + template + const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, EXPR&& val) { + return create(source, Expr(std::forward(val))); } /// Creates a ast::StructMemberAlignAttribute - /// @param val the align value + /// @param val the align value expression /// @returns the align attribute pointer - const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) { - return create(source_, val); + template + const ast::StructMemberAlignAttribute* MemberAlign(EXPR&& val) { + return create(source_, Expr(std::forward(val))); } /// Creates the ast::GroupAttribute diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index 93353565cf..c49580cf06 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -3874,7 +3874,9 @@ Maybe ParserImpl::attribute() { } match(Token::Type::kComma); - return create(t.source(), val.value); + return create( + t.source(), create( + val.value, ast::IntLiteralExpression::Suffix::kNone)); }); } diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc index df75f96984..4fb95280d1 100644 --- a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc +++ b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc @@ -102,7 +102,10 @@ TEST_F(ParserImplTest, Attribute_Align) { ASSERT_TRUE(member_attr->Is()); auto* o = member_attr->As(); - EXPECT_EQ(o->align, 4u); + ASSERT_TRUE(o->align->Is()); + EXPECT_EQ(o->align->As()->value, 4); + EXPECT_EQ(o->align->As()->suffix, + ast::IntLiteralExpression::Suffix::kNone); } TEST_F(ParserImplTest, Attribute_Align_TrailingComma) { @@ -118,7 +121,11 @@ TEST_F(ParserImplTest, Attribute_Align_TrailingComma) { ASSERT_TRUE(member_attr->Is()); auto* o = member_attr->As(); - EXPECT_EQ(o->align, 4u); + ASSERT_TRUE(o->align->Is()); + + auto* expr = o->align->As(); + EXPECT_EQ(expr->value, 4); + EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone); } TEST_F(ParserImplTest, Attribute_Align_MissingLeftParen) { diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc index d2ab9160a4..c64f7728dd 100644 --- a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc +++ b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc @@ -49,7 +49,13 @@ TEST_F(ParserImplTest, StructMember_ParsesWithAlignAttribute) { EXPECT_TRUE(m->type->Is()); EXPECT_EQ(m->attributes.Length(), 1u); EXPECT_TRUE(m->attributes[0]->Is()); - EXPECT_EQ(m->attributes[0]->As()->align, 2u); + + auto* attr = m->attributes[0]->As(); + ASSERT_TRUE(attr->align->Is()); + + auto* expr = attr->align->As(); + EXPECT_EQ(expr->value, 2); + EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone); EXPECT_EQ(m->source.range, (Source::Range{{1u, 11u}, {1u, 12u}})); EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 15u}, {1u, 18u}})); @@ -89,10 +95,16 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleattributes) { EXPECT_EQ(m->symbol, builder.Symbols().Get("a")); EXPECT_TRUE(m->type->Is()); EXPECT_EQ(m->attributes.Length(), 2u); - EXPECT_TRUE(m->attributes[0]->Is()); + ASSERT_TRUE(m->attributes[0]->Is()); EXPECT_EQ(m->attributes[0]->As()->size, 2u); - EXPECT_TRUE(m->attributes[1]->Is()); - EXPECT_EQ(m->attributes[1]->As()->align, 4u); + + ASSERT_TRUE(m->attributes[1]->Is()); + auto* attr = m->attributes[1]->As(); + + ASSERT_TRUE(attr->align->Is()); + auto* expr = attr->align->As(); + EXPECT_EQ(expr->value, 4); + EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone); EXPECT_EQ(m->source.range, (Source::Range{{2u, 11u}, {2u, 12u}})); EXPECT_EQ(m->type->source.range, (Source::Range{{2u, 15u}, {2u, 18u}})); diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc index 4f6545cb13..70d46123a7 100644 --- a/src/tint/resolver/attribute_validation_test.cc +++ b/src/tint/resolver/attribute_validation_test.cc @@ -89,7 +89,7 @@ static utils::Vector createAttributes(const Source& so AttributeKind kind) { switch (kind) { case AttributeKind::kAlign: - return {builder.create(source, 4u)}; + return {builder.MemberAlign(source, 4_u)}; case AttributeKind::kBinding: return {builder.create(source, 1u)}; case AttributeKind::kBuiltin: @@ -625,14 +625,13 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest, TestParams{AttributeKind::kWorkgroup, false}, TestParams{AttributeKind::kBindingAndGroup, false})); TEST_F(StructMemberAttributeTest, DuplicateAttribute) { - Structure("mystruct", - utils::Vector{ - Member("a", ty.i32(), - utils::Vector{ - create(Source{{12, 34}}, 4u), - create(Source{{56, 78}}, 8u), - }), - }); + Structure("mystruct", utils::Vector{ + Member("a", ty.i32(), + utils::Vector{ + MemberAlign(Source{{12, 34}}, 4_u), + MemberAlign(Source{{56, 78}}, 8_u), + }), + }); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), R"(56:78 error: duplicate align attribute diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index cd8bdc8175..b32ca832c6 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -2673,11 +2673,26 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) { align = 1; has_offset_attr = true; } else if (auto* a = attr->As()) { - if (a->align <= 0 || !utils::IsPowerOfTwo(a->align)) { + const auto* expr = Expression(a->align); + if (!expr) { + return nullptr; + } + auto* materialized = Materialize(expr); + if (!materialized) { + return nullptr; + } + auto const_value = materialized->ConstantValue(); + if (!const_value) { + AddError("'align' must be constant expression", a->align->source); + return nullptr; + } + auto value = const_value->As(); + + if (value <= 0 || !utils::IsPowerOfTwo(value)) { AddError("align value must be a positive, power-of-two integer", a->source); return nullptr; } - align = a->align; + align = const_value->As(); has_align_attr = true; } else if (auto* s = attr->As()) { if (s->size < size) { diff --git a/src/tint/resolver/storage_class_layout_validation_test.cc b/src/tint/resolver/storage_class_layout_validation_test.cc index 9c16ec4153..51b8eccbc1 100644 --- a/src/tint/resolver/storage_class_layout_validation_test.cc +++ b/src/tint/resolver/storage_class_layout_validation_test.cc @@ -36,7 +36,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember) Structure(Source{{12, 34}}, "S", utils::Vector{ Member("a", ty.f32(), utils::Vector{MemberSize(5)}), - Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1)}), + Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_u)}), }); GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0), @@ -66,7 +66,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember_S Structure(Source{{12, 34}}, "S", utils::Vector{ Member("a", ty.f32(), utils::Vector{MemberSize(5)}), - Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4)}), + Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_u)}), }); GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0), @@ -142,7 +142,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, utils::Vector{ Member("scalar", ty.f32()), Member(Source{{56, 78}}, "inner", ty.type_name("Inner"), - utils::Vector{MemberAlign(16)}), + utils::Vector{MemberAlign(16_u)}), }); GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0), @@ -201,7 +201,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_A utils::Vector{ Member("scalar", ty.f32()), Member(Source{{34, 56}}, "inner", ty.type_name("Inner"), - utils::Vector{MemberAlign(16)}), + utils::Vector{MemberAlign(16_u)}), }); GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0), @@ -227,7 +227,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotM Structure(Source{{12, 34}}, "Inner", utils::Vector{ - Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}), + Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_u), MemberSize(5)}), }); Structure(Source{{34, 56}}, "Outer", @@ -279,7 +279,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, Member("a", ty.i32()), Member("b", ty.i32()), Member("c", ty.i32()), - Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}), + Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_u), MemberSize(5)}), }); Structure(Source{{34, 56}}, "Outer", @@ -327,13 +327,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest, Structure(Source{{12, 34}}, "Inner", utils::Vector{ - Member("scalar", ty.i32(), utils::Vector{MemberAlign(1), MemberSize(5)}), + Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_u), MemberSize(5)}), }); Structure(Source{{34, 56}}, "Outer", utils::Vector{ Member(Source{{56, 78}}, "inner", ty.type_name("Inner")), - Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16)}), + Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16_u)}), }); GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0), @@ -551,7 +551,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) { Structure( Source{{12, 34}}, "S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}), - Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1)})}); + Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_u)})}); GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kPushConstant); ASSERT_FALSE(r()->Resolve()); @@ -576,7 +576,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_Aligned) { // var a : S; Enable(ast::Extension::kChromiumExperimentalPushConstant); Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}), - Member("b", ty.f32(), utils::Vector{MemberAlign(4)})}); + Member("b", ty.f32(), utils::Vector{MemberAlign(4_u)})}); GlobalVar("a", ty.type_name("S"), ast::StorageClass::kPushConstant); ASSERT_TRUE(r()->Resolve()) << r()->error(); diff --git a/src/tint/resolver/struct_layout_test.cc b/src/tint/resolver/struct_layout_test.cc index 59faf8d292..ae3972b04f 100644 --- a/src/tint/resolver/struct_layout_test.cc +++ b/src/tint/resolver/struct_layout_test.cc @@ -498,15 +498,15 @@ TEST_F(ResolverStructLayoutTest, SizeAttributes) { TEST_F(ResolverStructLayoutTest, AlignAttributes) { auto* inner = Structure("Inner", utils::Vector{ - Member("a", ty.f32(), utils::Vector{MemberAlign(8)}), - Member("b", ty.f32(), utils::Vector{MemberAlign(16)}), - Member("c", ty.f32(), utils::Vector{MemberAlign(4)}), + Member("a", ty.f32(), utils::Vector{MemberAlign(8_u)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(16_u)}), + Member("c", ty.f32(), utils::Vector{MemberAlign(4_u)}), }); auto* s = Structure("S", utils::Vector{ - Member("a", ty.f32(), utils::Vector{MemberAlign(4)}), - Member("b", ty.u32(), utils::Vector{MemberAlign(8)}), + Member("a", ty.f32(), utils::Vector{MemberAlign(4_u)}), + Member("b", ty.u32(), utils::Vector{MemberAlign(8_u)}), Member("c", ty.Of(inner)), - Member("d", ty.i32(), utils::Vector{MemberAlign(32)}), + Member("d", ty.i32(), utils::Vector{MemberAlign(32_u)}), }); ASSERT_TRUE(r()->Resolve()) << r()->error(); @@ -536,7 +536,7 @@ TEST_F(ResolverStructLayoutTest, AlignAttributes) { TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) { auto* s = Structure("S", utils::Vector{ - Member("a", ty.i32(), utils::Vector{MemberAlign(1024)}), + Member("a", ty.i32(), utils::Vector{MemberAlign(1024_u)}), }); ASSERT_TRUE(r()->Resolve()) << r()->error(); diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc index 623ff1c726..cbd05c126a 100644 --- a/src/tint/resolver/validation_test.cc +++ b/src/tint/resolver/validation_test.cc @@ -1239,7 +1239,7 @@ TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) { TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) { Structure("S", utils::Vector{ - Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 3)}), + Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 3_u)}), }); EXPECT_FALSE(r()->Resolve()); @@ -1248,7 +1248,7 @@ TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) { TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) { Structure("S", utils::Vector{ - Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 0)}), + Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 0_u)}), }); EXPECT_FALSE(r()->Resolve()); @@ -1279,7 +1279,7 @@ TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) { TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) { Structure("S", utils::Vector{ Member(Source{{12, 34}}, "a", ty.f32(), - utils::Vector{MemberOffset(0), MemberAlign(4)}), + utils::Vector{MemberOffset(0), MemberAlign(4_u)}), }); EXPECT_FALSE(r()->Resolve()); @@ -1291,7 +1291,7 @@ TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) { TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) { Structure("S", utils::Vector{ Member(Source{{12, 34}}, "a", ty.f32(), - utils::Vector{MemberOffset(0), MemberAlign(4), MemberSize(4)}), + utils::Vector{MemberOffset(0), MemberAlign(4_u), MemberSize(4)}), }); EXPECT_FALSE(r()->Resolve()); diff --git a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc index 842bf35ef3..0264b0249b 100644 --- a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc +++ b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc @@ -13,9 +13,11 @@ // limitations under the License. #include "gmock/gmock.h" +#include "src/tint/number.h" #include "src/tint/writer/glsl/test_helper.h" using ::testing::HasSubstr; +using namespace tint::number_suffixes; // NOLINT namespace tint::writer::glsl { namespace { @@ -31,9 +33,9 @@ void TestAlign(ProgramBuilder* ctx) { // @group(0) @binding(0) var nephews : Nephews; auto* nephews = ctx->Structure( "Nephews", utils::Vector{ - ctx->Member("huey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}), - ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}), - ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}), + ctx->Member("huey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}), + ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}), + ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}), }); ctx->GlobalVar("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage, ctx->Binding(0), ctx->Group(0)); diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc index 72f9fa51e2..531a45d72e 100644 --- a/src/tint/writer/msl/generator_impl_type_test.cc +++ b/src/tint/writer/msl/generator_impl_type_test.cc @@ -252,35 +252,35 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) { } TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) { - auto* s = - Structure("S", utils::Vector{ - Member("a", ty.i32(), utils::Vector{MemberSize(32)}), - Member("b", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}), - Member("c", ty.vec2()), - Member("d", ty.u32()), - Member("e", ty.vec3()), - Member("f", ty.u32()), - Member("g", ty.vec4()), - Member("h", ty.u32()), - Member("i", ty.mat2x2()), - Member("j", ty.u32()), - Member("k", ty.mat2x3()), - Member("l", ty.u32()), - Member("m", ty.mat2x4()), - Member("n", ty.u32()), - Member("o", ty.mat3x2()), - Member("p", ty.u32()), - Member("q", ty.mat3x3()), - Member("r", ty.u32()), - Member("s", ty.mat3x4()), - Member("t", ty.u32()), - Member("u", ty.mat4x2()), - Member("v", ty.u32()), - Member("w", ty.mat4x3()), - Member("x", ty.u32()), - Member("y", ty.mat4x4()), - Member("z", ty.f32()), - }); + auto* s = Structure( + "S", utils::Vector{ + Member("a", ty.i32(), utils::Vector{MemberSize(32)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(128_u), MemberSize(128)}), + Member("c", ty.vec2()), + Member("d", ty.u32()), + Member("e", ty.vec3()), + Member("f", ty.u32()), + Member("g", ty.vec4()), + Member("h", ty.u32()), + Member("i", ty.mat2x2()), + Member("j", ty.u32()), + Member("k", ty.mat2x3()), + Member("l", ty.u32()), + Member("m", ty.mat2x4()), + Member("n", ty.u32()), + Member("o", ty.mat3x2()), + Member("p", ty.u32()), + Member("q", ty.mat3x3()), + Member("r", ty.u32()), + Member("s", ty.mat3x4()), + Member("t", ty.u32()), + Member("u", ty.mat4x2()), + Member("v", ty.u32()), + Member("w", ty.mat4x3()), + Member("x", ty.u32()), + Member("y", ty.mat4x4()), + Member("z", ty.f32()), + }); GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0), Group(0)); @@ -368,10 +368,11 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) { // inner_x: size(1024), align(512) - auto* inner_x = Structure("inner_x", utils::Vector{ - Member("a", ty.i32()), - Member("b", ty.f32(), utils::Vector{MemberAlign(512)}), - }); + auto* inner_x = + Structure("inner_x", utils::Vector{ + Member("a", ty.i32()), + Member("b", ty.f32(), utils::Vector{MemberAlign(512_u)}), + }); // inner_y: size(516), align(4) auto* inner_y = Structure("inner_y", utils::Vector{ @@ -456,7 +457,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) { // inner: size(1024), align(512) auto* inner = Structure("inner", utils::Vector{ Member("a", ty.i32()), - Member("b", ty.f32(), utils::Vector{MemberAlign(512)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(512_u)}), }); // array_x: size(28), align(4) @@ -588,36 +589,36 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) { } TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) { - auto* s = Structure( - "S", utils::Vector{ - // uses symbols tint_pad_[0..9] and tint_pad_[20..35] - Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32)}), - Member("tint_pad_20", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}), - Member("tint_pad_33", ty.vec2()), - Member("tint_pad_1", ty.u32()), - Member("tint_pad_3", ty.vec3()), - Member("tint_pad_7", ty.u32()), - Member("tint_pad_25", ty.vec4()), - Member("tint_pad_5", ty.u32()), - Member("tint_pad_27", ty.mat2x2()), - Member("tint_pad_24", ty.u32()), - Member("tint_pad_23", ty.mat2x3()), - Member("tint_pad", ty.u32()), - Member("tint_pad_8", ty.mat2x4()), - Member("tint_pad_26", ty.u32()), - Member("tint_pad_29", ty.mat3x2()), - Member("tint_pad_6", ty.u32()), - Member("tint_pad_22", ty.mat3x3()), - Member("tint_pad_32", ty.u32()), - Member("tint_pad_34", ty.mat3x4()), - Member("tint_pad_35", ty.u32()), - Member("tint_pad_30", ty.mat4x2()), - Member("tint_pad_9", ty.u32()), - Member("tint_pad_31", ty.mat4x3()), - Member("tint_pad_28", ty.u32()), - Member("tint_pad_4", ty.mat4x4()), - Member("tint_pad_21", ty.f32()), - }); + auto* s = Structure("S", utils::Vector{ + // uses symbols tint_pad_[0..9] and tint_pad_[20..35] + Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32)}), + Member("tint_pad_20", ty.f32(), + utils::Vector{MemberAlign(128_u), MemberSize(128_u)}), + Member("tint_pad_33", ty.vec2()), + Member("tint_pad_1", ty.u32()), + Member("tint_pad_3", ty.vec3()), + Member("tint_pad_7", ty.u32()), + Member("tint_pad_25", ty.vec4()), + Member("tint_pad_5", ty.u32()), + Member("tint_pad_27", ty.mat2x2()), + Member("tint_pad_24", ty.u32()), + Member("tint_pad_23", ty.mat2x3()), + Member("tint_pad", ty.u32()), + Member("tint_pad_8", ty.mat2x4()), + Member("tint_pad_26", ty.u32()), + Member("tint_pad_29", ty.mat3x2()), + Member("tint_pad_6", ty.u32()), + Member("tint_pad_22", ty.mat3x3()), + Member("tint_pad_32", ty.u32()), + Member("tint_pad_34", ty.mat3x4()), + Member("tint_pad_35", ty.u32()), + Member("tint_pad_30", ty.mat4x2()), + Member("tint_pad_9", ty.u32()), + Member("tint_pad_31", ty.mat4x3()), + Member("tint_pad_28", ty.u32()), + Member("tint_pad_4", ty.mat4x4()), + Member("tint_pad_21", ty.f32()), + }); GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0), Group(0)); diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc index c6f044e9bf..3b8e0b170d 100644 --- a/src/tint/writer/spirv/builder_type_test.cc +++ b/src/tint/writer/spirv/builder_type_test.cc @@ -336,7 +336,7 @@ OpMemberName %1 0 "a" TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) { auto* s = Structure("S", utils::Vector{ Member("a", ty.f32()), - Member("b", ty.f32(), utils::Vector{MemberAlign(8)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(8_u)}), }); spirv::Builder& b = Build(); diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc index efc96016a0..9f9c4c6809 100644 --- a/src/tint/writer/wgsl/generator_impl.cc +++ b/src/tint/writer/wgsl/generator_impl.cc @@ -776,7 +776,11 @@ bool GeneratorImpl::EmitAttributes(std::ostream& out, return true; }, [&](const ast::StructMemberAlignAttribute* align) { - out << "align(" << align->align << ")"; + out << "align("; + if (!EmitExpression(out, align->align)) { + return false; + } + out << ")"; return true; }, [&](const ast::StrideAttribute* stride) { diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc index 73fc1862bc..cdba585176 100644 --- a/src/tint/writer/wgsl/generator_impl_type_test.cc +++ b/src/tint/writer/wgsl/generator_impl_type_test.cc @@ -219,8 +219,8 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) { TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) { auto* s = Structure("S", utils::Vector{ - Member("a", ty.i32(), utils::Vector{MemberAlign(8)}), - Member("b", ty.f32(), utils::Vector{MemberAlign(16)}), + Member("a", ty.i32(), utils::Vector{MemberAlign(8_a)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(16_a)}), }); GeneratorImpl& gen = Build(); @@ -256,7 +256,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) { TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) { auto* s = Structure("S", utils::Vector{ Member("a", ty.i32()), - Member("b", ty.f32(), utils::Vector{MemberAlign(8)}), + Member("b", ty.f32(), utils::Vector{MemberAlign(8_a)}), }); GeneratorImpl& gen = Build();