From e9d7f7e640de2f9953f322472f5b480442702507 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 6 Jan 2021 12:57:41 +0000 Subject: [PATCH] src/transform: Reimplement tests in WGSL Easier to read and write, and ensures that the tests exercise valid AST instead of synthetic structures that can never exist. Change-Id: I5d361ef96383c71943a424f5765952f21d740042 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/36422 Reviewed-by: dan sinclair Commit-Queue: Ben Clayton Auto-Submit: Ben Clayton --- BUILD.gn | 1 + src/CMakeLists.txt | 14 +- src/transform/bound_array_accessors_test.cc | 1028 ++++----------- src/transform/emit_vertex_point_size_test.cc | 249 ++-- src/transform/first_index_offset_test.cc | 526 +++----- src/transform/test_helper.h | 115 ++ src/transform/vertex_pulling_test.cc | 1203 ++++-------------- 7 files changed, 907 insertions(+), 2229 deletions(-) create mode 100644 src/transform/test_helper.h diff --git a/BUILD.gn b/BUILD.gn index 01684a9472..547b74a401 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -831,6 +831,7 @@ source_set("tint_unittests_core_src") { "src/transform/bound_array_accessors_test.cc", "src/transform/emit_vertex_point_size_test.cc", "src/transform/first_index_offset_test.cc", + "src/transform/test_helper.h", "src/transform/vertex_pulling_test.cc", "src/type_determiner_test.cc", "src/validator/validator_control_block_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a7c6a452b..adc89aff10 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -465,10 +465,6 @@ if(${TINT_BUILD_TESTS}) scope_stack_test.cc symbol_table_test.cc symbol_test.cc - transform/emit_vertex_point_size_test.cc - transform/bound_array_accessors_test.cc - transform/first_index_offset_test.cc - transform/vertex_pulling_test.cc type_determiner_test.cc validator/validator_control_block_test.cc validator/validator_function_test.cc @@ -656,6 +652,16 @@ if(${TINT_BUILD_TESTS}) ) endif() + if(${TINT_BUILD_WGSL_READER} AND ${TINT_BUILD_WGSL_WRITER}) + list(APPEND TINT_TEST_SRCS + transform/bound_array_accessors_test.cc + transform/emit_vertex_point_size_test.cc + transform/first_index_offset_test.cc + transform/test_helper.h + transform/vertex_pulling_test.cc + ) + endif() + if(${TINT_BUILD_MSL_WRITER}) list(APPEND TINT_TEST_SRCS writer/msl/generator_impl_alias_type_test.cc diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc index a3c148f5c9..e7d70ceff0 100644 --- a/src/transform/bound_array_accessors_test.cc +++ b/src/transform/bound_array_accessors_test.cc @@ -14,918 +14,400 @@ #include "src/transform/bound_array_accessors.h" -#include -#include - -#include "gtest/gtest.h" -#include "src/ast/array_accessor_expression.h" -#include "src/ast/binary_expression.h" -#include "src/ast/block_statement.h" -#include "src/ast/builder.h" -#include "src/ast/call_expression.h" -#include "src/ast/function.h" -#include "src/ast/identifier_expression.h" -#include "src/ast/module.h" -#include "src/ast/scalar_constructor_expression.h" -#include "src/ast/sint_literal.h" -#include "src/ast/storage_class.h" -#include "src/ast/type/array_type.h" -#include "src/ast/type/f32_type.h" -#include "src/ast/type/i32_type.h" -#include "src/ast/type/matrix_type.h" -#include "src/ast/type/pointer_type.h" -#include "src/ast/type/u32_type.h" -#include "src/ast/type/vector_type.h" -#include "src/ast/type/void_type.h" -#include "src/ast/type_constructor_expression.h" -#include "src/ast/uint_literal.h" -#include "src/ast/variable.h" -#include "src/ast/variable_decl_statement.h" -#include "src/diagnostic/formatter.h" -#include "src/transform/manager.h" -#include "src/type_determiner.h" +#include "src/transform/test_helper.h" namespace tint { namespace transform { namespace { -template -T* FindVariable(ast::Module* mod, std::string name) { - if (auto* func = mod->FindFunctionBySymbol(mod->RegisterSymbol("func"))) { - for (auto* stmt : *func->body()) { - if (auto* decl = stmt->As()) { - if (auto* var = decl->variable()) { - if (var->name() == name) { - return As(var->constructor()); - } - } - } - } - } - return nullptr; -} - -class BoundArrayAccessorsTest : public testing::Test { - public: - ast::Module Transform(ast::Module in) { - TypeDeterminer td(&in); - if (!td.Determine()) { - error = "Type determination failed: " + td.error(); - return {}; - } - - Manager manager; - manager.append(std::make_unique()); - auto result = manager.Run(&in); - - if (result.diagnostics.contains_errors()) { - error = "manager().Run() errored:\n" + - diag::Formatter().format(result.diagnostics); - return {}; - } - - return std::move(result.module); - } - - std::string error; -}; - -struct ModuleBuilder : public ast::BuilderWithModule { - ast::Module Module() { - Build(); - mod->AddFunction(Func("func", ast::VariableList{}, ty.void_, statements, - ast::FunctionDecorationList{})); - return std::move(*mod); - } - - protected: - virtual void Build() = 0; - void OnVariableBuilt(ast::Variable* var) override { - statements.emplace_back(create(var)); - } - ast::StatementList statements; -}; +using BoundArrayAccessorsTest = TransformTest; TEST_F(BoundArrayAccessorsTest, Ptrs_Clamp) { - // var a : array; - // const c : u32 = 1; - // const b : ptr = a[c] - // - // -> const b : ptr = a[min(u32(c), 2)] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array()); - Const("c", ast::StorageClass::kFunction, ty.u32); - Const("b", ast::StorageClass::kFunction, - ty.pointer(ast::StorageClass::kFunction), - IndexAccessor("a", "c"), {}); - } - }; + auto* src = R"( +var a : array; +const c : u32 = 1u; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + const b : ptr = a[c]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : array; +const c : u32 = 1u; - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + const b : ptr = a[min(u32(c), 2u)]; +} +)"; - auto* idx = b->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); + auto got = Transform(src); - ASSERT_EQ(idx->params().size(), 2u); - - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - ASSERT_TRUE(tc->values()[0]->Is()); - ASSERT_EQ(tc->values()[0]->As()->name(), "c"); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - auto* scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Array_Idx_Nested_Scalar) { - // var a : array; - // var b : array; - // var i : u32; - // var c : f32 = a[b[i]]; - // - // -> var c : f32 = a[min(u32(b[min(u32(i), 4)]), 2)]; - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array()); - Var("b", ast::StorageClass::kFunction, ty.array()); - Var("i", ast::StorageClass::kFunction, ty.u32); - Const("c", ast::StorageClass::kFunction, ty.f32, - IndexAccessor("a", IndexAccessor("b", "i")), {}); - } - }; + auto* src = R"( +var a : array; +var b : array; +var i : u32; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var c : f32 = a[ b[i] ]; +} +)"; - auto* c = FindVariable(&module, "c"); - ASSERT_NE(c, nullptr); + auto* expect = R"( +var a : array; +var b : array; +var i : u32; - ASSERT_TRUE(c->Is()); - ASSERT_TRUE(c->idx_expr()->Is()); +fn f() -> void { + var c : f32 = a[min(u32(b[min(u32(i), 4u)]), 2u)]; +} +)"; - auto* idx = c->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); + auto got = Transform(src); - ASSERT_EQ(idx->params().size(), 2u); - - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - - auto* sub = tc->values()[0]; - ASSERT_TRUE(sub->Is()); - ASSERT_TRUE(sub->As() - ->idx_expr() - ->Is()); - - auto* sub_idx = sub->As() - ->idx_expr() - ->As(); - ASSERT_TRUE(sub_idx->func()->Is()); - EXPECT_EQ(sub_idx->func()->As()->name(), "min"); - - ASSERT_TRUE(sub_idx->params()[0]->Is()); - ASSERT_TRUE(sub_idx->params()[0]->Is()); - tc = sub_idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - ASSERT_TRUE(tc->values()[0]->Is()); - ASSERT_EQ(tc->values()[0]->As()->name(), "i"); - - ASSERT_TRUE(sub_idx->params()[1]->Is()); - ASSERT_TRUE(sub_idx->params()[1]->Is()); - auto* scalar = sub_idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 4u); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(c->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(c->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Array_Idx_Scalar) { - // var a : array - // var b : f32 = a[1]; - // - // -> var b : f32 = a[1]; - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array(ty.f32, 3)); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 1u), - {}); - } - }; + auto* src = R"( +var a : array; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : array; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[1]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Array_Idx_Expr) { - // var a : array - // var c : u32; - // var b : f32 = a[c + 2 - 3] - // - // -> var b : f32 = a[min(u32(c + 2 - 3), 2)] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array()); - Var("c", ast::StorageClass::kFunction, ty.u32); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor("a", Add("c", Sub(2u, 3u))), {}); - } - }; + auto* src = R"( +var a : array; +var c : u32; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[c + 2 - 3]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : array; +var c : u32; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[min(u32(((c + 2) - 3)), 2u)]; +} +)"; - auto* idx = b->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); + auto got = Transform(src); - ASSERT_EQ(idx->params().size(), 2u); - - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - auto* add = tc->values()[0]->As(); - ASSERT_NE(add, nullptr); - ASSERT_EQ(add->op(), ast::BinaryOp::kAdd); - auto* add_lhs = add->lhs()->As(); - ASSERT_NE(add_lhs, nullptr); - ASSERT_EQ(add_lhs->name(), "c"); - auto* add_rhs = add->rhs()->As(); - ASSERT_NE(add_rhs, nullptr); - ASSERT_TRUE(add_rhs->lhs()->Is()); - ASSERT_EQ(add_rhs->lhs() - ->As() - ->literal() - ->As() - ->value(), - 2u); - ASSERT_TRUE(add_rhs->rhs()->Is()); - ASSERT_EQ(add_rhs->rhs() - ->As() - ->literal() - ->As() - ->value(), - 3u); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - auto* scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Array_Idx_Negative) { - // var a : array - // var b : f32 = a[-1] - // - // -> var b : f32 = a[0] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array()); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", -1), - {}); - } - }; + auto* src = R"( +var a : array; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[-1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : array; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[0]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 0); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Array_Idx_OutOfBounds) { - // var a : array - // var b : f32 = a[3] - // - // -> var b : f32 = a[2] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.array()); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 3u), - {}); - } - }; + auto* src = R"( +var a : array; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[3]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : array; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[2]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Vector_Idx_Scalar) { - // var a : vec3 - // var b : f32 = a[1]; - // - // -> var b : f32 = a[1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.vec3()); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 1u), - {}); - } - }; + auto* src = R"( +var a : vec3; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : vec3; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[1]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Vector_Idx_Expr) { - // var a : vec3 - // var c : u32; - // var b : f32 = a[c + 2 - 3] - // - // -> var b : f32 = a[min(u32(c + 2 - 3), 2)] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.vec3()); - Var("c", ast::StorageClass::kFunction, ty.u32); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor("a", Add("c", Sub(2u, 3u))), {}); - } - }; + auto* src = R"( +var a : vec3; +var c : u32; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[c + 2 - 3]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : vec3; +var c : u32; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[min(u32(((c + 2) - 3)), 2u)]; +} +)"; - auto* idx = b->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); + auto got = Transform(src); - ASSERT_EQ(idx->params().size(), 2u); - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - auto* add = tc->values()[0]->As(); - ASSERT_NE(add, nullptr); - auto* add_lhs = add->lhs()->As(); - ASSERT_NE(add_lhs, nullptr); - ASSERT_EQ(add_lhs->name(), "c"); - auto* add_rhs = add->rhs()->As(); - ASSERT_NE(add_rhs, nullptr); - ASSERT_TRUE(add_rhs->lhs()->Is()); - ASSERT_EQ(add_rhs->lhs() - ->As() - ->literal() - ->As() - ->value(), - 2u); - ASSERT_TRUE(add_rhs->rhs()->Is()); - ASSERT_EQ(add_rhs->rhs() - ->As() - ->literal() - ->As() - ->value(), - 3u); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - auto* scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Vector_Idx_Negative) { - // var a : vec3 - // var b : f32 = a[-1] - // - // -> var b : f32 = a[0] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.vec3()); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", -1), - {}); - } - }; + auto* src = R"( +var a : vec3; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[-1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : vec3; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[0]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 0); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Vector_Idx_OutOfBounds) { - // var a : vec3 - // var b : f32 = a[3] - // - // -> var b : f32 = a[2] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.vec3()); - Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 3u), - {}); - } - }; + auto* src = R"( +var a : vec3; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[3]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : vec3; - ASSERT_TRUE(b->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); +fn f() -> void { + var b : f32 = a[2]; +} +)"; - auto* scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); + auto got = Transform(src); - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Scalar) { - // var a : mat3x2 - // var b : f32 = a[2][1]; - // - // -> var b : f32 = a[2][1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", 2u), 1u), {}); - } - }; + auto* src = R"( +var a : mat3x2; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[2][1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[2][1]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); + auto got = Transform(src); - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Expr_Column) { - // var a : mat3x2 - // var c : u32; - // var b : f32 = a[c + 2 - 3][1] - // - // -> var b : f32 = a[min(u32(c + 2 - 3), 2)][1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("c", ast::StorageClass::kFunction, ty.u32); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", Add("c", Sub(2u, 3u))), 1u), {}); - } - }; + auto* src = R"( +var a : mat3x2; +var c : u32; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[c + 2 - 3][1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; +var c : u32; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); + auto got = Transform(src); - ASSERT_TRUE(ary->idx_expr()->Is()); - auto* idx = ary->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); - - ASSERT_EQ(idx->params().size(), 2u); - - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - auto* add = tc->values()[0]->As(); - ASSERT_NE(add, nullptr); - auto* add_lhs = add->lhs()->As(); - ASSERT_NE(add_lhs, nullptr); - ASSERT_EQ(add_lhs->name(), "c"); - auto* add_rhs = add->rhs()->As(); - ASSERT_NE(add_rhs, nullptr); - ASSERT_TRUE(add_rhs->lhs()->Is()); - ASSERT_EQ(add_rhs->lhs() - ->As() - ->literal() - ->As() - ->value(), - 2u); - ASSERT_TRUE(add_rhs->rhs()->Is()); - ASSERT_EQ(add_rhs->rhs() - ->As() - ->literal() - ->As() - ->value(), - 3u); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - auto* scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Expr_Row) { - // var a : mat3x2 - // var c : u32; - // var b : f32 = a[1][c + 2 - 3] - // - // -> var b : f32 = a[1][min(u32(c + 2 - 3), 1)] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("c", ast::StorageClass::kFunction, ty.u32); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", 1u), Add("c", Sub(2u, 3u))), {}); - } - }; + auto* src = R"( +var a : mat3x2; +var c : u32; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[1][c + 2 - 3]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; +var c : u32; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); + auto got = Transform(src); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); - - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_TRUE(b->idx_expr()->Is()); - auto* idx = b->idx_expr()->As(); - ASSERT_TRUE(idx->func()->Is()); - EXPECT_EQ(idx->func()->As()->name(), "min"); - - ASSERT_EQ(idx->params().size(), 2u); - - ASSERT_TRUE(idx->params()[0]->Is()); - ASSERT_TRUE(idx->params()[0]->Is()); - auto* tc = idx->params()[0]->As(); - EXPECT_TRUE(tc->type()->Is()); - ASSERT_EQ(tc->values().size(), 1u); - auto* add = tc->values()[0]->As(); - ASSERT_NE(add, nullptr); - auto* add_lhs = add->lhs()->As(); - ASSERT_NE(add_lhs, nullptr); - ASSERT_EQ(add_lhs->name(), "c"); - auto* add_rhs = add->rhs()->As(); - ASSERT_NE(add_rhs, nullptr); - ASSERT_TRUE(add_rhs->lhs()->Is()); - ASSERT_EQ(add_rhs->lhs() - ->As() - ->literal() - ->As() - ->value(), - 2u); - ASSERT_TRUE(add_rhs->rhs()->Is()); - ASSERT_EQ(add_rhs->rhs() - ->As() - ->literal() - ->As() - ->value(), - 3u); - - ASSERT_TRUE(idx->params()[1]->Is()); - ASSERT_TRUE(idx->params()[1]->Is()); - scalar = idx->params()[1]->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Negative_Column) { - // var a : mat3x2 - // var b : f32 = a[-1][1] - // - // -> var b : f32 = a[0][1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", -1), 1), {}); - } - }; + auto* src = R"( +var a : mat3x2; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[-1][1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[0][1]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); + auto got = Transform(src); - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 0); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Negative_Row) { - // var a : mat3x2 - // var b : f32 = a[2][-1] - // - // -> var b : f32 = a[2][0] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", 2), -1), {}); - } - }; + auto* src = R"( +var a : mat3x2; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[2][-1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[2][0]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); + auto got = Transform(src); - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 0); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_OutOfBounds_Column) { - // var a : mat3x2 - // var b : f32 = a[5][1] - // - // -> var b : f32 = a[2][1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", 5u), 1u), {}); - } - }; + auto* src = R"( +var a : mat3x2; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[5][1]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[2][1]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); + auto got = Transform(src); - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } TEST_F(BoundArrayAccessorsTest, Matrix_Idx_OutOfBounds_Row) { - // var a : mat3x2 - // var b : f32 = a[2][5] - // - // -> var b : f32 = a[2][1] - struct Builder : ModuleBuilder { - void Build() override { - Var("a", ast::StorageClass::kFunction, ty.mat3x2()); - Var("b", ast::StorageClass::kFunction, ty.f32, - IndexAccessor(IndexAccessor("a", 2u), 5u), {}); - } - }; + auto* src = R"( +var a : mat3x2; - ast::Module module = Transform(Builder{}.Module()); - ASSERT_EQ(error, ""); +fn f() -> void { + var b : f32 = a[2][5]; +} +)"; - auto* b = FindVariable(&module, "b"); - ASSERT_NE(b, nullptr); + auto* expect = R"( +var a : mat3x2; - ASSERT_TRUE(b->Is()); +fn f() -> void { + var b : f32 = a[2][1]; +} +)"; - ASSERT_TRUE(b->array()->Is()); - auto* ary = b->array()->As(); - ASSERT_TRUE(ary->idx_expr()->Is()); - ASSERT_TRUE(ary->idx_expr()->Is()); + auto got = Transform(src); - auto* scalar = ary->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 2u); - - ASSERT_NE(ary->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(ary->idx_expr()->result_type()->Is()); - - ASSERT_TRUE(b->idx_expr()->Is()); - ASSERT_TRUE(b->idx_expr()->Is()); - - scalar = b->idx_expr()->As(); - ASSERT_TRUE(scalar->literal()->Is()); - EXPECT_EQ(scalar->literal()->As()->value(), 1u); - - ASSERT_NE(b->idx_expr()->result_type(), nullptr); - ASSERT_TRUE(b->idx_expr()->result_type()->Is()); + EXPECT_EQ(expect, got); } // TODO(dsinclair): Implement when constant_id exists @@ -934,7 +416,7 @@ TEST_F(BoundArrayAccessorsTest, DISABLED_Vector_Constant_Id_Clamps) { // var a : vec3 // var b : f32 = a[idx] // - // ->var b : f32 = a[min(u32(idx), 2)] + // ->var b : f32 = a[min(u32(idx), 2)] } // TODO(dsinclair): Implement when constant_id exists diff --git a/src/transform/emit_vertex_point_size_test.cc b/src/transform/emit_vertex_point_size_test.cc index c3c5f70775..9a4a35958c 100644 --- a/src/transform/emit_vertex_point_size_test.cc +++ b/src/transform/emit_vertex_point_size_test.cc @@ -14,203 +14,106 @@ #include "src/transform/emit_vertex_point_size.h" -#include -#include - -#include "gtest/gtest.h" -#include "src/ast/builder.h" -#include "src/ast/stage_decoration.h" -#include "src/ast/variable_decl_statement.h" -#include "src/demangler.h" -#include "src/diagnostic/formatter.h" -#include "src/transform/manager.h" +#include "src/transform/test_helper.h" namespace tint { namespace transform { namespace { -class EmitVertexPointSizeTest : public testing::Test { - public: - Transform::Output GetTransform(ast::Module in) { - Manager manager; - manager.append(std::make_unique()); - return manager.Run(&in); - } -}; - -struct ModuleBuilder : public ast::BuilderWithModule { - ModuleBuilder() {} - - ast::Module Module() { - Build(); - return std::move(*mod); - } - - protected: - virtual void Build() = 0; -}; +using EmitVertexPointSizeTest = TransformTest; TEST_F(EmitVertexPointSizeTest, VertexStageBasic) { - struct Builder : ModuleBuilder { - void Build() override { - mod->AddFunction(Func("non_entry_a", ast::VariableList{}, ty.void_, - ast::StatementList{}, - ast::FunctionDecorationList{})); + auto* src = R"( +fn non_entry_a() -> void { +} - auto* entry = - Func("entry", ast::VariableList{}, ty.void_, - ast::StatementList{ - create( - Var("builtin_assignments_should_happen_before_this", - tint::ast::StorageClass::kFunction, ty.f32)), - }, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kVertex), - }); - mod->AddFunction(entry); +[[stage(vertex)]] +fn entry() -> void { + var builtin_assignments_should_happen_before_this : f32; +} - mod->AddFunction(Func("non_entry_b", ast::VariableList{}, ty.void_, - ast::StatementList{}, - ast::FunctionDecorationList{})); - } - }; - - auto result = GetTransform(Builder{}.Module()); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto* expected = R"(Module{ - Variable{ - Decorations{ - BuiltinDecoration{pointsize} - } - tint_pointsize - out - __f32 - } - Function non_entry_a -> __void - () - { - } - Function entry -> __void - StageDecoration{vertex} - () - { - Assignment{ - Identifier[__ptr_out__f32]{tint_pointsize} - ScalarConstructor[__f32]{1.000000} - } - VariableDeclStatement{ - Variable{ - builtin_assignments_should_happen_before_this - function - __f32 - } - } - } - Function non_entry_b -> __void - () - { - } +fn non_entry_b() -> void { } )"; - EXPECT_EQ(expected, - Demangler().Demangle(result.module, result.module.to_str())); + + auto* expect = R"( +[[builtin(pointsize)]] var tint_pointsize : f32; + +fn non_entry_a() -> void { +} + +[[stage(vertex)]] +fn entry() -> void { + tint_pointsize = 1.0; + var builtin_assignments_should_happen_before_this : f32; +} + +fn non_entry_b() -> void { +} +)"; + + auto got = Transform(src); + + EXPECT_EQ(expect, got); } TEST_F(EmitVertexPointSizeTest, VertexStageEmpty) { - struct Builder : ModuleBuilder { - void Build() override { - mod->AddFunction(Func("non_entry_a", ast::VariableList{}, ty.void_, - ast::StatementList{}, - ast::FunctionDecorationList{})); + auto* src = R"( +fn non_entry_a() -> void { +} - mod->AddFunction( - Func("entry", ast::VariableList{}, ty.void_, ast::StatementList{}, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kVertex), - })); +[[stage(vertex)]] +fn entry() -> void { +} - mod->AddFunction(Func("non_entry_b", ast::VariableList{}, ty.void_, - ast::StatementList{}, - ast::FunctionDecorationList{})); - } - }; - - auto result = GetTransform(Builder{}.Module()); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto* expected = R"(Module{ - Variable{ - Decorations{ - BuiltinDecoration{pointsize} - } - tint_pointsize - out - __f32 - } - Function non_entry_a -> __void - () - { - } - Function entry -> __void - StageDecoration{vertex} - () - { - Assignment{ - Identifier[__ptr_out__f32]{tint_pointsize} - ScalarConstructor[__f32]{1.000000} - } - } - Function non_entry_b -> __void - () - { - } +fn non_entry_b() -> void { } )"; - EXPECT_EQ(expected, - Demangler().Demangle(result.module, result.module.to_str())); + + auto* expect = R"( +[[builtin(pointsize)]] var tint_pointsize : f32; + +fn non_entry_a() -> void { +} + +[[stage(vertex)]] +fn entry() -> void { + tint_pointsize = 1.0; +} + +fn non_entry_b() -> void { +} +)"; + + auto got = Transform(src); + + EXPECT_EQ(expect, got); } TEST_F(EmitVertexPointSizeTest, NonVertexStage) { - struct Builder : ModuleBuilder { - void Build() override { - auto* fragment_entry = Func( - "fragment_entry", ast::VariableList{}, ty.void_, ast::StatementList{}, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kFragment), - }); - mod->AddFunction(fragment_entry); + auto* src = R"( +[[stage(fragment)]] +fn fragment_entry() -> void { +} - auto* compute_entry = Func( - "compute_entry", ast::VariableList{}, ty.void_, ast::StatementList{}, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kCompute), - }); - mod->AddFunction(compute_entry); - } - }; - - auto result = GetTransform(Builder{}.Module()); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto* expected = R"(Module{ - Function fragment_entry -> __void - StageDecoration{fragment} - () - { - } - Function compute_entry -> __void - StageDecoration{compute} - () - { - } +[[stage(compute)]] +fn compute_entry() -> void { } )"; - EXPECT_EQ(expected, - Demangler().Demangle(result.module, result.module.to_str())); + + auto* expect = R"( +[[stage(fragment)]] +fn fragment_entry() -> void { +} + +[[stage(compute)]] +fn compute_entry() -> void { +} +)"; + + auto got = Transform(src); + + EXPECT_EQ(expect, got); } } // namespace diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc index 094df6d7eb..c739810dba 100644 --- a/src/transform/first_index_offset_test.cc +++ b/src/transform/first_index_offset_test.cc @@ -15,413 +15,223 @@ #include "src/transform/first_index_offset.h" #include -#include #include +#include -#include "gtest/gtest.h" -#include "src/ast/block_statement.h" -#include "src/ast/builder.h" -#include "src/ast/builtin.h" -#include "src/ast/builtin_decoration.h" -#include "src/ast/call_expression.h" -#include "src/ast/call_statement.h" -#include "src/ast/function.h" -#include "src/ast/identifier_expression.h" -#include "src/ast/module.h" -#include "src/ast/return_statement.h" -#include "src/ast/storage_class.h" -#include "src/ast/type/u32_type.h" -#include "src/ast/variable.h" -#include "src/ast/variable_decoration.h" -#include "src/demangler.h" -#include "src/diagnostic/formatter.h" -#include "src/source.h" -#include "src/transform/manager.h" +#include "src/transform/test_helper.h" namespace tint { namespace transform { namespace { -class FirstIndexOffsetTest : public testing::Test {}; - -struct ModuleBuilder : public ast::BuilderWithModule { - ast::Module Module() { - Build(); - return std::move(*mod); - } - - protected: - void AddBuiltinInput(const std::string& name, ast::Builtin builtin) { - mod->AddGlobalVariable(Var(name, ast::StorageClass::kInput, ty.u32, nullptr, - {create(builtin)})); - } - - ast::Function* AddFunction(const std::string& name, - ast::StatementList stmts) { - auto* func = Func(name, ast::VariableList{}, ty.u32, stmts, - ast::FunctionDecorationList{}); - mod->AddFunction(func); - return func; - } - - virtual void Build() = 0; -}; +using FirstIndexOffsetTest = TransformTest; TEST_F(FirstIndexOffsetTest, Error_AlreadyTransformed) { - struct Builder : public ModuleBuilder { - void Build() override { - AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx); - AddFunction("test", {create(Expr("vert_idx"))}); - } - }; + auto* src = R"( +[[builtin(vertex_idx)]] var vert_idx : u32; - Manager manager; - manager.append(std::make_unique(0, 0)); - manager.append(std::make_unique(1, 1)); +fn test() -> u32 { + return vert_idx; +} - auto module = Builder{}.Module(); - auto result = manager.Run(&module); +[[stage(vertex)]] +fn entry() -> void { + test(); +} +)"; - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } + auto* expect = R"(manager().Run() errored: +error: First index offset transform has already been applied.)"; - ASSERT_EQ(diag::Formatter().format(result.diagnostics), - "error: First index offset transform has already been applied."); + std::vector> transforms; + transforms.emplace_back(std::make_unique(0, 0)); + transforms.emplace_back(std::make_unique(1, 1)); + + auto got = Transform(src, std::move(transforms)); + + EXPECT_EQ(expect, got); } TEST_F(FirstIndexOffsetTest, EmptyModule) { - Manager manager; - manager.append(std::make_unique(0, 0)); + auto* src = ""; + auto* expect = ""; - ast::Module module; - auto result = manager.Run(&module); + auto got = Transform(src, 0, 0); - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } - - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto got = result.module.to_str(); - auto* expected = "Module{\n}\n"; - EXPECT_EQ(got, expected); + EXPECT_EQ(expect, got); } TEST_F(FirstIndexOffsetTest, BasicModuleVertexIndex) { - struct Builder : public ModuleBuilder { - void Build() override { - AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx); - AddFunction("test", {create(Expr("vert_idx"))}); - } - }; + auto* src = R"( +[[builtin(vertex_idx)]] var vert_idx : u32; - Manager manager; - manager.append(std::make_unique(1, 2)); +fn test() -> u32 { + return vert_idx; +} - auto module = Builder{}.Module(); - auto result = manager.Run(&module); - - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } - - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto got = result.module.to_str(); - auto* expected = - R"(Module{ - TintFirstIndexOffsetData Struct{ - [[block]] - StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - tint_first_index_offset_vert_idx - in - __u32 - } - Variable{ - Decorations{ - BindingDecoration{1} - SetDecoration{2} - } - tint_first_index_data - uniform - __struct_TintFirstIndexOffsetData - } - Function test -> __u32 - () - { - VariableDeclStatement{ - VariableConst{ - vert_idx - none - __u32 - { - Binary[__u32]{ - Identifier[__ptr_in__u32]{tint_first_index_offset_vert_idx} - add - MemberAccessor[__ptr_uniform__u32]{ - Identifier[__ptr_uniform__struct_TintFirstIndexOffsetData]{tint_first_index_data} - Identifier[not set]{tint_first_vertex_index} - } - } - } - } - } - Return{ - { - Identifier[__u32]{vert_idx} - } - } - } +[[stage(vertex)]] +fn entry() -> void { + test(); } )"; - EXPECT_EQ(Demangler().Demangle(result.module, got), expected); + + auto* expect = R"( +[[block]] +struct TintFirstIndexOffsetData { + [[offset(0)]] + tint_first_vertex_index : u32; +}; + +[[builtin(vertex_idx)]] var tint_first_index_offset_vert_idx : u32; +[[binding(1), set(2)]] var tint_first_index_data : TintFirstIndexOffsetData; + +fn test() -> u32 { + const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index); + return vert_idx; +} + +[[stage(vertex)]] +fn entry() -> void { + test(); +} +)"; + + auto got = Transform(src, 1, 2); + + EXPECT_EQ(expect, got); } TEST_F(FirstIndexOffsetTest, BasicModuleInstanceIndex) { - struct Builder : public ModuleBuilder { - void Build() override { - AddBuiltinInput("inst_idx", ast::Builtin::kInstanceIdx); - AddFunction("test", {create(Expr("inst_idx"))}); - } - }; + auto* src = R"( +[[builtin(instance_idx)]] var inst_idx : u32; - Manager manager; - manager.append(std::make_unique(1, 7)); +fn test() -> u32 { + return inst_idx; +} - auto module = Builder{}.Module(); - auto result = manager.Run(&module); - - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } - - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto got = result.module.to_str(); - auto* expected = R"(Module{ - TintFirstIndexOffsetData Struct{ - [[block]] - StructMember{[[ offset 0 ]] tint_first_instance_index: __u32} - } - Variable{ - Decorations{ - BuiltinDecoration{instance_idx} - } - tint_first_index_offset_inst_idx - in - __u32 - } - Variable{ - Decorations{ - BindingDecoration{1} - SetDecoration{7} - } - tint_first_index_data - uniform - __struct_TintFirstIndexOffsetData - } - Function test -> __u32 - () - { - VariableDeclStatement{ - VariableConst{ - inst_idx - none - __u32 - { - Binary[__u32]{ - Identifier[__ptr_in__u32]{tint_first_index_offset_inst_idx} - add - MemberAccessor[__ptr_uniform__u32]{ - Identifier[__ptr_uniform__struct_TintFirstIndexOffsetData]{tint_first_index_data} - Identifier[not set]{tint_first_instance_index} - } - } - } - } - } - Return{ - { - Identifier[__u32]{inst_idx} - } - } - } +[[stage(vertex)]] +fn entry() -> void { + test(); } )"; - EXPECT_EQ(Demangler().Demangle(result.module, got), expected); + + auto* expect = R"( +[[block]] +struct TintFirstIndexOffsetData { + [[offset(0)]] + tint_first_instance_index : u32; +}; + +[[builtin(instance_idx)]] var tint_first_index_offset_inst_idx : u32; +[[binding(1), set(7)]] var tint_first_index_data : TintFirstIndexOffsetData; + +fn test() -> u32 { + const inst_idx : u32 = (tint_first_index_offset_inst_idx + tint_first_index_data.tint_first_instance_index); + return inst_idx; +} + +[[stage(vertex)]] +fn entry() -> void { + test(); +} +)"; + + auto got = Transform(src, 1, 7); + + EXPECT_EQ(expect, got); } TEST_F(FirstIndexOffsetTest, BasicModuleBothIndex) { - struct Builder : public ModuleBuilder { - void Build() override { - AddBuiltinInput("inst_idx", ast::Builtin::kInstanceIdx); - AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx); - AddFunction("test", { - create(Expr(1u)), - }); - } - }; + auto* src = R"( +[[builtin(instance_idx)]] var instance_idx : u32; +[[builtin(vertex_idx)]] var vert_idx : u32; - auto transform = std::make_unique(1, 7); - auto* transform_ptr = transform.get(); +fn test() -> u32 { + return instance_idx + vert_idx; +} - Manager manager; - manager.append(std::move(transform)); - - auto module = Builder{}.Module(); - auto result = manager.Run(&module); - - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } - - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto got = result.module.to_str(); - auto* expected = R"(Module{ - TintFirstIndexOffsetData Struct{ - [[block]] - StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32} - StructMember{[[ offset 4 ]] tint_first_instance_index: __u32} - } - Variable{ - Decorations{ - BuiltinDecoration{instance_idx} - } - tint_first_index_offset_inst_idx - in - __u32 - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - tint_first_index_offset_vert_idx - in - __u32 - } - Variable{ - Decorations{ - BindingDecoration{1} - SetDecoration{7} - } - tint_first_index_data - uniform - __struct_TintFirstIndexOffsetData - } - Function test -> __u32 - () - { - Return{ - { - ScalarConstructor[__u32]{1} - } - } - } +[[stage(vertex)]] +fn entry() -> void { + test(); } )"; - EXPECT_EQ(Demangler().Demangle(result.module, got), expected); - EXPECT_TRUE(transform_ptr->HasVertexIndex()); - EXPECT_EQ(transform_ptr->GetFirstVertexOffset(), 0u); + auto* expect = R"( +[[block]] +struct TintFirstIndexOffsetData { + [[offset(0)]] + tint_first_vertex_index : u32; + [[offset(4)]] + tint_first_instance_index : u32; +}; - EXPECT_TRUE(transform_ptr->HasInstanceIndex()); - EXPECT_EQ(transform_ptr->GetFirstInstanceOffset(), 4u); +[[builtin(instance_idx)]] var tint_first_index_offset_instance_idx : u32; +[[builtin(vertex_idx)]] var tint_first_index_offset_vert_idx : u32; +[[binding(1), set(2)]] var tint_first_index_data : TintFirstIndexOffsetData; + +fn test() -> u32 { + const instance_idx : u32 = (tint_first_index_offset_instance_idx + tint_first_index_data.tint_first_instance_index); + const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index); + return (instance_idx + vert_idx); +} + +[[stage(vertex)]] +fn entry() -> void { + test(); +} +)"; + + auto got = Transform(src, 1, 2); + + EXPECT_EQ(expect, got); } TEST_F(FirstIndexOffsetTest, NestedCalls) { - struct Builder : public ModuleBuilder { - void Build() override { - AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx); - AddFunction("func1", {create(Expr("vert_idx"))}); - AddFunction("func2", {create(Call("func1"))}); - } - }; + auto* src = R"( +[[builtin(vertex_idx)]] var vert_idx : u32; - auto transform = std::make_unique(2, 2); +fn func1() -> u32 { + return vert_idx; +} - Manager manager; - manager.append(std::move(transform)); +fn func2() -> u32 { + return func1(); +} - auto module = Builder{}.Module(); - auto result = manager.Run(&module); - - // Release the source module to ensure there's no uncloned data in result - { auto tmp = std::move(module); } - - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - auto got = result.module.to_str(); - auto* expected = R"(Module{ - TintFirstIndexOffsetData Struct{ - [[block]] - StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - tint_first_index_offset_vert_idx - in - __u32 - } - Variable{ - Decorations{ - BindingDecoration{2} - SetDecoration{2} - } - tint_first_index_data - uniform - __struct_TintFirstIndexOffsetData - } - Function func1 -> __u32 - () - { - VariableDeclStatement{ - VariableConst{ - vert_idx - none - __u32 - { - Binary[__u32]{ - Identifier[__ptr_in__u32]{tint_first_index_offset_vert_idx} - add - MemberAccessor[__ptr_uniform__u32]{ - Identifier[__ptr_uniform__struct_TintFirstIndexOffsetData]{tint_first_index_data} - Identifier[not set]{tint_first_vertex_index} - } - } - } - } - } - Return{ - { - Identifier[__u32]{vert_idx} - } - } - } - Function func2 -> __u32 - () - { - Return{ - { - Call[__u32]{ - Identifier[__u32]{func1} - ( - ) - } - } - } - } +[[stage(vertex)]] +fn entry() -> void { + func2(); } )"; - EXPECT_EQ(Demangler().Demangle(result.module, got), expected); + + auto* expect = R"( +[[block]] +struct TintFirstIndexOffsetData { + [[offset(0)]] + tint_first_vertex_index : u32; +}; + +[[builtin(vertex_idx)]] var tint_first_index_offset_vert_idx : u32; +[[binding(1), set(2)]] var tint_first_index_data : TintFirstIndexOffsetData; + +fn func1() -> u32 { + const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index); + return vert_idx; +} + +fn func2() -> u32 { + return func1(); +} + +[[stage(vertex)]] +fn entry() -> void { + func2(); +} +)"; + + auto got = Transform(src, 1, 2); + + EXPECT_EQ(expect, got); } } // namespace diff --git a/src/transform/test_helper.h b/src/transform/test_helper.h new file mode 100644 index 0000000000..269d8a9485 --- /dev/null +++ b/src/transform/test_helper.h @@ -0,0 +1,115 @@ +// Copyright 2021 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_TRANSFORM_TEST_HELPER_H_ +#define SRC_TRANSFORM_TEST_HELPER_H_ + +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "src/reader/wgsl/parser.h" +#include "src/transform/manager.h" +#include "src/type_determiner.h" +#include "src/writer/wgsl/generator.h" + +namespace tint { +namespace transform { + +/// Helper class for testing transforms +class TransformTest : public testing::Test { + public: + /// Transforms and returns the WGSL source `in`, transformed using + /// `transforms`. + /// @param in the input WGSL source + /// @param transforms the list of transforms to apply + /// @return the transformed WGSL output + std::string Transform( + std::string in, + std::vector> transforms) { + Source::File file("test", in); + reader::wgsl::Parser parser(&file); + if (!parser.Parse()) { + return "WGSL reader failed:\n" + parser.error(); + } + + auto module = parser.module(); + TypeDeterminer td(&module); + if (!td.Determine()) { + return "Type determination failed:\n" + td.error(); + } + + Manager manager; + for (auto& transform : transforms) { + manager.append(std::move(transform)); + } + auto result = manager.Run(&module); + + if (result.diagnostics.contains_errors()) { + return "manager().Run() errored:\n" + + diag::Formatter().format(result.diagnostics); + } + + // Release the source module to ensure there's no uncloned data in result + { auto tmp = std::move(module); } + + writer::wgsl::Generator generator(std::move(result.module)); + if (!generator.Generate()) { + return "WGSL writer failed:\n" + generator.error(); + } + + auto res = generator.result(); + if (res.empty()) { + return res; + } + // The WGSL sometimes has two trailing newlines. Strip them + while (res.back() == '\n') { + res.pop_back(); + } + if (res.empty()) { + return res; + } + return "\n" + res + "\n"; + } + + /// Transforms and returns the WGSL source `in`, transformed using + /// `transform`. + /// @param transform the transform to apply + /// @param in the input WGSL source + /// @return the transformed WGSL output + std::string Transform(std::string in, + std::unique_ptr transform) { + std::vector> transforms; + transforms.emplace_back(std::move(transform)); + return Transform(std::move(in), std::move(transforms)); + } + + /// Transforms and returns the WGSL source `in`, transformed using + /// a transform of type `TRANSFORM`. + /// @param in the input WGSL source + /// @param args the TRANSFORM constructor arguments + /// @return the transformed WGSL output + template + std::string Transform(std::string in, ARGS&&... args) { + return Transform(std::move(in), + std::make_unique(std::forward(args)...)); + } +}; + +} // namespace transform +} // namespace tint + +#endif // SRC_TRANSFORM_TEST_HELPER_H_ diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc index 129a4f9bc2..87e9a0c9cd 100644 --- a/src/transform/vertex_pulling_test.cc +++ b/src/transform/vertex_pulling_test.cc @@ -16,1008 +16,369 @@ #include -#include "gtest/gtest.h" -#include "src/ast/builder.h" -#include "src/ast/function.h" -#include "src/ast/pipeline_stage.h" -#include "src/ast/stage_decoration.h" -#include "src/ast/type/array_type.h" -#include "src/ast/type/f32_type.h" -#include "src/ast/type/i32_type.h" -#include "src/ast/type/void_type.h" -#include "src/demangler.h" -#include "src/diagnostic/formatter.h" -#include "src/transform/manager.h" -#include "src/type_determiner.h" -#include "src/validator/validator.h" +#include "src/transform/test_helper.h" namespace tint { namespace transform { namespace { -class VertexPullingHelper : public ast::BuilderWithModule { - public: - VertexPullingHelper() { - manager_ = std::make_unique(); - auto transform = std::make_unique(); - transform_ = transform.get(); - manager_->append(std::move(transform)); - } - - // Create basic module with an entry point and vertex function - void InitBasicModule() { - auto* func = - Func("main", ast::VariableList{}, ty.void_, ast::StatementList{}, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kVertex)}); - - mod->AddFunction(func); - } - - // Set up the transformation, after building the module - void InitTransform(VertexStateDescriptor vertex_state) { - EXPECT_TRUE(mod->IsValid()); - - TypeDeterminer td(mod); - EXPECT_TRUE(td.Determine()); - - transform_->SetVertexState(vertex_state); - transform_->SetEntryPoint("main"); - } - - // Inserts a variable which will be converted to vertex pulling - void AddVertexInputVariable(uint32_t location, - std::string name, - ast::type::Type* type) { - auto* var = Var(name, ast::StorageClass::kInput, type, nullptr, - ast::VariableDecorationList{ - create(location), - }); - - mod->AddGlobalVariable(var); - } - - Manager* manager() { return manager_.get(); } - VertexPulling* transform() { return transform_; } - - private: - std::unique_ptr manager_; - VertexPulling* transform_; -}; - -class VertexPullingTest : public VertexPullingHelper, public testing::Test {}; +using VertexPullingTest = TransformTest; TEST_F(VertexPullingTest, Error_NoVertexState) { - auto result = manager()->Run(mod); - EXPECT_TRUE(result.diagnostics.contains_errors()); - EXPECT_EQ(diag::Formatter().format(result.diagnostics), - "error: SetVertexState not called"); + auto* src = R"( +[[stage(vertex)]] +fn main() -> void {} +)"; + + auto* expect = R"(manager().Run() errored: +error: SetVertexState not called)"; + + auto got = Transform(src); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, Error_NoEntryPoint) { - transform()->SetVertexState({}); - auto result = manager()->Run(mod); - EXPECT_TRUE(result.diagnostics.contains_errors()); - EXPECT_EQ(diag::Formatter().format(result.diagnostics), - "error: Vertex stage entry point not found"); + auto* src = ""; + + auto* expect = R"(manager().Run() errored: +error: Vertex stage entry point not found)"; + + auto transform = std::make_unique(); + transform->SetVertexState({}); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, Error_InvalidEntryPoint) { - InitBasicModule(); - InitTransform({}); - transform()->SetEntryPoint("_"); + auto* src = R"( +[[stage(vertex)]] +fn main() -> void {} +)"; - auto result = manager()->Run(mod); - EXPECT_TRUE(result.diagnostics.contains_errors()); - EXPECT_EQ(diag::Formatter().format(result.diagnostics), - "error: Vertex stage entry point not found"); + auto* expect = R"(manager().Run() errored: +error: Vertex stage entry point not found)"; + + auto transform = std::make_unique(); + transform->SetVertexState({}); + transform->SetEntryPoint("_"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, Error_EntryPointWrongStage) { - auto* func = - Func("main", ast::VariableList{}, ty.void_, ast::StatementList{}, - ast::FunctionDecorationList{ - create(ast::PipelineStage::kFragment), - }); - mod->AddFunction(func); + auto* src = R"( +[[stage(fragment)]] +fn main() -> void {} +)"; - InitTransform({}); - auto result = manager()->Run(mod); - EXPECT_TRUE(result.diagnostics.contains_errors()); - EXPECT_EQ(diag::Formatter().format(result.diagnostics), - "error: Vertex stage entry point not found"); + auto* expect = R"(manager().Run() errored: +error: Vertex stage entry point not found)"; + + auto transform = std::make_unique(); + transform->SetVertexState({}); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, BasicModule) { - InitBasicModule(); - InitTransform({}); - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); + auto* src = R"( +[[stage(vertex)]] +fn main() -> void {} +)"; + + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; + +[[stage(vertex)]] +fn main() -> void { + { + var _tint_pulling_pos : i32; + } +} +)"; + + auto transform = std::make_unique(); + transform->SetVertexState({}); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, OneAttribute) { - InitBasicModule(); + auto* src = R"( +[[location(0)]] var var_a : f32; - AddVertexInputVariable(0, "var_a", ty.f32); +[[stage(vertex)]] +fn main() -> void {} +)"; - InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); +[[builtin(vertex_idx)]] var _tint_pulling_vertex_index : i32; +[[binding(0), set(4)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +var var_a : f32; - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - _tint_pulling_vertex_index - in - __i32 - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __f32 - } - Function main -> __void - StageDecoration{vertex} - () +[[stage(vertex)]] +fn main() -> void { { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{4} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_a} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((_tint_pulling_vertex_index * 4u) + 0u); + var_a = bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]); } } -)", - Demangler().Demangle(result.module, result.module.to_str())); +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( + {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, OneInstancedAttribute) { - InitBasicModule(); + auto* src = R"( +[[location(0)]] var var_a : f32; - AddVertexInputVariable(0, "var_a", ty.f32); +[[stage(vertex)]] +fn main() -> void {} +)"; - InitTransform( - {{{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 0}}}}}); + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); +[[builtin(instance_idx)]] var _tint_pulling_instance_index : i32; +[[binding(0), set(4)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +var var_a : f32; - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BuiltinDecoration{instance_idx} - } - _tint_pulling_instance_index - in - __i32 - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __f32 - } - Function main -> __void - StageDecoration{vertex} - () +[[stage(vertex)]] +fn main() -> void { { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_instance_index} - multiply - ScalarConstructor[__u32]{4} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_a} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((_tint_pulling_instance_index * 4u) + 0u); + var_a = bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]); } } -)", - Demangler().Demangle(result.module, result.module.to_str())); +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( + {{{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 0}}}}}); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, OneAttributeDifferentOutputSet) { - InitBasicModule(); + auto* src = R"( +[[location(0)]] var var_a : f32; - AddVertexInputVariable(0, "var_a", ty.f32); +[[stage(vertex)]] +fn main() -> void {} +)"; - InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); - transform()->SetPullingBufferBindingSet(5); + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); +[[builtin(vertex_idx)]] var _tint_pulling_vertex_index : i32; +[[binding(0), set(5)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +var var_a : f32; - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - _tint_pulling_vertex_index - in - __i32 - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{5} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __f32 - } - Function main -> __void - StageDecoration{vertex} - () +[[stage(vertex)]] +fn main() -> void { { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{4} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_a} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((_tint_pulling_vertex_index * 4u) + 0u); + var_a = bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]); } } -)", - Demangler().Demangle(result.module, result.module.to_str())); +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( + {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); + transform->SetPullingBufferBindingSet(5); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } // We expect the transform to use an existing builtin variables if it finds them TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex) { - InitBasicModule(); + auto* src = R"( +[[location(0)]] var var_a : f32; +[[location(1)]] var var_b : f32; +[[builtin(vertex_idx)]] var custom_vertex_index : i32; +[[builtin(instance_idx)]] var custom_instance_index : i32; - AddVertexInputVariable(0, "var_a", ty.f32); - AddVertexInputVariable(1, "var_b", ty.f32); +[[stage(vertex)]] +fn main() -> void {} +)"; - mod->AddGlobalVariable( - Var("custom_vertex_index", ast::StorageClass::kInput, ty.i32, nullptr, - ast::VariableDecorationList{ - create(ast::Builtin::kVertexIdx), - })); + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; - mod->AddGlobalVariable( - Var("custom_instance_index", ast::StorageClass::kInput, ty.i32, nullptr, - ast::VariableDecorationList{ - create(ast::Builtin::kInstanceIdx), - })); +[[binding(0), set(4)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +[[binding(1), set(4)]] var _tint_pulling_vertex_buffer_1 : TintVertexData; +var var_a : f32; +var var_b : f32; +[[builtin(vertex_idx)]] var custom_vertex_index : i32; +[[builtin(instance_idx)]] var custom_instance_index : i32; - InitTransform( - {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}, - {4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 1}}}}}); - - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); - - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - Decorations{ - BindingDecoration{1} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_1 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __f32 - } - Variable{ - var_b - private - __f32 - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - custom_vertex_index - in - __i32 - } - Variable{ - Decorations{ - BuiltinDecoration{instance_idx} - } - custom_instance_index - in - __i32 - } - Function main -> __void - StageDecoration{vertex} - () +[[stage(vertex)]] +fn main() -> void { { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{custom_vertex_index} - multiply - ScalarConstructor[__u32]{4} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_a} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{custom_instance_index} - multiply - ScalarConstructor[__u32]{4} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_b} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_1} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((custom_vertex_index * 4u) + 0u); + var_a = bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]); + _tint_pulling_pos = ((custom_instance_index * 4u) + 0u); + var_b = bitcast(_tint_pulling_vertex_buffer_1._tint_vertex_data[(_tint_pulling_pos / 4u)]); } } -)", - Demangler().Demangle(result.module, result.module.to_str())); +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( + {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}, + {4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 1}}}}}); + transform->SetEntryPoint("main"); + + auto got = Transform(src, std::move(transform)); + + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, TwoAttributesSameBuffer) { - InitBasicModule(); + auto* src = R"( +[[location(0)]] var var_a : f32; +[[location(1)]] var var_b : array; - AddVertexInputVariable(0, "var_a", ty.f32); - AddVertexInputVariable(1, "var_b", ty.array()); +[[stage(vertex)]] +fn main() -> void {} +)"; - InitTransform( + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; + +[[builtin(vertex_idx)]] var _tint_pulling_vertex_index : i32; +[[binding(0), set(4)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +var var_a : f32; +var var_b : array; + +[[stage(vertex)]] +fn main() -> void { + { + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((_tint_pulling_vertex_index * 16u) + 0u); + var_a = bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]); + _tint_pulling_pos = ((_tint_pulling_vertex_index * 16u) + 0u); + var_b = vec4(bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 8u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 12u) / 4u)])); + } +} +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( {{{16, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}, {VertexFormat::kVec4F32, 0, 1}}}}}); + transform->SetEntryPoint("main"); - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); + auto got = Transform(src, std::move(transform)); - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - _tint_pulling_vertex_index - in - __i32 - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __f32 - } - Variable{ - var_b - private - __array__f32_4 - } - Function main -> __void - StageDecoration{vertex} - () - { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{16} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__f32]{var_a} - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - divide - ScalarConstructor[__u32]{4} - } - } - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{16} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__array__f32_4]{var_b} - TypeConstructor[__vec_4__f32]{ - __vec_4__f32 - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{0} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{4} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{8} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{12} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } - } - } -} -)", - Demangler().Demangle(result.module, result.module.to_str())); + EXPECT_EQ(expect, got); } TEST_F(VertexPullingTest, FloatVectorAttributes) { - InitBasicModule(); - AddVertexInputVariable(0, "var_a", ty.array()); - AddVertexInputVariable(1, "var_b", ty.array()); - AddVertexInputVariable(2, "var_c", ty.array()); + auto* src = R"( +[[location(0)]] var var_a : array; +[[location(1)]] var var_b : array; +[[location(2)]] var var_c : array; - InitTransform( +[[stage(vertex)]] +fn main() -> void {} +)"; + + auto* expect = R"( +[[block]] +struct TintVertexData { + [[offset(0)]] + _tint_vertex_data : [[stride(4)]] array; +}; + +[[builtin(vertex_idx)]] var _tint_pulling_vertex_index : i32; +[[binding(0), set(4)]] var _tint_pulling_vertex_buffer_0 : TintVertexData; +[[binding(1), set(4)]] var _tint_pulling_vertex_buffer_1 : TintVertexData; +[[binding(2), set(4)]] var _tint_pulling_vertex_buffer_2 : TintVertexData; +var var_a : array; +var var_b : array; +var var_c : array; + +[[stage(vertex)]] +fn main() -> void { + { + var _tint_pulling_pos : i32; + _tint_pulling_pos = ((_tint_pulling_vertex_index * 8u) + 0u); + var_a = vec2(bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)])); + _tint_pulling_pos = ((_tint_pulling_vertex_index * 12u) + 0u); + var_b = vec3(bitcast(_tint_pulling_vertex_buffer_1._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_1._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_1._tint_vertex_data[((_tint_pulling_pos + 8u) / 4u)])); + _tint_pulling_pos = ((_tint_pulling_vertex_index * 16u) + 0u); + var_c = vec4(bitcast(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 8u) / 4u)]), bitcast(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 12u) / 4u)])); + } +} +)"; + + auto transform = std::make_unique(); + transform->SetVertexState( {{{8, InputStepMode::kVertex, {{VertexFormat::kVec2F32, 0, 0}}}, {12, InputStepMode::kVertex, {{VertexFormat::kVec3F32, 0, 1}}}, {16, InputStepMode::kVertex, {{VertexFormat::kVec4F32, 0, 2}}}}}); + transform->SetEntryPoint("main"); - auto result = manager()->Run(mod); - ASSERT_FALSE(result.diagnostics.contains_errors()) - << diag::Formatter().format(result.diagnostics); + auto got = Transform(src, std::move(transform)); - EXPECT_EQ(R"(Module{ - TintVertexData Struct{ - [[block]] - StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4} - } - Variable{ - Decorations{ - BuiltinDecoration{vertex_idx} - } - _tint_pulling_vertex_index - in - __i32 - } - Variable{ - Decorations{ - BindingDecoration{0} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_0 - storage_buffer - __struct_TintVertexData - } - Variable{ - Decorations{ - BindingDecoration{1} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_1 - storage_buffer - __struct_TintVertexData - } - Variable{ - Decorations{ - BindingDecoration{2} - SetDecoration{4} - } - _tint_pulling_vertex_buffer_2 - storage_buffer - __struct_TintVertexData - } - Variable{ - var_a - private - __array__f32_2 - } - Variable{ - var_b - private - __array__f32_3 - } - Variable{ - var_c - private - __array__f32_4 - } - Function main -> __void - StageDecoration{vertex} - () - { - Block{ - VariableDeclStatement{ - Variable{ - _tint_pulling_pos - function - __i32 - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{8} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__array__f32_2]{var_a} - TypeConstructor[__vec_2__f32]{ - __vec_2__f32 - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{0} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_0} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{4} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{12} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__array__f32_3]{var_b} - TypeConstructor[__vec_3__f32]{ - __vec_3__f32 - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_1} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{0} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_1} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{4} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_1} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{8} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } - Assignment{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_in__i32]{_tint_pulling_vertex_index} - multiply - ScalarConstructor[__u32]{16} - } - add - ScalarConstructor[__u32]{0} - } - } - Assignment{ - Identifier[__ptr_private__array__f32_4]{var_c} - TypeConstructor[__vec_4__f32]{ - __vec_4__f32 - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_2} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{0} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_2} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{4} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_2} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{8} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - Bitcast[__f32]<__f32>{ - ArrayAccessor[__ptr_storage_buffer__u32]{ - MemberAccessor[__ptr_storage_buffer__array__u32_stride_4]{ - Identifier[__ptr_storage_buffer__struct_TintVertexData]{_tint_pulling_vertex_buffer_2} - Identifier[not set]{_tint_vertex_data} - } - Binary[__i32]{ - Binary[__i32]{ - Identifier[__ptr_function__i32]{_tint_pulling_pos} - add - ScalarConstructor[__u32]{12} - } - divide - ScalarConstructor[__u32]{4} - } - } - } - } - } - } - } -} -)", - Demangler().Demangle(result.module, result.module.to_str())); + EXPECT_EQ(expect, got); } } // namespace