Convert @align to hold an expression.

With the updated WGSL grammar the `@align` attribute takes an
expression instead of a value. This CL updates the internal data
structures to store an expression instead of an integer value.

The parser still only parses integers, they're just turned into
`IntLiteralExpressions` at the moment.

Bug: tint:1633
Change-Id: If34901798ed6ceaced354bc06ae9b6df875b700e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99980
Reviewed-by: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2022-08-23 13:28:44 +00:00 committed by Dawn LUCI CQ
parent b7cf9dd263
commit 4964d9bc20
18 changed files with 180 additions and 131 deletions

View File

@ -26,7 +26,7 @@ namespace tint::ast {
StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid, StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
uint32_t a) const ast::Expression* a)
: Base(pid, nid, src), align(a) {} : Base(pid, nid, src), align(a) {}
StructMemberAlignAttribute::~StructMemberAlignAttribute() = default; StructMemberAlignAttribute::~StructMemberAlignAttribute() = default;
@ -38,7 +38,8 @@ std::string StructMemberAlignAttribute::Name() const {
const StructMemberAlignAttribute* StructMemberAlignAttribute::Clone(CloneContext* ctx) const { const StructMemberAlignAttribute* StructMemberAlignAttribute::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering // Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source); auto src = ctx->Clone(source);
return ctx->dst->create<StructMemberAlignAttribute>(src, align); auto* align_ = ctx->Clone(align);
return ctx->dst->create<StructMemberAlignAttribute>(src, align_);
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -19,6 +19,7 @@
#include <string> #include <string>
#include "src/tint/ast/attribute.h" #include "src/tint/ast/attribute.h"
#include "src/tint/ast/expression.h"
namespace tint::ast { namespace tint::ast {
@ -29,8 +30,11 @@ class StructMemberAlignAttribute final : public Castable<StructMemberAlignAttrib
/// @param pid the identifier of the program that owns this node /// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier /// @param nid the unique node identifier
/// @param src the source of this node /// @param src the source of this node
/// @param align the align value /// @param align the align value expression
StructMemberAlignAttribute(ProgramID pid, NodeID nid, const Source& src, uint32_t align); StructMemberAlignAttribute(ProgramID pid,
NodeID nid,
const Source& src,
const ast::Expression* align);
~StructMemberAlignAttribute() override; ~StructMemberAlignAttribute() override;
/// @returns the WGSL name for the attribute /// @returns the WGSL name for the attribute
@ -42,8 +46,8 @@ class StructMemberAlignAttribute final : public Castable<StructMemberAlignAttrib
/// @return the newly cloned node /// @return the newly cloned node
const StructMemberAlignAttribute* Clone(CloneContext* ctx) const override; const StructMemberAlignAttribute* Clone(CloneContext* ctx) const override;
/// The align value /// The align value expression
const uint32_t align; const ast::Expression* const align;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -22,8 +22,10 @@ namespace {
using StructMemberAlignAttributeTest = TestHelper; using StructMemberAlignAttributeTest = TestHelper;
TEST_F(StructMemberAlignAttributeTest, Creation) { TEST_F(StructMemberAlignAttributeTest, Creation) {
auto* d = create<StructMemberAlignAttribute>(2u); auto* val = Expr("ident");
EXPECT_EQ(2u, d->align); auto* d = create<StructMemberAlignAttribute>(val);
EXPECT_EQ(val, d->align);
EXPECT_TRUE(d->align->Is<IdentifierExpression>());
} }
} // namespace } // namespace

View File

@ -1811,7 +1811,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
"foo_type", "foo_type",
utils::Vector{ utils::Vector{
Member("0i32", ty.i32()), 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); 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 // 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. // here the struct is expected to occupy 1024 bytes of workgroup storage.
const auto* wg_struct_type = MakeStructTypeFromMembers( const auto* wg_struct_type = MakeStructTypeFromMembers(
"WgStruct", "WgStruct", utils::Vector{
utils::Vector{ MakeStructMember(0, ty.f32(), utils::Vector{MemberAlign(1024_u)}),
MakeStructMember(0, ty.f32(), });
utils::Vector{create<ast::StructMemberAlignAttribute>(1024u)}),
});
AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type)); AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",

View File

@ -2274,17 +2274,19 @@ class ProgramBuilder {
/// Creates a ast::StructMemberAlignAttribute /// Creates a ast::StructMemberAlignAttribute
/// @param source the source information /// @param source the source information
/// @param val the align value /// @param val the align value expression
/// @returns the align attribute pointer /// @returns the align attribute pointer
const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, uint32_t val) { template <typename EXPR>
return create<ast::StructMemberAlignAttribute>(source, val); const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, EXPR&& val) {
return create<ast::StructMemberAlignAttribute>(source, Expr(std::forward<EXPR>(val)));
} }
/// Creates a ast::StructMemberAlignAttribute /// Creates a ast::StructMemberAlignAttribute
/// @param val the align value /// @param val the align value expression
/// @returns the align attribute pointer /// @returns the align attribute pointer
const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) { template <typename EXPR>
return create<ast::StructMemberAlignAttribute>(source_, val); const ast::StructMemberAlignAttribute* MemberAlign(EXPR&& val) {
return create<ast::StructMemberAlignAttribute>(source_, Expr(std::forward<EXPR>(val)));
} }
/// Creates the ast::GroupAttribute /// Creates the ast::GroupAttribute

View File

@ -3874,7 +3874,9 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
} }
match(Token::Type::kComma); match(Token::Type::kComma);
return create<ast::StructMemberAlignAttribute>(t.source(), val.value); return create<ast::StructMemberAlignAttribute>(
t.source(), create<ast::IntLiteralExpression>(
val.value, ast::IntLiteralExpression::Suffix::kNone));
}); });
} }

