Skip to content

Commit 603a515

Browse files
zoddicusDawn LUCI CQ
authored andcommitted
[tint][val] Check that RTAs are only the last member of structs
Includes some rewriting of the struct type check to avoid accidentally skipping unrelated checks when matrix decorations are allowed. Fixes: 445906424 Change-Id: I57c73aa6580e9d08411f12be7fe7d305c5a7eb74 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/264554 Commit-Queue: dan sinclair <[email protected]> Commit-Queue: James Price <[email protected]> Reviewed-by: dan sinclair <[email protected]> Auto-Submit: Ryan Harrison <[email protected]> Reviewed-by: James Price <[email protected]>
1 parent f497812 commit 603a515

File tree

2 files changed

+196
-45
lines changed

2 files changed

+196
-45
lines changed

src/tint/lang/core/ir/validator.cc

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,32 +2018,23 @@ void Validator::CheckType(const core::type::Type* root,
20182018
return tint::Switch(
20192019
type,
20202020
[&](const core::type::Struct* str) {
2021-
if (capabilities_.Contains(Capability::kAllowStructMatrixDecorations)) {
2022-
return true;
2023-
}
2024-
20252021
for (auto* member : str->Members()) {
20262022
CheckType(member->Type(), diag, ignore_caps);
20272023

2028-
if (member->RowMajor()) {
2029-
diag() << "Row major annotation not allowed on structures";
2030-
return false;
2031-
}
2032-
if (member->HasMatrixStride()) {
2033-
diag() << "Matrix stride annotation not allowed on structures";
2034-
return false;
2035-
}
2036-
if (member->Size() < member->Type()->Size()) {
2037-
diag() << "struct member " << member->Index()
2038-
<< " with size=" << member->Size()
2039-
<< " must be at least as large as the type with size "
2040-
<< member->Type()->Size();
2041-
return false;
2042-
}
20432024
if (member->Type()->Is<core::type::Void>()) {
20442025
diag() << "struct member " << member->Index() << " cannot have void type";
20452026
return false;
20462027
}
2028+
2029+
if (auto* arr = member->Type()->As<core::type::Array>();
2030+
arr && arr->Count()->Is<core::type::RuntimeArrayCount>()) {
2031+
if (member != str->Members().Back()) {
2032+
diag() << "runtime-sized arrays can only be the last member of a "
2033+
"struct";
2034+
return false;
2035+
}
2036+
}
2037+
20472038
if (member->Align() == 0) {
20482039
diag() << "struct member must not have an alignment of 0";
20492040
return false;
@@ -2052,11 +2043,34 @@ void Validator::CheckType(const core::type::Type* root,
20522043
diag() << "struct member type must not have an alignment of 0";
20532044
return false;
20542045
}
2055-
if (member->Align() % member->Type()->Align() != 0) {
2056-
diag() << "struct member alignment (" << member->Align()
2057-
<< ") must be divisible by type alignment ("
2058-
<< member->Type()->Align() << ")";
2059-
return false;
2046+
2047+
if (!capabilities_.Contains(Capability::kAllowStructMatrixDecorations)) {
2048+
if (member->RowMajor()) {
2049+
diag() << "Row major annotation not allowed on structures";
2050+
return false;
2051+
}
2052+
if (member->HasMatrixStride()) {
2053+
diag() << "Matrix stride annotation not allowed on structures";
2054+
return false;
2055+
}
2056+
}
2057+
2058+
// TODO(448608979): Remove guard once updated to handle RowMajor correctly
2059+
if (!member->RowMajor()) {
2060+
if (member->Size() < member->Type()->Size()) {
2061+
diag() << "struct member " << member->Index()
2062+
<< " with size=" << member->Size()
2063+
<< " must be at least as large as the type with size "
2064+
<< member->Type()->Size();
2065+
return false;
2066+
}
2067+
2068+
if (member->Align() % member->Type()->Align() != 0) {
2069+
diag() << "struct member alignment (" << member->Align()
2070+
<< ") must be divisible by type alignment ("
2071+
<< member->Type()->Align() << ")";
2072+
return false;
2073+
}
20602074
}
20612075
}
20622076
return true;

src/tint/lang/core/ir/validator_type_test.cc

Lines changed: 158 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,164 @@ TEST_F(IR_ValidatorTest, StructMember_AlignNotDivisibleByTypeAlignment) {
314314
)")) << res.Failure();
315315
}
316316

317+
TEST_F(IR_ValidatorTest, StructureMember_SizeTooSmall) {
318+
auto* str_ty =
319+
ty.Struct(mod.symbols.New("S"),
320+
Vector{
321+
ty.Get<type::StructMember>(mod.symbols.New("a"), ty.array<u32, 3>(), 0u, 0u,
322+
4u, 4u, IOAttributes{}),
323+
});
324+
mod.root_block->Append(b.Var("my_struct", private_, str_ty));
325+
326+
auto* fn = b.Function("F", ty.void_());
327+
b.Append(fn->Block(), [&] { b.Return(fn); });
328+
329+
auto res = ir::Validate(mod);
330+
ASSERT_NE(res, Success);
331+
EXPECT_THAT(
332+
res.Failure().reason,
333+
testing::HasSubstr(
334+
"struct member 0 with size=4 must be at least as large as the type with size 12"))
335+
<< res.Failure();
336+
}
337+
338+
TEST_F(IR_ValidatorTest, StructMember_RuntimeArrayNotLast) {
339+
auto* s1 = ty.Struct(mod.symbols.New("S1"), {{mod.symbols.New("a"), ty.u32()}});
340+
auto* rta = ty.runtime_array(s1);
341+
342+
auto* str_ty = ty.Struct(mod.symbols.New("OuterS"), {
343+
{mod.symbols.New("a1"), rta},
344+
{mod.symbols.New("j"), ty.u32()},
345+
});
346+
347+
auto* v = b.Var(ty.ptr(storage, str_ty, read_write));
348+
v->SetBindingPoint(0, 0);
349+
mod.root_block->Append(v);
350+
351+
auto res = ir::Validate(mod);
352+
ASSERT_NE(res, Success);
353+
EXPECT_THAT(
354+
res.Failure().reason,
355+
testing::HasSubstr(
356+
R"(:11:3 error: var: runtime-sized arrays can only be the last member of a struct
357+
%1:ptr<storage, OuterS, read_write> = var undef @binding_point(0, 0)
358+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^)"))
359+
<< res.Failure();
360+
}
361+
362+
TEST_F(IR_ValidatorTest, StructMember_RuntimeArrayIsLast) {
363+
auto* s1 = ty.Struct(mod.symbols.New("S1"), {{mod.symbols.New("a"), ty.u32()}});
364+
auto* rta = ty.runtime_array(s1);
365+
366+
auto* str_ty = ty.Struct(mod.symbols.New("OuterS"), {
367+
{mod.symbols.New("j"), ty.u32()},
368+
{mod.symbols.New("a1"), rta},
369+
});
370+
371+
auto* v = b.Var(ty.ptr(storage, str_ty, read_write));
372+
v->SetBindingPoint(0, 0);
373+
mod.root_block->Append(v);
374+
375+
auto res = ir::Validate(mod);
376+
ASSERT_EQ(res, Success) << res.Failure();
377+
}
378+
379+
TEST_F(IR_ValidatorTest, StructMember_MultipleRuntimeArrays) {
380+
auto* s1 = ty.Struct(mod.symbols.New("S1"), {{mod.symbols.New("a"), ty.u32()}});
381+
auto* rta = ty.runtime_array(s1);
382+
383+
auto* str_ty = ty.Struct(mod.symbols.New("OuterS"), {
384+
{mod.symbols.New("a1"), rta},
385+
{mod.symbols.New("a2"), rta},
386+
});
387+
388+
auto* v = b.Var(ty.ptr(storage, str_ty, read_write));
389+
v->SetBindingPoint(0, 0);
390+
mod.root_block->Append(v);
391+
392+
auto res = ir::Validate(mod);
393+
ASSERT_NE(res, Success);
394+
EXPECT_THAT(
395+
res.Failure().reason,
396+
testing::HasSubstr(
397+
R"(:11:3 error: var: runtime-sized arrays can only be the last member of a struct
398+
%1:ptr<storage, OuterS, read_write> = var undef @binding_point(0, 0)
399+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^)"))
400+
<< res.Failure();
401+
}
402+
403+
TEST_F(IR_ValidatorTest, StructMember_RowMajor_WithoutCapability) {
404+
auto* mat_ty = ty.mat2x2<f32>();
405+
auto* member = ty.Get<core::type::StructMember>(
406+
mod.symbols.New("m"), mat_ty, 0u, 0u, mat_ty->Align(), mat_ty->Size(), IOAttributes{});
407+
member->SetRowMajor();
408+
auto* str_ty =
409+
ty.Get<core::type::Struct>(mod.symbols.New("MyStruct"), Vector{member}, mat_ty->Size());
410+
411+
auto* v = b.Var(ty.ptr(private_, str_ty));
412+
mod.root_block->Append(v);
413+
414+
auto res = ir::Validate(mod);
415+
ASSERT_NE(res, Success);
416+
EXPECT_THAT(
417+
res.Failure().reason,
418+
testing::HasSubstr(R"(:6:3 error: var: Row major annotation not allowed on structures
419+
%1:ptr<private, MyStruct, read_write> = var undef
420+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
421+
)")) << res.Failure();
422+
}
423+
424+
TEST_F(IR_ValidatorTest, StructMember_RowMajor_WithCapability) {
425+
auto* mat_ty = ty.mat2x2<f32>();
426+
auto* member = ty.Get<core::type::StructMember>(
427+
mod.symbols.New("m"), mat_ty, 0u, 0u, mat_ty->Align(), mat_ty->Size(), IOAttributes{});
428+
member->SetRowMajor();
429+
auto* str_ty =
430+
ty.Get<core::type::Struct>(mod.symbols.New("MyStruct"), Vector{member}, mat_ty->Size());
431+
432+
auto* v = b.Var(ty.ptr(private_, str_ty));
433+
mod.root_block->Append(v);
434+
435+
auto res = ir::Validate(mod, Capabilities{Capability::kAllowStructMatrixDecorations});
436+
ASSERT_EQ(res, Success) << res.Failure();
437+
}
438+
439+
TEST_F(IR_ValidatorTest, StructMember_MatrixStride_WithoutCapability) {
440+
auto* mat_ty = ty.mat2x2<f32>();
441+
auto* member = ty.Get<core::type::StructMember>(
442+
mod.symbols.New("m"), mat_ty, 0u, 0u, mat_ty->Align(), mat_ty->Size(), IOAttributes{});
443+
member->SetMatrixStride(32);
444+
auto* str_ty =
445+
ty.Get<core::type::Struct>(mod.symbols.New("MyStruct"), Vector{member}, mat_ty->Size());
446+
447+
auto* v = b.Var(ty.ptr(private_, str_ty));
448+
mod.root_block->Append(v);
449+
450+
auto res = ir::Validate(mod);
451+
ASSERT_NE(res, Success);
452+
EXPECT_THAT(
453+
res.Failure().reason,
454+
testing::HasSubstr(R"(:6:3 error: var: Matrix stride annotation not allowed on structures
455+
%1:ptr<private, MyStruct, read_write> = var undef
456+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
457+
)")) << res.Failure();
458+
}
459+
460+
TEST_F(IR_ValidatorTest, StructMember_MatrixStride_WithCapability) {
461+
auto* mat_ty = ty.mat2x2<f32>();
462+
auto* member = ty.Get<core::type::StructMember>(
463+
mod.symbols.New("m"), mat_ty, 0u, 0u, mat_ty->Align(), mat_ty->Size(), IOAttributes{});
464+
member->SetMatrixStride(32);
465+
auto* str_ty =
466+
ty.Get<core::type::Struct>(mod.symbols.New("MyStruct"), Vector{member}, mat_ty->Size());
467+
468+
auto* v = b.Var(ty.ptr(private_, str_ty));
469+
mod.root_block->Append(v);
470+
471+
auto res = ir::Validate(mod, Capabilities{Capability::kAllowStructMatrixDecorations});
472+
ASSERT_EQ(res, Success) << res.Failure();
473+
}
474+
317475
TEST_F(IR_ValidatorTest, FunctionParam_InvalidAddressSpaceForHandleType) {
318476
auto* type = ty.ptr(AddressSpace::kFunction, ty.sampler());
319477
auto* fn = b.Function("my_func", ty.void_());
@@ -1342,27 +1500,6 @@ TEST_P(AddressSpace_AccessMode, Test) {
13421500
}
13431501
}
13441502

1345-
TEST_F(IR_ValidatorTest, StructureMemberSizeTooSmall) {
1346-
auto* str_ty =
1347-
ty.Struct(mod.symbols.New("S"),
1348-
Vector{
1349-
ty.Get<type::StructMember>(mod.symbols.New("a"), ty.array<u32, 3>(), 0u, 0u,
1350-
4u, 4u, IOAttributes{}),
1351-
});
1352-
mod.root_block->Append(b.Var("my_struct", private_, str_ty));
1353-
1354-
auto* fn = b.Function("F", ty.void_());
1355-
b.Append(fn->Block(), [&] { b.Return(fn); });
1356-
1357-
auto res = ir::Validate(mod);
1358-
ASSERT_NE(res, Success);
1359-
EXPECT_THAT(
1360-
res.Failure().reason,
1361-
testing::HasSubstr(
1362-
"struct member 0 with size=4 must be at least as large as the type with size 12"))
1363-
<< res.Failure();
1364-
}
1365-
13661503
INSTANTIATE_TEST_SUITE_P(IR_ValidatorTest,
13671504
AddressSpace_AccessMode,
13681505
testing::Combine(testing::Values(AddressSpace::kFunction,

0 commit comments

Comments
 (0)