From 42708348b796c86e198c6e2ca7245b86067ec3e3 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 21 Apr 2021 17:55:12 +0000 Subject: [PATCH] resolver: Validate uniform buffer types Fixed: tint:210 Change-Id: I7763ca23a5dce09755a1ca71d35f24897a875ac0 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48604 Commit-Queue: Ben Clayton Kokoro: Kokoro Reviewed-by: James Price --- src/ast/module_clone_test.cc | 4 +- src/inspector/inspector_test.cc | 25 -- src/program_builder.h | 43 ++- src/resolver/resolver.cc | 86 +++-- src/resolver/storage_class_validation_test.cc | 88 +++++ src/resolver/struct_storage_class_use_test.cc | 16 +- .../hlsl/generator_impl_function_test.cc | 334 +++++++++--------- .../msl/generator_impl_function_test.cc | 209 ++++++----- test/compute_boids.wgsl | 2 +- test/cube.wgsl | 2 +- 10 files changed, 463 insertions(+), 346 deletions(-) diff --git a/src/ast/module_clone_test.cc b/src/ast/module_clone_test.cc index 6f39c42ad2..6b614837e4 100644 --- a/src/ast/module_clone_test.cc +++ b/src/ast/module_clone_test.cc @@ -39,7 +39,7 @@ let c1 : bool = true; type t0 = [[stride(16)]] array>; type t1 = array>; -var g0 : u32 = 20u; +var g0 : u32 = 20u; var g1 : f32 = 123.0; var g2 : texture_2d; var g3 : [[access(read)]] texture_storage_2d; @@ -47,7 +47,7 @@ var g4 : [[access(write)]] texture_storage_2d; var g5 : [[access(read)]] texture_storage_2d; var g6 : [[access(write)]] texture_storage_2d; -[[builtin(position)]] var g7 : vec3; +var g7 : vec3; [[group(10), binding(20)]] var g8 : [[access(write)]] S; [[group(10), binding(20)]] var g9 : [[access(read)]] S; [[group(10), binding(20)]] var g10 : [[access(read_write)]] S; diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc index a14baa1a4a..eeb0ee7cb4 100644 --- a/src/inspector/inspector_test.cc +++ b/src/inspector/inspector_test.cc @@ -1822,31 +1822,6 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) { EXPECT_TRUE(error.find("not an entry point") != std::string::npos); } -TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingBlockDeco) { - ast::DecorationList decos; - auto* str = create( - Sym("foo_type"), - ast::StructMemberList{Member(StructMemberName(0, ty.i32()), ty.i32())}, - decos); - - auto* foo_type = ty.struct_(str); - AddUniformBuffer("foo_ub", foo_type, 0, 0); - - MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}}); - - MakeCallerBodyFunction( - "ep_func", {"ub_func"}, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), - }); - - Inspector& inspector = Build(); - - auto result = inspector.GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector.has_error()) << inspector.error(); - EXPECT_EQ(0u, result.size()); -} - TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple) { sem::StructType* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()}); diff --git a/src/program_builder.h b/src/program_builder.h index 2c6145033f..c006792e7b 100644 --- a/src/program_builder.h +++ b/src/program_builder.h @@ -985,13 +985,42 @@ class ProgramBuilder { decorations); } - /// @param args the arguments to pass to Var() - /// @returns a `ast::Variable` constructed by calling Var() with the arguments - /// of `args`, which is automatically registered as a global variable with the - /// ast::Module. - template - ast::Variable* Global(ARGS&&... args) { - auto* var = Var(std::forward(args)...); + /// @param name the variable name + /// @param type the variable type + /// @param storage the variable storage class + /// @param constructor constructor expression + /// @param decorations variable decorations + /// @returns a new `ast::Variable`, which is automatically registered as a + /// global variable with the ast::Module. + template + ast::Variable* Global(NAME&& name, + sem::Type* type, + ast::StorageClass storage, + ast::Expression* constructor = nullptr, + ast::DecorationList decorations = {}) { + auto* var = + Var(std::forward(name), type, storage, constructor, decorations); + AST().AddGlobalVariable(var); + return var; + } + + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param storage the variable storage class + /// @param constructor constructor expression + /// @param decorations variable decorations + /// @returns a new `ast::Variable`, which is automatically registered as a + /// global variable with the ast::Module. + template + ast::Variable* Global(const Source& source, + NAME&& name, + sem::Type* type, + ast::StorageClass storage, + ast::Expression* constructor = nullptr, + ast::DecorationList decorations = {}) { + auto* var = Var(source, std::forward(name), type, storage, + constructor, decorations); AST().AddGlobalVariable(var); return var; } diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index 084fe7c32d..6532144172 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -432,37 +432,69 @@ bool Resolver::GlobalVariable(ast::Variable* var) { } bool Resolver::ValidateGlobalVariable(const VariableInfo* info) { - if (info->storage_class == ast::StorageClass::kStorage) { - // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration - // Variables in the storage storage class and variables with a storage - // texture type must have an access attribute applied to the store type. + switch (info->storage_class) { + case ast::StorageClass::kStorage: { + // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration + // Variables in the storage storage class and variables with a storage + // texture type must have an access attribute applied to the store type. - // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables - // A variable in the storage storage class is a storage buffer variable. Its - // store type must be a host-shareable structure type with block attribute, - // satisfying the storage class constraints. + // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables + // A variable in the storage storage class is a storage buffer variable. + // Its store type must be a host-shareable structure type with block + // attribute, satisfying the storage class constraints. - auto* access = info->type->As(); - auto* str = access ? access->type()->As() : nullptr; - if (!str) { - diagnostics_.add_error( - "variables declared in the storage class must be of an " - "[[access]] qualified structure type", - info->declaration->source()); - return false; - } - - if (!str->IsBlockDecorated()) { - diagnostics_.add_error( - "structure used as a storage buffer must be declared with the " - "[[block]] decoration", - str->impl()->source()); - if (info->declaration->source().range.begin.line) { - diagnostics_.add_note("structure used as storage buffer here", - info->declaration->source()); + auto* access = info->type->As(); + auto* str = access ? access->type()->As() : nullptr; + if (!str) { + diagnostics_.add_error( + "variables declared in the storage class must be of an " + "[[access]] qualified structure type", + info->declaration->source()); + return false; } - return false; + + if (!str->IsBlockDecorated()) { + diagnostics_.add_error( + "structure used as a storage buffer must be declared with the " + "[[block]] decoration", + str->impl()->source()); + if (info->declaration->source().range.begin.line) { + diagnostics_.add_note("structure used as storage buffer here", + info->declaration->source()); + } + return false; + } + break; } + case ast::StorageClass::kUniform: { + // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables + // A variable in the uniform storage class is a uniform buffer variable. + // Its store type must be a host-shareable structure type with block + // attribute, satisfying the storage class constraints. + auto* str = info->type->As(); + if (!str) { + diagnostics_.add_error( + "variables declared in the storage class must be of a " + "structure type", + info->declaration->source()); + return false; + } + + if (!str->IsBlockDecorated()) { + diagnostics_.add_error( + "structure used as a uniform buffer must be declared with the " + "[[block]] decoration", + str->impl()->source()); + if (info->declaration->source().range.begin.line) { + diagnostics_.add_note("structure used as uniform buffer here", + info->declaration->source()); + } + return false; + } + break; + } + default: + break; } return ValidateVariable(info->declaration); diff --git a/src/resolver/storage_class_validation_test.cc b/src/resolver/storage_class_validation_test.cc index 931b23ab16..1ce3cbf5c0 100644 --- a/src/resolver/storage_class_validation_test.cc +++ b/src/resolver/storage_class_validation_test.cc @@ -138,6 +138,94 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) { ASSERT_TRUE(r()->Resolve()); } +/// + +TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) { + // var g : bool; + Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform); + + ASSERT_FALSE(r()->Resolve()); + + EXPECT_EQ( + r()->error(), + R"(56:78 error: variables declared in the storage class must be of a structure type)"); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) { + // var g : ptr; + Global(Source{{56, 78}}, "g", ty.pointer(ast::StorageClass::kInput), + ast::StorageClass::kUniform); + + ASSERT_FALSE(r()->Resolve()); + + EXPECT_EQ( + r()->error(), + R"(56:78 error: variables declared in the storage class must be of a structure type)"); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) { + // var g : [[access(read)]] array; + auto* s = Structure("S", {Member("a", ty.f32())}); + auto* a = ty.array(s, 3); + auto* ac = ty.access(ast::AccessControl::kReadOnly, a); + Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform); + + ASSERT_FALSE(r()->Resolve()); + + EXPECT_EQ( + r()->error(), + R"(56:78 error: variables declared in the storage class must be of a structure type)"); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) { + // type a = bool; + // var g : [[access(read)]] a; + auto* a = ty.alias("a", ty.bool_()); + Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform); + + ASSERT_FALSE(r()->Resolve()); + + EXPECT_EQ( + r()->error(), + R"(56:78 error: variables declared in the storage class must be of a structure type)"); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) { + // struct S { x : i32 }; + // var g : S; + auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())}); + Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform); + + ASSERT_FALSE(r()->Resolve()); + + EXPECT_EQ( + r()->error(), + R"(12:34 error: structure used as a uniform buffer must be declared with the [[block]] decoration +56:78 note: structure used as uniform buffer here)"); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) { + // [[block]] struct S { x : i32 }; + // var g : S; + auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, + {create()}); + Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform); + + ASSERT_TRUE(r()->Resolve()); +} + +TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) { + // [[block]] struct S { x : i32 }; + // type a1 = S; + // var g : a1; + auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, + {create()}); + auto* a1 = ty.alias("a1", s); + Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform); + + ASSERT_TRUE(r()->Resolve()); +} + } // namespace } // namespace resolver } // namespace tint diff --git a/src/resolver/struct_storage_class_use_test.cc b/src/resolver/struct_storage_class_use_test.cc index 475199277d..a34a835820 100644 --- a/src/resolver/struct_storage_class_use_test.cc +++ b/src/resolver/struct_storage_class_use_test.cc @@ -66,53 +66,53 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) { TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) { auto* s = Structure("S", {Member("a", ty.f32())}); - Global("g", s, ast::StorageClass::kUniform); + Global("g", s, ast::StorageClass::kPrivate); ASSERT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(s); ASSERT_NE(sem, nullptr); EXPECT_THAT(sem->StorageClassUsage(), - UnorderedElementsAre(ast::StorageClass::kUniform)); + UnorderedElementsAre(ast::StorageClass::kPrivate)); } TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) { auto* s = Structure("S", {Member("a", ty.f32())}); auto* a = ty.alias("A", s); - Global("g", a, ast::StorageClass::kUniform); + Global("g", a, ast::StorageClass::kPrivate); ASSERT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(s); ASSERT_NE(sem, nullptr); EXPECT_THAT(sem->StorageClassUsage(), - UnorderedElementsAre(ast::StorageClass::kUniform)); + UnorderedElementsAre(ast::StorageClass::kPrivate)); } TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) { auto* s = Structure("S", {Member("a", ty.f32())}); auto* o = Structure("O", {Member("a", s)}); - Global("g", o, ast::StorageClass::kUniform); + Global("g", o, ast::StorageClass::kPrivate); ASSERT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(s); ASSERT_NE(sem, nullptr); EXPECT_THAT(sem->StorageClassUsage(), - UnorderedElementsAre(ast::StorageClass::kUniform)); + UnorderedElementsAre(ast::StorageClass::kPrivate)); } TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) { auto* s = Structure("S", {Member("a", ty.f32())}); auto* a = ty.array(s, 3); - Global("g", a, ast::StorageClass::kUniform); + Global("g", a, ast::StorageClass::kPrivate); ASSERT_TRUE(r()->Resolve()) << r()->error(); auto* sem = Sem().Get(s); ASSERT_NE(sem, nullptr); EXPECT_THAT(sem->StorageClassUsage(), - UnorderedElementsAre(ast::StorageClass::kUniform)); + UnorderedElementsAre(ast::StorageClass::kPrivate)); } TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) { diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc index e3f733bc31..0c3cd2ac3d 100644 --- a/src/writer/hlsl/generator_impl_function_test.cc +++ b/src/writer/hlsl/generator_impl_function_test.cc @@ -31,10 +31,9 @@ using HlslGeneratorImplTest_Function = TestHelper; TEST_F(HlslGeneratorImplTest_Function, Emit_Function) { Func("my_func", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(), - }, - ast::DecorationList{}); + { + Return(), + }); GeneratorImpl& gen = Build(); @@ -50,10 +49,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function) { TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) { Func("GeometryShader", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(), - }, - ast::DecorationList{}); + { + Return(), + }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -68,10 +66,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) { TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) { Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(), - ast::StatementList{ - create(), - }, - ast::DecorationList{}); + { + Return(), + }); GeneratorImpl& gen = Build(); @@ -87,10 +84,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_NoReturn_Void) { - Func("main", ast::VariableList{}, ty.void_(), - ast::StatementList{/* no explicit return */}, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + Func("main", ast::VariableList{}, ty.void_(), {/* no explicit return */}, + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -111,9 +107,8 @@ TEST_F(HlslGeneratorImplTest_Function, // return foo; // } auto* foo_in = Param("foo", ty.f32(), {create(0)}); - Func("frag_main", ast::VariableList{foo_in}, ty.f32(), - {create(Expr("foo"))}, - {create(ast::PipelineStage::kFragment)}, + Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return(Expr("foo"))}, + {Stage(ast::PipelineStage::kFragment)}, {create(1)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -146,8 +141,8 @@ TEST_F(HlslGeneratorImplTest_Function, Param("coord", ty.vec4(), {create(ast::Builtin::kPosition)}); Func("frag_main", ast::VariableList{coord_in}, ty.f32(), - {create(MemberAccessor("coord", "x"))}, - {create(ast::PipelineStage::kFragment)}, + {Return(MemberAccessor("coord", "x"))}, + {Stage(ast::PipelineStage::kFragment)}, {create(ast::Builtin::kFragDepth)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -201,14 +196,12 @@ TEST_F(HlslGeneratorImplTest_Function, Func("frag_main", {Param("inputs", interface_struct)}, ty.void_(), { - WrapInStatement( - Const("r", ty.f32(), MemberAccessor(Expr("inputs"), "col1"))), - WrapInStatement( - Const("g", ty.f32(), MemberAccessor(Expr("inputs"), "col2"))), - WrapInStatement(Const("p", ty.vec4(), - MemberAccessor(Expr("inputs"), "pos"))), + Decl(Const("r", ty.f32(), MemberAccessor(Expr("inputs"), "col1"))), + Decl(Const("g", ty.f32(), MemberAccessor(Expr("inputs"), "col2"))), + Decl(Const("p", ty.vec4(), + MemberAccessor(Expr("inputs"), "pos"))), }, - {create(ast::PipelineStage::kFragment)}); + {Stage(ast::PipelineStage::kFragment)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -268,20 +261,19 @@ TEST_F(HlslGeneratorImplTest_Function, {create(ast::Builtin::kPosition)})}); Func("foo", {Param("x", ty.f32())}, vertex_output_struct, - {create(Construct( - vertex_output_struct, Construct(ty.vec4(), Expr("x"), Expr("x"), - Expr("x"), Expr(1.f))))}, + {Return(Construct(vertex_output_struct, + Construct(ty.vec4(), Expr("x"), Expr("x"), + Expr("x"), Expr(1.f))))}, {}); Func("vert_main1", {}, vertex_output_struct, - {create( - Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))}, - {create(ast::PipelineStage::kVertex)}); + {Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))}, + {Stage(ast::PipelineStage::kVertex)}); - Func("vert_main2", {}, vertex_output_struct, - {create( - Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))}, - {create(ast::PipelineStage::kVertex)}); + Func( + "vert_main2", {}, vertex_output_struct, + {Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))}, + {Stage(ast::PipelineStage::kVertex)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -320,33 +312,48 @@ tint_symbol_2 vert_main2() { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_With_Uniform) { - Global("coord", ty.vec4(), ast::StorageClass::kUniform, nullptr, - ast::DecorationList{ - create(0), - create(1), - }); + auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4())}, + {create()}); + auto* ubo = Global( + "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr, + {create(0), create(1)}); - auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, - MemberAccessor("coord", "x")); - - Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(var), - create(), + Func("sub_func", + { + Param("param", ty.f32()), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + ty.f32(), + { + Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")), + }); + + auto* var = + Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); + + Func("frag_main", {}, ty.void_(), + { + Decl(var), + Return(), + }, + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); ASSERT_TRUE(gen.Generate(out)) << gen.error(); - EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0, space1) { + EXPECT_EQ(result(), R"(struct UBO { float4 coord; }; +ConstantBuffer ubo : register(b0, space1); + +float sub_func(float param) { + return ubo.coord.x; +} + void frag_main() { - float v = coord.x; + float v = sub_func(1.0f); return; } @@ -357,10 +364,11 @@ void frag_main() { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_With_UniformStruct) { - auto* s = Structure("Uniforms", {Member("coord", ty.vec4())}); + auto* s = Structure("Uniforms", {Member("coord", ty.vec4())}, + {create()}); Global("uniforms", s, ast::StorageClass::kUniform, nullptr, - ast::DecorationList{ + { create(0), create(1), }); @@ -370,12 +378,12 @@ TEST_F(HlslGeneratorImplTest_Function, MemberAccessor("uniforms", "coord"), Expr("x"))); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -409,7 +417,7 @@ TEST_F(HlslGeneratorImplTest_Function, sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(1), }); @@ -418,12 +426,12 @@ TEST_F(HlslGeneratorImplTest_Function, MemberAccessor("coord", "b")); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -455,7 +463,7 @@ TEST_F(HlslGeneratorImplTest_Function, sem::AccessControl ac(ast::AccessControl::kReadOnly, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(1), }); @@ -464,12 +472,12 @@ TEST_F(HlslGeneratorImplTest_Function, MemberAccessor("coord", "b")); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -501,19 +509,19 @@ TEST_F(HlslGeneratorImplTest_Function, sem::AccessControl ac(ast::AccessControl::kWriteOnly, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(1), }); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(MemberAccessor("coord", "b"), Expr(2.0f)), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -545,19 +553,19 @@ TEST_F(HlslGeneratorImplTest_Function, sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(1), }); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(MemberAccessor("coord", "b"), Expr(2.0f)), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -582,36 +590,35 @@ TEST_F( HlslGeneratorImplTest_Function, Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) { // NOLINT Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr, - ast::DecorationList{ + { create(0), }); Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ + { create(1), }); Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ + { create(0), }); Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(), - ast::StatementList{ + { create(Expr("bar"), Expr("foo")), create(Expr("val"), Expr("param")), - create(Expr("foo")), - }, - ast::DecorationList{}); + Return(Expr("foo")), + }); Func( "ep_1", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(Expr("bar"), Call("sub_func", 1.0f)), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -646,24 +653,23 @@ ep_1_out ep_1(ep_1_in tint_in) { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) { Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ + { create(ast::Builtin::kFragDepth), }); Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(), - ast::StatementList{ - create(Expr("param")), - }, - ast::DecorationList{}); + { + Return(Expr("param")), + }); Func("ep_1", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(Expr("depth"), Call("sub_func", 1.0f)), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -693,31 +699,30 @@ TEST_F( HlslGeneratorImplTest_Function, Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) { // NOLINT Global("coord", ty.vec4(), ast::StorageClass::kInput, nullptr, - ast::DecorationList{ + { create(ast::Builtin::kPosition), }); Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ + { create(ast::Builtin::kFragDepth), }); Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(), - ast::StatementList{ + { create(Expr("depth"), MemberAccessor("coord", "x")), - create(Expr("param")), - }, - ast::DecorationList{}); + Return(Expr("param")), + }); Func("ep_1", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(Expr("depth"), Call("sub_func", 1.0f)), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -749,37 +754,40 @@ ep_1_out ep_1(ep_1_in tint_in) { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_Called_By_EntryPoint_With_Uniform) { - Global("coord", ty.vec4(), ast::StorageClass::kUniform, nullptr, - ast::DecorationList{ + auto* s = Structure("S", {Member("x", ty.f32())}, + {create()}); + Global("coord", s, ast::StorageClass::kUniform, nullptr, + { create(0), create(1), }); Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(), - ast::StatementList{ - create(MemberAccessor("coord", "x")), - }, - ast::DecorationList{}); + { + Return(MemberAccessor("coord", "x")), + }); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); ASSERT_TRUE(gen.Generate(out)) << gen.error(); - EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0, space1) { - float4 coord; + EXPECT_EQ(result(), R"(struct S { + float x; }; +ConstantBuffer coord : register(b0, space1); + float sub_func(float param) { return coord.x; } @@ -800,27 +808,26 @@ TEST_F(HlslGeneratorImplTest_Function, {create()}); auto* ac = ty.access(ast::AccessControl::kReadWrite, s); Global("coord", ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(1), }); Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(), - ast::StatementList{ - create(MemberAccessor("coord", "x")), - }, - ast::DecorationList{}); + { + Return(MemberAccessor("coord", "x")), + }); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -847,25 +854,21 @@ void frag_main() { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) { Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ + { create(1), }); - auto* list = create(ast::StatementList{ - create(), - }); - Func( "ep_1", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(Expr("bar"), Expr(1.0f)), create(create( ast::BinaryOp::kEqual, Expr(1), Expr(1)), - list, ast::ElseStatementList{}), - create(), + Block(Return()), ast::ElseStatementList{}), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -891,9 +894,9 @@ ep_1_out ep_1() { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_WithNameCollision) { - Func("GeometryShader", ast::VariableList{}, ty.void_(), ast::StatementList{}, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + Func("GeometryShader", ast::VariableList{}, ty.void_(), {}, + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = SanitizeAndBuild(); @@ -908,11 +911,11 @@ TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_Compute) { Func("main", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(), + { + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kCompute), + { + Stage(ast::PipelineStage::kCompute), }); GeneratorImpl& gen = Build(); @@ -931,11 +934,11 @@ void main() { TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_Compute_WithWorkgroup) { Func("main", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(), + { + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kCompute), + { + Stage(ast::PipelineStage::kCompute), create(2u, 4u, 6u), }); @@ -954,8 +957,8 @@ void main() { TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) { Func("my_func", ast::VariableList{Param("a", ty.array())}, ty.void_(), - ast::StatementList{ - create(), + { + Return(), }); GeneratorImpl& gen = Build(); @@ -990,14 +993,13 @@ TEST_F(HlslGeneratorImplTest_Function, // return; // } - auto* s = - Structure("Data", {Member("d", ty.f32())}, - ast::DecorationList{create()}); + auto* s = Structure("Data", {Member("d", ty.f32())}, + {create()}); sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("data", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{ + { create(0), create(0), }); @@ -1007,12 +1009,12 @@ TEST_F(HlslGeneratorImplTest_Function, MemberAccessor("data", "d")); Func("a", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kCompute), + { + Stage(ast::PipelineStage::kCompute), }); } @@ -1021,12 +1023,12 @@ TEST_F(HlslGeneratorImplTest_Function, MemberAccessor("data", "d")); Func("b", ast::VariableList{}, ty.void_(), - ast::StatementList{ + { create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kCompute), + { + Stage(ast::PipelineStage::kCompute), }); } diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc index 473d3216e9..e5c70a5f13 100644 --- a/src/writer/msl/generator_impl_function_test.cc +++ b/src/writer/msl/generator_impl_function_test.cc @@ -28,9 +28,9 @@ using MslGeneratorImplTest = TestHelper; TEST_F(MslGeneratorImplTest, Emit_Function) { Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{ - create(), + Return(), }, - ast::DecorationList{}); + {}); GeneratorImpl& gen = Build(); @@ -54,9 +54,9 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithParams) { Func("my_func", params, ty.void_(), ast::StatementList{ - create(), + Return(), }, - ast::DecorationList{}); + {}); GeneratorImpl& gen = Build(); @@ -76,8 +76,7 @@ using namespace metal; TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_NoReturn_Void) { Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{/* no explicit return */}, - ast::DecorationList{ - create(ast::PipelineStage::kFragment)}); + {Stage(ast::PipelineStage::kFragment)}); GeneratorImpl& gen = Build(); @@ -97,9 +96,8 @@ TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_WithInOutVars) { // return foo; // } auto* foo_in = Param("foo", ty.f32(), {create(0)}); - Func("frag_main", ast::VariableList{foo_in}, ty.f32(), - {create(Expr("foo"))}, - {create(ast::PipelineStage::kFragment)}, + Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return(Expr("foo"))}, + {Stage(ast::PipelineStage::kFragment)}, {create(1)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -133,8 +131,8 @@ TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_WithInOut_Builtins) { Param("coord", ty.vec4(), {create(ast::Builtin::kPosition)}); Func("frag_main", ast::VariableList{coord_in}, ty.f32(), - {create(MemberAccessor("coord", "x"))}, - {create(ast::PipelineStage::kFragment)}, + {Return(MemberAccessor("coord", "x"))}, + {Stage(ast::PipelineStage::kFragment)}, {create(ast::Builtin::kFragDepth)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -194,7 +192,7 @@ TEST_F(MslGeneratorImplTest, WrapInStatement( Const("g", ty.f32(), MemberAccessor(Expr("colors"), "col2"))), }, - {create(ast::PipelineStage::kFragment)}); + {Stage(ast::PipelineStage::kFragment)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -255,20 +253,19 @@ TEST_F(MslGeneratorImplTest, {create(ast::Builtin::kPosition)})}); Func("foo", {Param("x", ty.f32())}, vertex_output_struct, - {create(Construct( - vertex_output_struct, Construct(ty.vec4(), Expr("x"), Expr("x"), - Expr("x"), Expr(1.f))))}, + {Return(Construct(vertex_output_struct, + Construct(ty.vec4(), Expr("x"), Expr("x"), + Expr("x"), Expr(1.f))))}, {}); Func("vert_main1", {}, vertex_output_struct, - {create( - Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))}, - {create(ast::PipelineStage::kVertex)}); + {Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))}, + {Stage(ast::PipelineStage::kVertex)}); - Func("vert_main2", {}, vertex_output_struct, - {create( - Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))}, - {create(ast::PipelineStage::kVertex)}); + Func( + "vert_main2", {}, vertex_output_struct, + {Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))}, + {Stage(ast::PipelineStage::kVertex)}); GeneratorImpl& gen = SanitizeAndBuild(); @@ -317,8 +314,7 @@ TEST_F(MslGeneratorImplTest, sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{create(0), - create(1)}); + {create(0), create(1)}); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, MemberAccessor("coord", "b")); @@ -326,10 +322,10 @@ TEST_F(MslGeneratorImplTest, Func("frag_main", ast::VariableList{}, ty.void_(), ast::StatementList{ create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -363,8 +359,7 @@ TEST_F(MslGeneratorImplTest, sem::AccessControl ac(ast::AccessControl::kReadOnly, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{create(0), - create(1)}); + {create(0), create(1)}); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, MemberAccessor("coord", "b")); @@ -372,10 +367,10 @@ TEST_F(MslGeneratorImplTest, Func("frag_main", ast::VariableList{}, ty.void_(), ast::StatementList{ create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -402,13 +397,13 @@ TEST_F( MslGeneratorImplTest, Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) { // NOLINT Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr, - ast::DecorationList{create(0)}); + {create(0)}); Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{create(1)}); + {create(1)}); Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{create(0)}); + {create(0)}); ast::VariableList params; params.push_back(Param("param", ty.f32())); @@ -416,18 +411,18 @@ TEST_F( auto body = ast::StatementList{ create(Expr("bar"), Expr("foo")), create(Expr("val"), Expr("param")), - create(Expr("foo"))}; + Return(Expr("foo"))}; - Func("sub_func", params, ty.f32(), body, ast::DecorationList{}); + Func("sub_func", params, ty.f32(), body, {}); body = ast::StatementList{ create(Expr("bar"), Call("sub_func", 1.0f)), - create(), + Return(), }; Func("ep_1", ast::VariableList{}, ty.void_(), body, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -464,26 +459,25 @@ fragment ep_1_out ep_1(ep_1_in _tint_in [[stage_in]]) { TEST_F(MslGeneratorImplTest, Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) { Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ - create(ast::Builtin::kFragDepth)}); + {create(ast::Builtin::kFragDepth)}); ast::VariableList params; params.push_back(Param("param", ty.f32())); Func("sub_func", params, ty.f32(), ast::StatementList{ - create(Expr("param")), + Return(Expr("param")), }, - ast::DecorationList{}); + {}); auto body = ast::StatementList{ create(Expr("depth"), Call("sub_func", 1.0f)), - create(), + Return(), }; Func("ep_1", ast::VariableList{}, ty.void_(), body, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -514,12 +508,10 @@ TEST_F( MslGeneratorImplTest, Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) { // NOLINT Global("coord", ty.vec4(), ast::StorageClass::kInput, nullptr, - ast::DecorationList{ - create(ast::Builtin::kPosition)}); + {create(ast::Builtin::kPosition)}); Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ - create(ast::Builtin::kFragDepth)}); + {create(ast::Builtin::kFragDepth)}); ast::VariableList params; params.push_back(Param("param", ty.f32())); @@ -527,19 +519,19 @@ TEST_F( auto body = ast::StatementList{ create(Expr("depth"), MemberAccessor("coord", "x")), - create(Expr("param")), + Return(Expr("param")), }; - Func("sub_func", params, ty.f32(), body, ast::DecorationList{}); + Func("sub_func", params, ty.f32(), body, {}); body = ast::StatementList{ create(Expr("depth"), Call("sub_func", 1.0f)), - create(), + Return(), }; Func("ep_1", ast::VariableList{}, ty.void_(), body, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -568,29 +560,31 @@ fragment ep_1_out ep_1(float4 coord [[position]]) { TEST_F(MslGeneratorImplTest, Emit_Decoration_Called_By_EntryPoint_With_Uniform) { - Global("coord", ty.vec4(), ast::StorageClass::kUniform, nullptr, - ast::DecorationList{create(0), - create(1)}); + auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4())}, + {create()}); + auto* ubo = Global( + "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr, + {create(0), create(1)}); - ast::VariableList params; - params.push_back(Param("param", ty.f32())); - - auto body = ast::StatementList{ - create(MemberAccessor("coord", "x")), - }; - - Func("sub_func", params, ty.f32(), body, ast::DecorationList{}); + Func("sub_func", + { + Param("param", ty.f32()), + }, + ty.f32(), + { + Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")), + }); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); - Func("frag_main", ast::VariableList{}, ty.void_(), - ast::StatementList{ - create(var), - create(), + Func("frag_main", {}, ty.void_(), + { + Decl(var), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -599,12 +593,16 @@ TEST_F(MslGeneratorImplTest, EXPECT_EQ(gen.result(), R"(#include using namespace metal; -float sub_func(constant float4& coord, float param) { - return coord.x; +struct UBO { + /* 0x0000 */ packed_float4 coord; +}; + +float sub_func(constant UBO& ubo, float param) { + return ubo.coord.x; } -fragment void frag_main(constant float4& coord [[buffer(0)]]) { - float v = sub_func(coord, 1.0f); +fragment void frag_main(constant UBO& ubo [[buffer(0)]]) { + float v = sub_func(ubo, 1.0f); return; } @@ -623,16 +621,14 @@ TEST_F(MslGeneratorImplTest, sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{create(0), - create(1)}); + {create(0), create(1)}); ast::VariableList params; params.push_back(Param("param", ty.f32())); - auto body = ast::StatementList{ - create(MemberAccessor("coord", "b"))}; + auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))}; - Func("sub_func", params, ty.f32(), body, ast::DecorationList{}); + Func("sub_func", params, ty.f32(), body, {}); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); @@ -640,10 +636,10 @@ TEST_F(MslGeneratorImplTest, Func("frag_main", ast::VariableList{}, ty.void_(), ast::StatementList{ create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -681,16 +677,14 @@ TEST_F(MslGeneratorImplTest, sem::AccessControl ac(ast::AccessControl::kReadOnly, s); Global("coord", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{create(0), - create(1)}); + {create(0), create(1)}); ast::VariableList params; params.push_back(Param("param", ty.f32())); - auto body = ast::StatementList{ - create(MemberAccessor("coord", "b"))}; + auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))}; - Func("sub_func", params, ty.f32(), body, ast::DecorationList{}); + Func("sub_func", params, ty.f32(), body, {}); auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f)); @@ -698,10 +692,10 @@ TEST_F(MslGeneratorImplTest, Func("frag_main", ast::VariableList{}, ty.void_(), ast::StatementList{ create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -731,10 +725,10 @@ fragment void frag_main(const device Data& coord [[buffer(0)]]) { TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) { Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{create(1)}); + {create(1)}); auto* list = create(ast::StatementList{ - create(), + Return(), }); auto body = ast::StatementList{ @@ -742,12 +736,12 @@ TEST_F(MslGeneratorImplTest, create(create( ast::BinaryOp::kEqual, Expr(1), Expr(1)), list, ast::ElseStatementList{}), - create(), + Return(), }; Func("ep_1", ast::VariableList{}, ty.void_(), body, - ast::DecorationList{ - create(ast::PipelineStage::kFragment), + { + Stage(ast::PipelineStage::kFragment), }); GeneratorImpl& gen = Build(); @@ -778,9 +772,9 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) { Func("my_func", params, ty.void_(), ast::StatementList{ - create(), + Return(), }, - ast::DecorationList{}); + {}); GeneratorImpl& gen = Build(); @@ -821,8 +815,7 @@ TEST_F(MslGeneratorImplTest, sem::AccessControl ac(ast::AccessControl::kReadWrite, s); Global("data", &ac, ast::StorageClass::kStorage, nullptr, - ast::DecorationList{create(0), - create(0)}); + {create(0), create(0)}); { auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction, @@ -831,10 +824,10 @@ TEST_F(MslGeneratorImplTest, Func("a", ast::VariableList{}, ty.void_(), ast::StatementList{ create(var), - create(), + Return(), }, - ast::DecorationList{ - create(ast::PipelineStage::kCompute), + { + Stage(ast::PipelineStage::kCompute), }); } @@ -843,10 +836,8 @@ TEST_F(MslGeneratorImplTest, MemberAccessor("data", "d")); Func("b", ast::VariableList{}, ty.void_(), - ast::StatementList{create(var), - create()}, - ast::DecorationList{ - create(ast::PipelineStage::kCompute)}); + ast::StatementList{create(var), Return()}, + {Stage(ast::PipelineStage::kCompute)}); } GeneratorImpl& gen = Build(); diff --git a/test/compute_boids.wgsl b/test/compute_boids.wgsl index 2f168dc121..7570102ee6 100644 --- a/test/compute_boids.wgsl +++ b/test/compute_boids.wgsl @@ -53,7 +53,7 @@ struct Particle { particles : array; }; -[[binding(0), group(0)]] var params : [[access(read)]] SimParams; +[[binding(0), group(0)]] var params : SimParams; [[binding(1), group(0)]] var particlesA : [[access(read_write)]] Particles; [[binding(2), group(0)]] var particlesB : [[access(read_write)]] Particles; diff --git a/test/cube.wgsl b/test/cube.wgsl index 313954a206..6eefd59083 100644 --- a/test/cube.wgsl +++ b/test/cube.wgsl @@ -17,7 +17,7 @@ modelViewProjectionMatrix : mat4x4; }; -[[binding(0), group(0)]] var uniforms : [[access(read)]] Uniforms; +[[binding(0), group(0)]] var uniforms : Uniforms; struct VertexInput { [[location(0)]] cur_position : vec4;