View File

@ -102,7 +102,10 @@ TEST_F(ParserImplTest, Attribute_Align) {
ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>()); ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
auto* o = member_attr->As<ast::StructMemberAlignAttribute>(); auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
EXPECT_EQ(o->align, 4u); ASSERT_TRUE(o->align->Is<ast::IntLiteralExpression>());
EXPECT_EQ(o->align->As<ast::IntLiteralExpression>()->value, 4);
EXPECT_EQ(o->align->As<ast::IntLiteralExpression>()->suffix,
ast::IntLiteralExpression::Suffix::kNone);
} }
TEST_F(ParserImplTest, Attribute_Align_TrailingComma) { TEST_F(ParserImplTest, Attribute_Align_TrailingComma) {
@ -118,7 +121,11 @@ TEST_F(ParserImplTest, Attribute_Align_TrailingComma) {
ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>()); ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
auto* o = member_attr->As<ast::StructMemberAlignAttribute>(); auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
EXPECT_EQ(o->align, 4u); ASSERT_TRUE(o->align->Is<ast::IntLiteralExpression>());
auto* expr = o->align->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 4);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
} }
TEST_F(ParserImplTest, Attribute_Align_MissingLeftParen) { TEST_F(ParserImplTest, Attribute_Align_MissingLeftParen) {

View File

@ -49,7 +49,13 @@ TEST_F(ParserImplTest, StructMember_ParsesWithAlignAttribute) {
EXPECT_TRUE(m->type->Is<ast::I32>()); EXPECT_TRUE(m->type->Is<ast::I32>());
EXPECT_EQ(m->attributes.Length(), 1u); EXPECT_EQ(m->attributes.Length(), 1u);
EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberAlignAttribute>()); EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberAlignAttribute>());
EXPECT_EQ(m->attributes[0]->As<ast::StructMemberAlignAttribute>()->align, 2u);
auto* attr = m->attributes[0]->As<ast::StructMemberAlignAttribute>();
ASSERT_TRUE(attr->align->Is<ast::IntLiteralExpression>());
auto* expr = attr->align->As<ast::IntLiteralExpression>();
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->source.range, (Source::Range{{1u, 11u}, {1u, 12u}}));
EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 15u}, {1u, 18u}})); 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_EQ(m->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(m->type->Is<ast::I32>()); EXPECT_TRUE(m->type->Is<ast::I32>());
EXPECT_EQ(m->attributes.Length(), 2u); EXPECT_EQ(m->attributes.Length(), 2u);
EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>()); ASSERT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u); EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
EXPECT_TRUE(m->attributes[1]->Is<ast::StructMemberAlignAttribute>());
EXPECT_EQ(m->attributes[1]->As<ast::StructMemberAlignAttribute>()->align, 4u); ASSERT_TRUE(m->attributes[1]->Is<ast::StructMemberAlignAttribute>());
auto* attr = m->attributes[1]->As<ast::StructMemberAlignAttribute>();
ASSERT_TRUE(attr->align->Is<ast::IntLiteralExpression>());
auto* expr = attr->align->As<ast::IntLiteralExpression>();
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->source.range, (Source::Range{{2u, 11u}, {2u, 12u}}));
EXPECT_EQ(m->type->source.range, (Source::Range{{2u, 15u}, {2u, 18u}})); EXPECT_EQ(m->type->source.range, (Source::Range{{2u, 15u}, {2u, 18u}}));

