writer/spirv: Validate arrayLength()
This was tested but the output was not run through the validator.
Once the AST is actually correct, the output is validated correctly.
Fixed: tint:266
Change-Id: I83bb53323c124c8fbaa3cd9b80524f89c2e30557
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40601
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index bd8e0c3..1095e34 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -25,6 +25,7 @@
#include "src/ast/sint_literal.h"
#include "src/ast/stage_decoration.h"
#include "src/ast/struct.h"
+#include "src/ast/struct_block_decoration.h"
#include "src/ast/struct_member.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/uint_literal.h"
@@ -1406,77 +1407,103 @@
}
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
- auto* s =
- create<ast::Struct>(ast::StructMemberList{Member("a", ty.array<f32>())},
- ast::StructDecorationList{});
+ auto* s = create<ast::Struct>(
+ ast::StructMemberList{Member(0, "a", ty.array<f32>(4))},
+ ast::StructDecorationList{
+ create<ast::StructBlockDecoration>(),
+ });
auto* s_type = ty.struct_("my_struct", s);
- auto* var = Global("b", ast::StorageClass::kPrivate, s_type);
+ Global("b", ast::StorageClass::kStorage, s_type, nullptr,
+ ast::VariableDecorationList{
+ create<ast::BindingDecoration>(1),
+ create<ast::GroupDecoration>(2),
+ });
auto* expr = Call("arrayLength", MemberAccessor("b", "a"));
- WrapInFunction(expr);
- auto* func = Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{}, ast::FunctionDecorationList{});
+ Func("a_func", ast::VariableList{}, ty.void_(),
+ ast::StatementList{
+ create<ast::CallStatement>(expr),
+ },
+ ast::FunctionDecorationList{
+ create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+ });
spirv::Builder& b = Build();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- EXPECT_EQ(b.GenerateExpression(expr), 11u) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()),
- R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%9 = OpTypeFloat 32
-%8 = OpTypeRuntimeArray %9
-%7 = OpTypeStruct %8
-%6 = OpTypePointer Private %7
-%10 = OpConstantNull %7
-%5 = OpVariable %6 Private %10
-%12 = OpTypeInt 32 0
-)");
+ ASSERT_EQ(b.functions().size(), 1u);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpArrayLength %12 %5 0
-)");
+ auto* expected_types = R"(%5 = OpTypeFloat 32
+%4 = OpTypeRuntimeArray %5
+%3 = OpTypeStruct %4
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
+
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
+
+ Validate(b);
}
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
- auto* s =
- create<ast::Struct>(ast::StructMemberList{Member("z", ty.f32()),
- Member("a", ty.array<f32>())},
- ast::StructDecorationList{});
+ auto* s = create<ast::Struct>(
+ ast::StructMemberList{Member(0, "z", ty.f32()),
+ Member(4, "a", ty.array<f32>(4))},
+ ast::StructDecorationList{
+ create<ast::StructBlockDecoration>(),
+ });
auto* s_type = ty.struct_("my_struct", s);
- auto* var = Global("b", ast::StorageClass::kPrivate, s_type);
+ Global("b", ast::StorageClass::kStorage, s_type, nullptr,
+ ast::VariableDecorationList{
+ create<ast::BindingDecoration>(1),
+ create<ast::GroupDecoration>(2),
+ });
auto* expr = Call("arrayLength", MemberAccessor("b", "a"));
- WrapInFunction(expr);
- auto* func = Func("a_func", ast::VariableList{}, ty.void_(),
- ast::StatementList{}, ast::FunctionDecorationList{});
+ Func("a_func", ast::VariableList{}, ty.void_(),
+ ast::StatementList{
+ create<ast::CallStatement>(expr),
+ },
+ ast::FunctionDecorationList{
+ create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+ });
spirv::Builder& b = Build();
- ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
- ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
- EXPECT_EQ(b.GenerateExpression(expr), 11u) << b.error();
+ ASSERT_TRUE(b.Build()) << b.error();
- EXPECT_EQ(DumpInstructions(b.types()),
- R"(%2 = OpTypeVoid
-%1 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%9 = OpTypeRuntimeArray %8
-%7 = OpTypeStruct %8 %9
-%6 = OpTypePointer Private %7
-%10 = OpConstantNull %7
-%5 = OpVariable %6 Private %10
-%12 = OpTypeInt 32 0
-)");
+ ASSERT_EQ(b.functions().size(), 1u);
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%11 = OpArrayLength %12 %5 1
-)");
+ auto* expected_types = R"(%4 = OpTypeFloat 32
+%5 = OpTypeRuntimeArray %4
+%3 = OpTypeStruct %4 %5
+%2 = OpTypePointer StorageBuffer %3
+%1 = OpVariable %2 StorageBuffer
+%7 = OpTypeVoid
+%6 = OpTypeFunction %7
+%11 = OpTypeInt 32 0
+)";
+ auto got_types = DumpInstructions(b.types());
+ EXPECT_EQ(expected_types, got_types);
+
+ auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
+)";
+ auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+ EXPECT_EQ(expected_instructions, got_instructions);
+
+ Validate(b);
}
} // namespace