Convert `align` attribute to expressions.
This CL updates the align attribute to parse expressions. Bug: tint:1633 Change-Id: I5412180ff62e6b286b35ea3297e2b4f136899960 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/102841 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
5b0bab84be
commit
cb41b8f97f
|
@ -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_u)}),
|
Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
|
||||||
|
@ -3239,7 +3239,7 @@ TEST_F(InspectorGetWorkgroupStorageSizeTest, StructAlignment) {
|
||||||
// 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", utils::Vector{
|
"WgStruct", utils::Vector{
|
||||||
MakeStructMember(0, ty.f32(), utils::Vector{MemberAlign(1024_u)}),
|
MakeStructMember(0, ty.f32(), utils::Vector{MemberAlign(1024_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
|
AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
|
||||||
|
|
|
@ -3435,15 +3435,16 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
||||||
if (t == "align") {
|
if (t == "align") {
|
||||||
const char* use = "align attribute";
|
const char* use = "align attribute";
|
||||||
return expect_paren_block(use, [&]() -> Result {
|
return expect_paren_block(use, [&]() -> Result {
|
||||||
auto val = expect_positive_sint(use);
|
auto expr = expression();
|
||||||
if (val.errored) {
|
if (expr.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
if (!expr.matched) {
|
||||||
|
return add_error(peek(), "expected align expression");
|
||||||
|
}
|
||||||
match(Token::Type::kComma);
|
match(Token::Type::kComma);
|
||||||
|
|
||||||
return create<ast::StructMemberAlignAttribute>(
|
return create<ast::StructMemberAlignAttribute>(t.source(), expr.value);
|
||||||
t.source(), create<ast::IntLiteralExpression>(
|
|
||||||
val.value, ast::IntLiteralExpression::Suffix::kNone));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -851,17 +851,9 @@ struct S { 1 : i32, };
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignInvaldValue) {
|
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignInvaldValue) {
|
||||||
EXPECT("struct S { @align(x) i : i32, };",
|
EXPECT("struct S { @align(fn) i : i32, };",
|
||||||
R"(test.wgsl:1:19 error: expected signed integer literal for align attribute
|
R"(test.wgsl:1:19 error: expected align expression
|
||||||
struct S { @align(x) i : i32, };
|
struct S { @align(fn) i : i32, };
|
||||||
^
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignNegativeValue) {
|
|
||||||
EXPECT("struct S { @align(-2) i : i32, };",
|
|
||||||
R"(test.wgsl:1:19 error: align attribute must be positive
|
|
||||||
struct S { @align(-2) i : i32, };
|
|
||||||
^^
|
^^
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,12 @@ TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
|
||||||
TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {
|
TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {
|
||||||
auto p = parser(R"(
|
auto p = parser(R"(
|
||||||
{
|
{
|
||||||
@align(nan) a : i32,
|
@align(if) a : i32,
|
||||||
})");
|
})");
|
||||||
auto m = p->expect_struct_body_decl();
|
auto m = p->expect_struct_body_decl();
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
ASSERT_TRUE(m.errored);
|
ASSERT_TRUE(m.errored);
|
||||||
EXPECT_EQ(p->error(), "3:10: expected signed integer literal for align attribute");
|
EXPECT_EQ(p->error(), "3:10: expected align expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
|
TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
|
||||||
|
|
|
@ -110,13 +110,39 @@ TEST_F(ParserImplTest, Attribute_Align) {
|
||||||
ast::IntLiteralExpression::Suffix::kNone);
|
ast::IntLiteralExpression::Suffix::kNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, Attribute_Align_Expression) {
|
||||||
|
auto p = parser("align(4 + 5)");
|
||||||
|
auto attr = p->attribute();
|
||||||
|
EXPECT_TRUE(attr.matched);
|
||||||
|
EXPECT_FALSE(attr.errored);
|
||||||
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
ASSERT_NE(attr.value, nullptr);
|
||||||
|
|
||||||
|
auto* member_attr = attr.value->As<ast::Attribute>();
|
||||||
|
ASSERT_NE(member_attr, nullptr);
|
||||||
|
ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
|
||||||
|
|
||||||
|
auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
|
||||||
|
ASSERT_TRUE(o->expr->Is<ast::BinaryExpression>());
|
||||||
|
auto* expr = o->expr->As<ast::BinaryExpression>();
|
||||||
|
|
||||||
|
EXPECT_EQ(ast::BinaryOp::kAdd, expr->op);
|
||||||
|
auto* v = expr->lhs->As<ast::IntLiteralExpression>();
|
||||||
|
ASSERT_NE(nullptr, v);
|
||||||
|
EXPECT_EQ(v->value, 4u);
|
||||||
|
|
||||||
|
v = expr->rhs->As<ast::IntLiteralExpression>();
|
||||||
|
ASSERT_NE(nullptr, v);
|
||||||
|
EXPECT_EQ(v->value, 5u);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, Attribute_Align_TrailingComma) {
|
TEST_F(ParserImplTest, Attribute_Align_TrailingComma) {
|
||||||
auto p = parser("align(4,)");
|
auto p = parser("align(4,)");
|
||||||
auto attr = p->attribute();
|
auto attr = p->attribute();
|
||||||
EXPECT_TRUE(attr.matched);
|
EXPECT_TRUE(attr.matched);
|
||||||
EXPECT_FALSE(attr.errored);
|
EXPECT_FALSE(attr.errored);
|
||||||
ASSERT_NE(attr.value, nullptr);
|
ASSERT_NE(attr.value, nullptr);
|
||||||
ASSERT_FALSE(p->has_error());
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
|
||||||
auto* member_attr = attr.value->As<ast::Attribute>();
|
auto* member_attr = attr.value->As<ast::Attribute>();
|
||||||
ASSERT_NE(member_attr, nullptr);
|
ASSERT_NE(member_attr, nullptr);
|
||||||
|
@ -157,17 +183,18 @@ TEST_F(ParserImplTest, Attribute_Align_MissingValue) {
|
||||||
EXPECT_TRUE(attr.errored);
|
EXPECT_TRUE(attr.errored);
|
||||||
EXPECT_EQ(attr.value, nullptr);
|
EXPECT_EQ(attr.value, nullptr);
|
||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:7: expected signed integer literal for align attribute");
|
EXPECT_EQ(p->error(), "1:7: expected align expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, Attribute_Align_MissingInvalid) {
|
TEST_F(ParserImplTest, Attribute_Align_ExpressionInvalid) {
|
||||||
auto p = parser("align(nan)");
|
auto p = parser("align(4 + 5 << 6)");
|
||||||
auto attr = p->attribute();
|
auto attr = p->attribute();
|
||||||
EXPECT_FALSE(attr.matched);
|
EXPECT_FALSE(attr.matched);
|
||||||
EXPECT_TRUE(attr.errored);
|
EXPECT_TRUE(attr.errored);
|
||||||
EXPECT_EQ(attr.value, nullptr);
|
EXPECT_EQ(attr.value, nullptr);
|
||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:7: expected signed integer literal for align attribute");
|
|
||||||
|
EXPECT_EQ(p->error(), "1:13: expected ')' for align attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -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.MemberAlign(source, 4_u)};
|
return {builder.MemberAlign(source, 4_i)};
|
||||||
case AttributeKind::kBinding:
|
case AttributeKind::kBinding:
|
||||||
return {builder.Binding(source, 1_a)};
|
return {builder.Binding(source, 1_a)};
|
||||||
case AttributeKind::kBuiltin:
|
case AttributeKind::kBuiltin:
|
||||||
|
@ -627,8 +627,8 @@ TEST_F(StructMemberAttributeTest, DuplicateAttribute) {
|
||||||
Structure("mystruct", utils::Vector{
|
Structure("mystruct", utils::Vector{
|
||||||
Member("a", ty.i32(),
|
Member("a", ty.i32(),
|
||||||
utils::Vector{
|
utils::Vector{
|
||||||
MemberAlign(Source{{12, 34}}, 4_u),
|
MemberAlign(Source{{12, 34}}, 4_i),
|
||||||
MemberAlign(Source{{56, 78}}, 8_u),
|
MemberAlign(Source{{56, 78}}, 8_i),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -659,6 +659,89 @@ TEST_F(StructMemberAttributeTest, InvariantAttributeWithoutPosition) {
|
||||||
"position builtin");
|
"position builtin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_Const) {
|
||||||
|
GlobalConst("val", ty.i32(), Expr(1_i));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberAlign("val")})});
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstNegative) {
|
||||||
|
GlobalConst("val", ty.i32(), Expr(-2_i));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
R"(12:34 error: 'align' value must be a positive, power-of-two integer)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstPowerOfTwo) {
|
||||||
|
GlobalConst("val", ty.i32(), Expr(3_i));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
R"(12:34 error: 'align' value must be a positive, power-of-two integer)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstF32) {
|
||||||
|
GlobalConst("val", ty.f32(), Expr(1.23_f));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), R"(12:34 error: 'align' must be an i32 value)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstU32) {
|
||||||
|
GlobalConst("val", ty.u32(), Expr(2_u));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), R"(12:34 error: 'align' must be an i32 value)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstAInt) {
|
||||||
|
GlobalConst("val", Expr(2_a));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_ConstAFloat) {
|
||||||
|
GlobalConst("val", Expr(2.0_a));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), R"(12:34 error: 'align' must be an i32 value)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_Var) {
|
||||||
|
GlobalVar(Source{{1, 2}}, "val", ty.f32(), ast::StorageClass::kPrivate, ast::Access::kUndefined,
|
||||||
|
Expr(1.23_f));
|
||||||
|
|
||||||
|
Structure(Source{{6, 4}}, "mystruct",
|
||||||
|
utils::Vector{Member(Source{{12, 5}}, "a", ty.f32(),
|
||||||
|
utils::Vector{MemberAlign(Expr(Source{{12, 35}}, "val"))})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), R"(12:35 error: var 'val' cannot be referenced at module-scope
|
||||||
|
1:2 note: var 'val' declared here)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructMemberAttributeTest, Align_Attribute_Override) {
|
||||||
|
Override("val", ty.f32(), Expr(1.23_f));
|
||||||
|
|
||||||
|
Structure("mystruct", utils::Vector{Member(
|
||||||
|
"a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, "val")})});
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), R"(12:34 error: 'align' must be an i32 value)");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace StructAndStructMemberTests
|
} // namespace StructAndStructMemberTests
|
||||||
|
|
||||||
using ArrayAttributeTest = TestWithParams;
|
using ArrayAttributeTest = TestWithParams;
|
||||||
|
|
|
@ -182,6 +182,7 @@ class DependencyScanner {
|
||||||
[&](const ast::Struct* str) {
|
[&](const ast::Struct* str) {
|
||||||
Declare(str->name, str);
|
Declare(str->name, str);
|
||||||
for (auto* member : str->members) {
|
for (auto* member : str->members) {
|
||||||
|
TraverseAttributes(member->attributes);
|
||||||
TraverseType(member->type);
|
TraverseType(member->type);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -421,11 +422,16 @@ class DependencyScanner {
|
||||||
TraverseExpression(wg->z);
|
TraverseExpression(wg->z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (auto* align = attr->As<ast::StructMemberAlignAttribute>()) {
|
||||||
|
TraverseExpression(align->expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (attr->IsAnyOf<ast::BindingAttribute, ast::BuiltinAttribute, ast::GroupAttribute,
|
if (attr->IsAnyOf<ast::BindingAttribute, ast::BuiltinAttribute, ast::GroupAttribute,
|
||||||
ast::IdAttribute, ast::InternalAttribute, ast::InterpolateAttribute,
|
ast::IdAttribute, ast::InternalAttribute, ast::InterpolateAttribute,
|
||||||
ast::InvariantAttribute, ast::LocationAttribute, ast::StageAttribute,
|
ast::InvariantAttribute, ast::LocationAttribute, ast::StageAttribute,
|
||||||
ast::StrideAttribute, ast::StructMemberAlignAttribute,
|
ast::StrideAttribute, ast::StructMemberOffsetAttribute,
|
||||||
ast::StructMemberOffsetAttribute, ast::StructMemberSizeAttribute>()) {
|
ast::StructMemberSizeAttribute>()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1229,7 +1229,10 @@ TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
|
||||||
#define F add_use(func_decl, Expr(func_sym), __LINE__, "F()")
|
#define F add_use(func_decl, Expr(func_sym), __LINE__, "F()")
|
||||||
|
|
||||||
Alias(Sym(), T);
|
Alias(Sym(), T);
|
||||||
Structure(Sym(), utils::Vector{Member(Sym(), T)});
|
Structure(Sym(), //
|
||||||
|
utils::Vector{
|
||||||
|
Member(Sym(), T, utils::Vector{MemberAlign(V)}) //
|
||||||
|
});
|
||||||
GlobalVar(Sym(), T, V);
|
GlobalVar(Sym(), T, V);
|
||||||
GlobalConst(Sym(), T, V);
|
GlobalConst(Sym(), T, V);
|
||||||
Func(Sym(), //
|
Func(Sym(), //
|
||||||
|
|
|
@ -2821,15 +2821,20 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||||
if (!materialized) {
|
if (!materialized) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (!materialized->Type()->Is<sem::I32>()) {
|
||||||
|
AddError("'align' must be an i32 value", a->source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto const_value = materialized->ConstantValue();
|
auto const_value = materialized->ConstantValue();
|
||||||
if (!const_value) {
|
if (!const_value) {
|
||||||
AddError("'align' must be constant expression", a->expr->source);
|
AddError("'align' must be constant expression", a->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto value = const_value->As<AInt>();
|
auto value = const_value->As<AInt>();
|
||||||
|
|
||||||
if (value <= 0 || !utils::IsPowerOfTwo(value)) {
|
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 = const_value->As<u32>();
|
align = const_value->As<u32>();
|
||||||
|
|
|
@ -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_a)}),
|
Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_u)}),
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
||||||
|
@ -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_a)}),
|
Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_u)}),
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(4_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage, Group(0_a),
|
||||||
|
@ -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_u)}),
|
utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
||||||
|
@ -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_u)}),
|
utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
||||||
|
@ -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_u), MemberSize(5_a)}),
|
Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_i), MemberSize(5_a)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
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_u), MemberSize(5_a)}),
|
Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_i), MemberSize(5_a)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
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_u), MemberSize(5_a)}),
|
Member("scalar", ty.i32(), utils::Vector{MemberAlign(1_i), MemberSize(5_a)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
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_u)}),
|
Member(Source{{78, 90}}, "scalar", ty.i32(), utils::Vector{MemberAlign(16_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
GlobalVar(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform, Group(0_a),
|
||||||
|
@ -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_a)}),
|
utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_u)})});
|
Member(Source{{34, 56}}, "b", ty.f32(), utils::Vector{MemberAlign(1_i)})});
|
||||||
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_a)}),
|
Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(5_a)}),
|
||||||
Member("b", ty.f32(), utils::Vector{MemberAlign(4_u)})});
|
Member("b", ty.f32(), utils::Vector{MemberAlign(4_i)})});
|
||||||
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();
|
||||||
|
|
|
@ -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_u)}),
|
Member("a", ty.f32(), utils::Vector{MemberAlign(8_i)}),
|
||||||
Member("b", ty.f32(), utils::Vector{MemberAlign(16_u)}),
|
Member("b", ty.f32(), utils::Vector{MemberAlign(16_i)}),
|
||||||
Member("c", ty.f32(), utils::Vector{MemberAlign(4_u)}),
|
Member("c", ty.f32(), utils::Vector{MemberAlign(4_i)}),
|
||||||
});
|
});
|
||||||
auto* s = Structure("S", utils::Vector{
|
auto* s = Structure("S", utils::Vector{
|
||||||
Member("a", ty.f32(), utils::Vector{MemberAlign(4_u)}),
|
Member("a", ty.f32(), utils::Vector{MemberAlign(4_i)}),
|
||||||
Member("b", ty.u32(), utils::Vector{MemberAlign(8_u)}),
|
Member("b", ty.u32(), utils::Vector{MemberAlign(8_i)}),
|
||||||
Member("c", ty.Of(inner)),
|
Member("c", ty.Of(inner)),
|
||||||
Member("d", ty.i32(), utils::Vector{MemberAlign(32_u)}),
|
Member("d", ty.i32(), utils::Vector{MemberAlign(32_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
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_u)}),
|
Member("a", ty.i32(), utils::Vector{MemberAlign(1024_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
|
@ -1237,22 +1237,31 @@ TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) {
|
||||||
EXPECT_TRUE(r()->Resolve());
|
EXPECT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
|
TEST_F(ResolverValidationTest, NegativeStructMemberAlignAttribute) {
|
||||||
Structure("S", utils::Vector{
|
Structure("S", utils::Vector{
|
||||||
Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 3_u)}),
|
Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, -2_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: align value must be a positive, power-of-two integer");
|
EXPECT_EQ(r()->error(), "12:34 error: 'align' value must be a positive, power-of-two integer");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
|
||||||
|
Structure("S", utils::Vector{
|
||||||
|
Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 3_i)}),
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: 'align' value must be a positive, power-of-two integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
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_u)}),
|
Member("a", ty.f32(), utils::Vector{MemberAlign(Source{{12, 34}}, 0_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: align value must be a positive, power-of-two integer");
|
EXPECT_EQ(r()->error(), "12:34 error: 'align' value must be a positive, power-of-two integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
|
TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
|
||||||
|
@ -1279,7 +1288,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_a), MemberAlign(4_u)}),
|
utils::Vector{MemberOffset(0_a), MemberAlign(4_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -1291,7 +1300,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_a), MemberAlign(4_u), MemberSize(4_a)}),
|
utils::Vector{MemberOffset(0_a), MemberAlign(4_i), MemberSize(4_a)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
|
@ -460,7 +460,7 @@ struct Std140::State {
|
||||||
// The matrix was @align() annotated with a larger alignment
|
// The matrix was @align() annotated with a larger alignment
|
||||||
// than the natural alignment for the matrix. This extra padding
|
// than the natural alignment for the matrix. This extra padding
|
||||||
// needs to be applied to the first column vector.
|
// needs to be applied to the first column vector.
|
||||||
attributes.Push(b.MemberAlign(u32(align)));
|
attributes.Push(b.MemberAlign(i32(align)));
|
||||||
}
|
}
|
||||||
if ((i == num_columns - 1) && mat->Size() != size) {
|
if ((i == num_columns - 1) && mat->Size() != size) {
|
||||||
// The matrix was @size() annotated with a larger size than the
|
// The matrix was @size() annotated with a larger size than the
|
||||||
|
|
|
@ -200,7 +200,7 @@ struct S {
|
||||||
|
|
||||||
struct S_std140 {
|
struct S_std140 {
|
||||||
before : i32,
|
before : i32,
|
||||||
@align(128u)
|
@align(128i)
|
||||||
m_0 : vec2<f32>,
|
m_0 : vec2<f32>,
|
||||||
m_1 : vec2<f32>,
|
m_1 : vec2<f32>,
|
||||||
m_2 : vec2<f32>,
|
m_2 : vec2<f32>,
|
||||||
|
@ -272,7 +272,7 @@ struct S {
|
||||||
|
|
||||||
struct S_std140 {
|
struct S_std140 {
|
||||||
before : i32,
|
before : i32,
|
||||||
@align(128u)
|
@align(128i)
|
||||||
m_0 : vec2<f32>,
|
m_0 : vec2<f32>,
|
||||||
m_1 : vec2<f32>,
|
m_1 : vec2<f32>,
|
||||||
@size(112)
|
@size(112)
|
||||||
|
|
|
@ -33,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_u)}),
|
ctx->Member("huey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_i)}),
|
||||||
ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}),
|
ctx->Member("dewey", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_i)}),
|
||||||
ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_u)}),
|
ctx->Member("louie", ctx->ty.f32(), utils::Vector{ctx->MemberAlign(256_i)}),
|
||||||
});
|
});
|
||||||
ctx->GlobalVar("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage, ctx->Binding(0_a),
|
ctx->GlobalVar("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage, ctx->Binding(0_a),
|
||||||
ctx->Group(0_a));
|
ctx->Group(0_a));
|
||||||
|
|
|
@ -255,7 +255,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
||||||
auto* s = Structure(
|
auto* s = Structure(
|
||||||
"S", utils::Vector{
|
"S", utils::Vector{
|
||||||
Member("a", ty.i32(), utils::Vector{MemberSize(32_a)}),
|
Member("a", ty.i32(), utils::Vector{MemberSize(32_a)}),
|
||||||
Member("b", ty.f32(), utils::Vector{MemberAlign(128_u), MemberSize(128_a)}),
|
Member("b", ty.f32(), utils::Vector{MemberAlign(128_i), MemberSize(128_a)}),
|
||||||
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>()),
|
||||||
|
@ -372,7 +372,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
||||||
auto* inner_x =
|
auto* inner_x =
|
||||||
Structure("inner_x", utils::Vector{
|
Structure("inner_x", utils::Vector{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32(), utils::Vector{MemberAlign(512_u)}),
|
Member("b", ty.f32(), utils::Vector{MemberAlign(512_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// inner_y: size(516), align(4)
|
// inner_y: size(516), align(4)
|
||||||
|
@ -460,7 +460,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_u)}),
|
Member("b", ty.f32(), utils::Vector{MemberAlign(512_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// array_x: size(28), align(4)
|
// array_x: size(28), align(4)
|
||||||
|
@ -598,7 +598,7 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
||||||
// 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_a)}),
|
Member("tint_pad_2", ty.i32(), utils::Vector{MemberSize(32_a)}),
|
||||||
Member("tint_pad_20", ty.f32(),
|
Member("tint_pad_20", ty.f32(),
|
||||||
utils::Vector{MemberAlign(128_u), MemberSize(128_u)}),
|
utils::Vector{MemberAlign(128_i), 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>()),
|
||||||
|
|
|
@ -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_u)}),
|
Member("b", ty.f32(), utils::Vector{MemberAlign(8_i)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
Loading…
Reference in New Issue