View File

@ -89,7 +89,7 @@ static utils::Vector<const ast::Attribute*, 2> createAttributes(const Source& so
AttributeKind kind) { AttributeKind kind) {
switch (kind) { switch (kind) {
case AttributeKind::kAlign: case AttributeKind::kAlign:
return {builder.create<ast::StructMemberAlignAttribute>(source, 4u)}; return {builder.MemberAlign(source, 4_u)};
case AttributeKind::kBinding: case AttributeKind::kBinding:
return {builder.create<ast::BindingAttribute>(source, 1u)}; return {builder.create<ast::BindingAttribute>(source, 1u)};
case AttributeKind::kBuiltin: case AttributeKind::kBuiltin:
@ -625,14 +625,13 @@ INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
TestParams{AttributeKind::kWorkgroup, false}, TestParams{AttributeKind::kWorkgroup, false},
TestParams{AttributeKind::kBindingAndGroup, false})); TestParams{AttributeKind::kBindingAndGroup, false}));
TEST_F(StructMemberAttributeTest, DuplicateAttribute) { TEST_F(StructMemberAttributeTest, DuplicateAttribute) {
Structure("mystruct", Structure("mystruct", utils::Vector{
utils::Vector{ Member("a", ty.i32(),
Member("a", ty.i32(), utils::Vector{
utils::Vector{ MemberAlign(Source{{12, 34}}, 4_u),
create<ast::StructMemberAlignAttribute>(Source{{12, 34}}, 4u), MemberAlign(Source{{56, 78}}, 8_u),
create<ast::StructMemberAlignAttribute>(Source{{56, 78}}, 8u), }),
}), });
});
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(),
R"(56:78 error: duplicate align attribute R"(56:78 error: duplicate align attribute

View File

@ -2673,11 +2673,26 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
align = 1; align = 1;
has_offset_attr = true; has_offset_attr = true;
} else if (auto* a = attr->As<ast::StructMemberAlignAttribute>()) { } else if (auto* a = attr->As<ast::StructMemberAlignAttribute>()) {
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<AInt>();
if (value <= 0 || !utils::IsPowerOfTwo(value)) {
AddError("align value must be a positive, power-of-two integer", a->source); AddError("align value must be a positive, power-of-two integer", a->source);
return nullptr; return nullptr;
} }
align = a->align; align = const_value->As<u32>();
has_align_attr = true; has_align_attr = true;
} else if (auto* s = attr->As<ast::StructMemberSizeAttribute>()) { } else if (auto* s = attr->As<ast::StructMemberSizeAttribute>()) {
if (s->size < size) { if (s->size < size) {

View File

@ -36,7 +36,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember)
Structure(Source{{12, 34}}, "S", Structure(Source{{12, 34}}, "S",
utils::Vector{ utils::Vector{
Member("a", ty.f32(), utils::Vector{MemberSize(5)}), 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), 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", Structure(Source{{12, 34}}, "S",
utils::Vector{ utils::Vector{
Member("a", ty.f32(), utils::Vector{MemberSize(5)}), 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), GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0),
@ -142,7 +142,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
utils::Vector{ utils::Vector{
Member("scalar", ty.f32()), Member("scalar", ty.f32()),
Member(Source{{56, 78}}, "inner", ty.type_name("Inner"), 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), 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{ utils::Vector{
Member("scalar", ty.f32()), Member("scalar", ty.f32()),
Member(Source{{34, 56}}, "inner", ty.type_name("Inner"), 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), 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", Structure(Source{{12, 34}}, "Inner",
utils::Vector{ 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", Structure(Source{{34, 56}}, "Outer",
@ -279,7 +279,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.i32()), Member("b", ty.i32()),
Member("c", 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", Structure(Source{{34, 56}}, "Outer",
@ -327,13 +327,13 @@ TEST_F(ResolverStorageClassLayoutValidationTest,
Structure(Source{{12, 34}}, "Inner", Structure(Source{{12, 34}}, "Inner",
utils::Vector{ 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", Structure(Source{{34, 56}}, "Outer",
utils::Vector{ utils::Vector{
Member(Source{{56, 78}}, "inner", ty.type_name("Inner")), 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), GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0),
@ -551,7 +551,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_UnalignedMember) {
Structure( Structure(
Source{{12, 34}}, "S", Source{{12, 34}}, "S",
utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}), 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); GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kPushConstant);
ASSERT_FALSE(r()->Resolve()); ASSERT_FALSE(r()->Resolve());
@ -576,7 +576,7 @@ TEST_F(ResolverStorageClassLayoutValidationTest, PushConstant_Aligned) {
// var<push_constant> a : S; // var<push_constant> a : S;
Enable(ast::Extension::kChromiumExperimentalPushConstant); Enable(ast::Extension::kChromiumExperimentalPushConstant);
Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5)}), 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); GlobalVar("a", ty.type_name("S"), ast::StorageClass::kPushConstant);
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();

View File

@ -498,15 +498,15 @@ TEST_F(ResolverStructLayoutTest, SizeAttributes) {
TEST_F(ResolverStructLayoutTest, AlignAttributes) { TEST_F(ResolverStructLayoutTest, AlignAttributes) {
auto* inner = Structure("Inner", utils::Vector{ auto* inner = Structure("Inner", utils::Vector{
Member("a", ty.f32(), utils::Vector{MemberAlign(8)}), Member("a", ty.f32(), utils::Vector{MemberAlign(8_u)}),
Member("b", ty.f32(), utils::Vector{MemberAlign(16)}), Member("b", ty.f32(), utils::Vector{MemberAlign(16_u)}),
Member("c", ty.f32(), utils::Vector{MemberAlign(4)}), Member("c", ty.f32(), utils::Vector{MemberAlign(4_u)}),
}); });
auto* s = Structure("S", utils::Vector{ auto* s = Structure("S", utils::Vector{
Member("a", ty.f32(), utils::Vector{MemberAlign(4)}), Member("a", ty.f32(), utils::Vector{MemberAlign(4_u)}),
Member("b", ty.u32(), utils::Vector{MemberAlign(8)}), Member("b", ty.u32(), utils::Vector{MemberAlign(8_u)}),
Member("c", ty.Of(inner)), 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(); ASSERT_TRUE(r()->Resolve()) << r()->error();
@ -536,7 +536,7 @@ TEST_F(ResolverStructLayoutTest, AlignAttributes) {
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) { TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
auto* s = Structure("S", utils::Vector{ 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(); ASSERT_TRUE(r()->Resolve()) << r()->error();

View File

@ -1239,7 +1239,7 @@ TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) {
TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) { TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
Structure("S", utils::Vector{ 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()); EXPECT_FALSE(r()->Resolve());
@ -1248,7 +1248,7 @@ TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) { TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) {
Structure("S", utils::Vector{ 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()); EXPECT_FALSE(r()->Resolve());
@ -1279,7 +1279,7 @@ TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) {
TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) { TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
Structure("S", utils::Vector{ Structure("S", utils::Vector{
Member(Source{{12, 34}}, "a", ty.f32(), Member(Source{{12, 34}}, "a", ty.f32(),
utils::Vector{MemberOffset(0), MemberAlign(4)}), utils::Vector{MemberOffset(0), MemberAlign(4_u)}),
}); });
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
@ -1291,7 +1291,7 @@ TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) { TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) {
Structure("S", utils::Vector{ Structure("S", utils::Vector{
Member(Source{{12, 34}}, "a", ty.f32(), 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()); EXPECT_FALSE(r()->Resolve());

View File

@ -13,9 +13,11 @@
// limitations under the License. // limitations under the License.
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "src/tint/number.h"
#include "src/tint/writer/glsl/test_helper.h" #include "src/tint/writer/glsl/test_helper.h"
using ::testing::HasSubstr; using ::testing::HasSubstr;
using namespace tint::number_suffixes; // NOLINT
namespace tint::writer::glsl { namespace tint::writer::glsl {
namespace { namespace {
@ -31,9 +33,9 @@ void TestAlign(ProgramBuilder* ctx) {
// @group(0) @binding(0) var<storage, read_write> nephews : Nephews; // @group(0) @binding(0) var<storage, read_write> nephews : Nephews;
auto* nephews = ctx->Structure( auto* nephews = ctx->Structure(
"Nephews", utils::Vector{ "Nephews", utils::Vector{
ctx->Member("huey", 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)}), ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}),
ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256)}), 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->GlobalVar("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage, ctx->Binding(0),
ctx->Group(0)); ctx->Group(0));

View File

@ -252,35 +252,35 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
} }
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
auto* s = auto* s = Structure(
Structure("S", utils::Vector{ "S", utils::Vector{
Member("a", ty.i32(), utils::Vector{MemberSize(32)}), Member("a", ty.i32(), utils::Vector{MemberSize(32)}),
Member("b", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}), Member("b", ty.f32(), utils::Vector{MemberAlign(128_u), MemberSize(128)}),
Member("c", ty.vec2<f32>()), Member("c", ty.vec2<f32>()),
Member("d", ty.u32()), Member("d", ty.u32()),
Member("e", ty.vec3<f32>()), Member("e", ty.vec3<f32>()),
Member("f", ty.u32()), Member("f", ty.u32()),
Member("g", ty.vec4<f32>()), Member("g", ty.vec4<f32>()),
Member("h", ty.u32()), Member("h", ty.u32()),
Member("i", ty.mat2x2<f32>()), Member("i", ty.mat2x2<f32>()),
Member("j", ty.u32()), Member("j", ty.u32()),
Member("k", ty.mat2x3<f32>()), Member("k", ty.mat2x3<f32>()),
Member("l", ty.u32()), Member("l", ty.u32()),
Member("m", ty.mat2x4<f32>()), Member("m", ty.mat2x4<f32>()),
Member("n", ty.u32()), Member("n", ty.u32()),
Member("o", ty.mat3x2<f32>()), Member("o", ty.mat3x2<f32>()),
Member("p", ty.u32()), Member("p", ty.u32()),
Member("q", ty.mat3x3<f32>()), Member("q", ty.mat3x3<f32>()),
Member("r", ty.u32()), Member("r", ty.u32()),
Member("s", ty.mat3x4<f32>()), Member("s", ty.mat3x4<f32>()),
Member("t", ty.u32()), Member("t", ty.u32()),
Member("u", ty.mat4x2<f32>()), Member("u", ty.mat4x2<f32>()),
Member("v", ty.u32()), Member("v", ty.u32()),
Member("w", ty.mat4x3<f32>()), Member("w", ty.mat4x3<f32>()),
Member("x", ty.u32()), Member("x", ty.u32()),
Member("y", ty.mat4x4<f32>()), Member("y", ty.mat4x4<f32>()),
Member("z", ty.f32()), Member("z", ty.f32()),
}); });
GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0), Group(0)); 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) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
// inner_x: size(1024), align(512) // inner_x: size(1024), align(512)
auto* inner_x = Structure("inner_x", utils::Vector{ auto* inner_x =
Member("a", ty.i32()), Structure("inner_x", utils::Vector{
Member("b", ty.f32(), utils::Vector{MemberAlign(512)}), Member("a", ty.i32()),
}); Member("b", ty.f32(), utils::Vector{MemberAlign(512_u)}),
});
// inner_y: size(516), align(4) // inner_y: size(516), align(4)
auto* inner_y = Structure("inner_y", utils::Vector{ auto* inner_y = Structure("inner_y", utils::Vector{
@ -456,7 +457,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// inner: size(1024), align(512) // inner: size(1024), align(512)
auto* inner = Structure("inner", utils::Vector{ auto* inner = Structure("inner", utils::Vector{
Member("a", ty.i32()), 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) // array_x: size(28), align(4)
@ -588,36 +589,36 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
} }
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) { TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
auto* s = Structure( auto* s = Structure("S", utils::Vector{
"S", utils::Vector{ // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
// uses symbols tint_pad_[0..9] and tint_pad_[20..35] Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32)}),
Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32)}), Member("tint_pad_20", ty.f32(),
Member("tint_pad_20", ty.f32(), utils::Vector{MemberAlign(128), MemberSize(128)}), utils::Vector{MemberAlign(128_u), MemberSize(128_u)}),
Member("tint_pad_33", ty.vec2<f32>()), Member("tint_pad_33", ty.vec2<f32>()),
Member("tint_pad_1", ty.u32()), Member("tint_pad_1", ty.u32()),
Member("tint_pad_3", ty.vec3<f32>()), Member("tint_pad_3", ty.vec3<f32>()),
Member("tint_pad_7", ty.u32()), Member("tint_pad_7", ty.u32()),
Member("tint_pad_25", ty.vec4<f32>()), Member("tint_pad_25", ty.vec4<f32>()),
Member("tint_pad_5", ty.u32()), Member("tint_pad_5", ty.u32()),
Member("tint_pad_27", ty.mat2x2<f32>()), Member("tint_pad_27", ty.mat2x2<f32>()),
Member("tint_pad_24", ty.u32()), Member("tint_pad_24", ty.u32()),
Member("tint_pad_23", ty.mat2x3<f32>()), Member("tint_pad_23", ty.mat2x3<f32>()),
Member("tint_pad", ty.u32()), Member("tint_pad", ty.u32()),
Member("tint_pad_8", ty.mat2x4<f32>()), Member("tint_pad_8", ty.mat2x4<f32>()),
Member("tint_pad_26", ty.u32()), Member("tint_pad_26", ty.u32()),
Member("tint_pad_29", ty.mat3x2<f32>()), Member("tint_pad_29", ty.mat3x2<f32>()),
Member("tint_pad_6", ty.u32()), Member("tint_pad_6", ty.u32()),
Member("tint_pad_22", ty.mat3x3<f32>()), Member("tint_pad_22", ty.mat3x3<f32>()),
Member("tint_pad_32", ty.u32()), Member("tint_pad_32", ty.u32()),
Member("tint_pad_34", ty.mat3x4<f32>()), Member("tint_pad_34", ty.mat3x4<f32>()),
Member("tint_pad_35", ty.u32()), Member("tint_pad_35", ty.u32()),
Member("tint_pad_30", ty.mat4x2<f32>()), Member("tint_pad_30", ty.mat4x2<f32>()),
Member("tint_pad_9", ty.u32()), Member("tint_pad_9", ty.u32()),
Member("tint_pad_31", ty.mat4x3<f32>()), Member("tint_pad_31", ty.mat4x3<f32>()),
Member("tint_pad_28", ty.u32()), Member("tint_pad_28", ty.u32()),
Member("tint_pad_4", ty.mat4x4<f32>()), Member("tint_pad_4", ty.mat4x4<f32>()),
Member("tint_pad_21", ty.f32()), Member("tint_pad_21", ty.f32()),
}); });
GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0), Group(0)); GlobalVar("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead, Binding(0), Group(0));

View File

@ -336,7 +336,7 @@ OpMemberName %1 0 "a"
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) { TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
auto* s = Structure("S", utils::Vector{ auto* s = Structure("S", utils::Vector{
Member("a", ty.f32()), 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(); spirv::Builder& b = Build();

View File

@ -776,7 +776,11 @@ bool GeneratorImpl::EmitAttributes(std::ostream& out,
return true; return true;
}, },
[&](const ast::StructMemberAlignAttribute* align) { [&](const ast::StructMemberAlignAttribute* align) {
out << "align(" << align->align << ")"; out << "align(";
if (!EmitExpression(out, align->align)) {
return false;
}
out << ")";
return true; return true;
}, },
[&](const ast::StrideAttribute* stride) { [&](const ast::StrideAttribute* stride) {

View File

@ -219,8 +219,8 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) { TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
auto* s = Structure("S", utils::Vector{ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32(), utils::Vector{MemberAlign(8)}), Member("a", ty.i32(), utils::Vector{MemberAlign(8_a)}),
Member("b", ty.f32(), utils::Vector{MemberAlign(16)}), Member("b", ty.f32(), utils::Vector{MemberAlign(16_a)}),
}); });
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
@ -256,7 +256,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) { TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) {
auto* s = Structure("S", utils::Vector{ auto* s = Structure("S", utils::Vector{
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32(), utils::Vector{MemberAlign(8)}), Member("b", ty.f32(), utils::Vector{MemberAlign(8_a)}),
}); });
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();