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 <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 01684a9..547b74a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -831,6 +831,7 @@
"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 1a7c6a4..adc89af 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -465,10 +465,6 @@
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 @@
)
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 a3c148f..e7d70ce 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 <memory>
-#include <utility>
-
-#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 <typename T = ast::Expression>
-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<ast::VariableDeclStatement>()) {
- if (auto* var = decl->variable()) {
- if (var->name() == name) {
- return As<T>(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<BoundArrayAccessors>());
- 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<ast::VariableDeclStatement>(var));
- }
- ast::StatementList statements;
-};
+using BoundArrayAccessorsTest = TransformTest;
TEST_F(BoundArrayAccessorsTest, Ptrs_Clamp) {
- // var a : array<f32, 3>;
- // const c : u32 = 1;
- // const b : ptr<function, f32> = a[c]
- //
- // -> const b : ptr<function, i32> = a[min(u32(c), 2)]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
- Const("c", ast::StorageClass::kFunction, ty.u32);
- Const("b", ast::StorageClass::kFunction,
- ty.pointer<f32>(ast::StorageClass::kFunction),
- IndexAccessor("a", "c"), {});
- }
- };
+ auto* src = R"(
+var a : array<f32, 3>;
+const c : u32 = 1u;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ const b : ptr<function, f32> = a[c];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
+const c : u32 = 1u;
- ASSERT_TRUE(b->idx_expr()->Is<ast::CallExpression>());
+fn f() -> void {
+ const b : ptr<function, f32> = a[min(u32(c), 2u)];
+}
+)";
- auto* idx = b->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_EQ(idx->params().size(), 2u);
-
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- ASSERT_TRUE(tc->values()[0]->Is<ast::IdentifierExpression>());
- ASSERT_EQ(tc->values()[0]->As<ast::IdentifierExpression>()->name(), "c");
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- auto* scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Array_Idx_Nested_Scalar) {
- // var a : array<f32, 3>;
- // var b : array<f32, 5>;
- // 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<f32, 3>());
- Var("b", ast::StorageClass::kFunction, ty.array<f32, 5>());
- 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<f32, 3>;
+var b : array<f32, 5>;
+var i : u32;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var c : f32 = a[ b[i] ];
+}
+)";
- auto* c = FindVariable<ast::ArrayAccessorExpression>(&module, "c");
- ASSERT_NE(c, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
+var b : array<f32, 5>;
+var i : u32;
- ASSERT_TRUE(c->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(c->idx_expr()->Is<ast::CallExpression>());
+fn f() -> void {
+ var c : f32 = a[min(u32(b[min(u32(i), 4u)]), 2u)];
+}
+)";
- auto* idx = c->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_EQ(idx->params().size(), 2u);
-
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
-
- auto* sub = tc->values()[0];
- ASSERT_TRUE(sub->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(sub->As<ast::ArrayAccessorExpression>()
- ->idx_expr()
- ->Is<ast::CallExpression>());
-
- auto* sub_idx = sub->As<ast::ArrayAccessorExpression>()
- ->idx_expr()
- ->As<ast::CallExpression>();
- ASSERT_TRUE(sub_idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(sub_idx->func()->As<ast::IdentifierExpression>()->name(), "min");
-
- ASSERT_TRUE(sub_idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(sub_idx->params()[0]->Is<ast::TypeConstructorExpression>());
- tc = sub_idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- ASSERT_TRUE(tc->values()[0]->Is<ast::IdentifierExpression>());
- ASSERT_EQ(tc->values()[0]->As<ast::IdentifierExpression>()->name(), "i");
-
- ASSERT_TRUE(sub_idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(sub_idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- auto* scalar = sub_idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 4u);
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(c->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(c->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Array_Idx_Scalar) {
- // var a : array<f32, 3>
- // 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<f32, 3>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[1];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Array_Idx_Expr) {
- // var a : array<f32, 3>
- // 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<f32, 3>());
- 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<f32, 3>;
+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<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
+var c : u32;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::CallExpression>());
+fn f() -> void {
+ var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
+}
+)";
- auto* idx = b->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_EQ(idx->params().size(), 2u);
-
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- auto* add = tc->values()[0]->As<ast::BinaryExpression>();
- ASSERT_NE(add, nullptr);
- ASSERT_EQ(add->op(), ast::BinaryOp::kAdd);
- auto* add_lhs = add->lhs()->As<ast::IdentifierExpression>();
- ASSERT_NE(add_lhs, nullptr);
- ASSERT_EQ(add_lhs->name(), "c");
- auto* add_rhs = add->rhs()->As<ast::BinaryExpression>();
- ASSERT_NE(add_rhs, nullptr);
- ASSERT_TRUE(add_rhs->lhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->lhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 2u);
- ASSERT_TRUE(add_rhs->rhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->rhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 3u);
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- auto* scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Array_Idx_Negative) {
- // var a : array<f32, 3>
- // var b : f32 = a[-1]
- //
- // -> var b : f32 = a[0]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
- Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", -1),
- {});
- }
- };
+ auto* src = R"(
+var a : array<f32, 3>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[-1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[0];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 0);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::I32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Array_Idx_OutOfBounds) {
- // var a : array<f32, 3>
- // var b : f32 = a[3]
- //
- // -> var b : f32 = a[2]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
- Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 3u),
- {});
- }
- };
+ auto* src = R"(
+var a : array<f32, 3>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[3];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : array<f32, 3>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[2];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Vector_Idx_Scalar) {
- // var a : vec3<f32>
- // var b : f32 = a[1];
- //
- // -> var b : f32 = a[1]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 1u),
- {});
- }
- };
+ auto* src = R"(
+var a : vec3<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : vec3<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[1];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Vector_Idx_Expr) {
- // var a : vec3<f32>
- // 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<f32>());
- 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<f32>;
+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<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : vec3<f32>;
+var c : u32;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::CallExpression>());
+fn f() -> void {
+ var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
+}
+)";
- auto* idx = b->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_EQ(idx->params().size(), 2u);
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- auto* add = tc->values()[0]->As<ast::BinaryExpression>();
- ASSERT_NE(add, nullptr);
- auto* add_lhs = add->lhs()->As<ast::IdentifierExpression>();
- ASSERT_NE(add_lhs, nullptr);
- ASSERT_EQ(add_lhs->name(), "c");
- auto* add_rhs = add->rhs()->As<ast::BinaryExpression>();
- ASSERT_NE(add_rhs, nullptr);
- ASSERT_TRUE(add_rhs->lhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->lhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 2u);
- ASSERT_TRUE(add_rhs->rhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->rhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 3u);
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- auto* scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Vector_Idx_Negative) {
- // var a : vec3<f32>
- // var b : f32 = a[-1]
- //
- // -> var b : f32 = a[0]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", -1),
- {});
- }
- };
+ auto* src = R"(
+var a : vec3<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[-1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : vec3<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[0];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 0);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::I32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Vector_Idx_OutOfBounds) {
- // var a : vec3<f32>
- // var b : f32 = a[3]
- //
- // -> var b : f32 = a[2]
- struct Builder : ModuleBuilder {
- void Build() override {
- Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32, IndexAccessor("a", 3u),
- {});
- }
- };
+ auto* src = R"(
+var a : vec3<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[3];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : vec3<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
+fn f() -> void {
+ var b : f32 = a[2];
+}
+)";
- auto* scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Scalar) {
- // var a : mat3x2<f32>
- // 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<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32,
- IndexAccessor(IndexAccessor("a", 2u), 1u), {});
- }
- };
+ auto* src = R"(
+var a : mat3x2<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[2][1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[2][1];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
+ auto got = Transform<BoundArrayAccessors>(src);
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::U32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Expr_Column) {
- // var a : mat3x2<f32>
- // 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<f32>());
- 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<f32>;
+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<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
+var c : u32;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_TRUE(ary->idx_expr()->Is<ast::CallExpression>());
- auto* idx = ary->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
-
- ASSERT_EQ(idx->params().size(), 2u);
-
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- auto* add = tc->values()[0]->As<ast::BinaryExpression>();
- ASSERT_NE(add, nullptr);
- auto* add_lhs = add->lhs()->As<ast::IdentifierExpression>();
- ASSERT_NE(add_lhs, nullptr);
- ASSERT_EQ(add_lhs->name(), "c");
- auto* add_rhs = add->rhs()->As<ast::BinaryExpression>();
- ASSERT_NE(add_rhs, nullptr);
- ASSERT_TRUE(add_rhs->lhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->lhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 2u);
- ASSERT_TRUE(add_rhs->rhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->rhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 3u);
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- auto* scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::U32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Expr_Row) {
- // var a : mat3x2<f32>
- // 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<f32>());
- 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<f32>;
+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<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
+var c : u32;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
+ auto got = Transform<BoundArrayAccessors>(src);
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::CallExpression>());
- auto* idx = b->idx_expr()->As<ast::CallExpression>();
- ASSERT_TRUE(idx->func()->Is<ast::IdentifierExpression>());
- EXPECT_EQ(idx->func()->As<ast::IdentifierExpression>()->name(), "min");
-
- ASSERT_EQ(idx->params().size(), 2u);
-
- ASSERT_TRUE(idx->params()[0]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[0]->Is<ast::TypeConstructorExpression>());
- auto* tc = idx->params()[0]->As<ast::TypeConstructorExpression>();
- EXPECT_TRUE(tc->type()->Is<ast::type::U32>());
- ASSERT_EQ(tc->values().size(), 1u);
- auto* add = tc->values()[0]->As<ast::BinaryExpression>();
- ASSERT_NE(add, nullptr);
- auto* add_lhs = add->lhs()->As<ast::IdentifierExpression>();
- ASSERT_NE(add_lhs, nullptr);
- ASSERT_EQ(add_lhs->name(), "c");
- auto* add_rhs = add->rhs()->As<ast::BinaryExpression>();
- ASSERT_NE(add_rhs, nullptr);
- ASSERT_TRUE(add_rhs->lhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->lhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 2u);
- ASSERT_TRUE(add_rhs->rhs()->Is<ast::ScalarConstructorExpression>());
- ASSERT_EQ(add_rhs->rhs()
- ->As<ast::ScalarConstructorExpression>()
- ->literal()
- ->As<ast::UintLiteral>()
- ->value(),
- 3u);
-
- ASSERT_TRUE(idx->params()[1]->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(idx->params()[1]->Is<ast::ScalarConstructorExpression>());
- scalar = idx->params()[1]->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::U32>());
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Negative_Column) {
- // var a : mat3x2<f32>
- // 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<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32,
- IndexAccessor(IndexAccessor("a", -1), 1), {});
- }
- };
+ auto* src = R"(
+var a : mat3x2<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[-1][1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[0][1];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
+ auto got = Transform<BoundArrayAccessors>(src);
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 0);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::I32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 1);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::I32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_Negative_Row) {
- // var a : mat3x2<f32>
- // 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<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32,
- IndexAccessor(IndexAccessor("a", 2), -1), {});
- }
- };
+ auto* src = R"(
+var a : mat3x2<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[2][-1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[2][0];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
+ auto got = Transform<BoundArrayAccessors>(src);
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 2);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::I32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::SintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::SintLiteral>()->value(), 0);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::I32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_OutOfBounds_Column) {
- // var a : mat3x2<f32>
- // 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<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32,
- IndexAccessor(IndexAccessor("a", 5u), 1u), {});
- }
- };
+ auto* src = R"(
+var a : mat3x2<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[5][1];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[2][1];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
+ auto got = Transform<BoundArrayAccessors>(src);
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::U32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
TEST_F(BoundArrayAccessorsTest, Matrix_Idx_OutOfBounds_Row) {
- // var a : mat3x2<f32>
- // 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<f32>());
- Var("b", ast::StorageClass::kFunction, ty.f32,
- IndexAccessor(IndexAccessor("a", 2u), 5u), {});
- }
- };
+ auto* src = R"(
+var a : mat3x2<f32>;
- ast::Module module = Transform(Builder{}.Module());
- ASSERT_EQ(error, "");
+fn f() -> void {
+ var b : f32 = a[2][5];
+}
+)";
- auto* b = FindVariable<ast::ArrayAccessorExpression>(&module, "b");
- ASSERT_NE(b, nullptr);
+ auto* expect = R"(
+var a : mat3x2<f32>;
- ASSERT_TRUE(b->Is<ast::ArrayAccessorExpression>());
+fn f() -> void {
+ var b : f32 = a[2][1];
+}
+)";
- ASSERT_TRUE(b->array()->Is<ast::ArrayAccessorExpression>());
- auto* ary = b->array()->As<ast::ArrayAccessorExpression>();
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(ary->idx_expr()->Is<ast::ScalarConstructorExpression>());
+ auto got = Transform<BoundArrayAccessors>(src);
- auto* scalar = ary->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 2u);
-
- ASSERT_NE(ary->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(ary->idx_expr()->result_type()->Is<ast::type::U32>());
-
- ASSERT_TRUE(b->idx_expr()->Is<ast::ConstructorExpression>());
- ASSERT_TRUE(b->idx_expr()->Is<ast::ScalarConstructorExpression>());
-
- scalar = b->idx_expr()->As<ast::ScalarConstructorExpression>();
- ASSERT_TRUE(scalar->literal()->Is<ast::UintLiteral>());
- EXPECT_EQ(scalar->literal()->As<ast::UintLiteral>()->value(), 1u);
-
- ASSERT_NE(b->idx_expr()->result_type(), nullptr);
- ASSERT_TRUE(b->idx_expr()->result_type()->Is<ast::type::U32>());
+ EXPECT_EQ(expect, got);
}
// TODO(dsinclair): Implement when constant_id exists
@@ -934,7 +416,7 @@
// var a : vec3<f32>
// 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 c3c5f70..9a4a359 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 <memory>
-#include <utility>
-
-#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<EmitVertexPointSize>());
- 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<ast::VariableDeclStatement>(
- Var("builtin_assignments_should_happen_before_this",
- tint::ast::StorageClass::kFunction, ty.f32)),
- },
- ast::FunctionDecorationList{
- create<ast::StageDecoration>(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<out> 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<EmitVertexPointSize>(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::StageDecoration>(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<out> 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<EmitVertexPointSize>(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::StageDecoration>(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::StageDecoration>(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<EmitVertexPointSize>(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 094df6d..c739810 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 <memory>
-#include <string>
#include <utility>
+#include <vector>
-#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<ast::BuiltinDecoration>(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<ast::ReturnStatement>(Expr("vert_idx"))});
- }
- };
+ auto* src = R"(
+[[builtin(vertex_idx)]] var<in> vert_idx : u32;
- Manager manager;
- manager.append(std::make_unique<FirstIndexOffset>(0, 0));
- manager.append(std::make_unique<FirstIndexOffset>(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<std::unique_ptr<transform::Transform>> transforms;
+ transforms.emplace_back(std::make_unique<FirstIndexOffset>(0, 0));
+ transforms.emplace_back(std::make_unique<FirstIndexOffset>(1, 1));
+
+ auto got = Transform(src, std::move(transforms));
+
+ EXPECT_EQ(expect, got);
}
TEST_F(FirstIndexOffsetTest, EmptyModule) {
- Manager manager;
- manager.append(std::make_unique<FirstIndexOffset>(0, 0));
+ auto* src = "";
+ auto* expect = "";
- ast::Module module;
- auto result = manager.Run(&module);
+ auto got = Transform<FirstIndexOffset>(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<ast::ReturnStatement>(Expr("vert_idx"))});
- }
- };
+ auto* src = R"(
+[[builtin(vertex_idx)]] var<in> vert_idx : u32;
- Manager manager;
- manager.append(std::make_unique<FirstIndexOffset>(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<in> tint_first_index_offset_vert_idx : u32;
+[[binding(1), set(2)]] var<uniform> 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<FirstIndexOffset>(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<ast::ReturnStatement>(Expr("inst_idx"))});
- }
- };
+ auto* src = R"(
+[[builtin(instance_idx)]] var<in> inst_idx : u32;
- Manager manager;
- manager.append(std::make_unique<FirstIndexOffset>(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<in> tint_first_index_offset_inst_idx : u32;
+[[binding(1), set(7)]] var<uniform> 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<FirstIndexOffset>(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<ast::ReturnStatement>(Expr(1u)),
- });
- }
- };
+ auto* src = R"(
+[[builtin(instance_idx)]] var<in> instance_idx : u32;
+[[builtin(vertex_idx)]] var<in> vert_idx : u32;
- auto transform = std::make_unique<FirstIndexOffset>(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<in> tint_first_index_offset_instance_idx : u32;
+[[builtin(vertex_idx)]] var<in> tint_first_index_offset_vert_idx : u32;
+[[binding(1), set(2)]] var<uniform> 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<FirstIndexOffset>(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<ast::ReturnStatement>(Expr("vert_idx"))});
- AddFunction("func2", {create<ast::ReturnStatement>(Call("func1"))});
- }
- };
+ auto* src = R"(
+[[builtin(vertex_idx)]] var<in> vert_idx : u32;
- auto transform = std::make_unique<FirstIndexOffset>(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<in> tint_first_index_offset_vert_idx : u32;
+[[binding(1), set(2)]] var<uniform> 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<FirstIndexOffset>(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 0000000..269d8a9
--- /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 <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<std::unique_ptr<transform::Transform>> 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::Transform> transform) {
+ std::vector<std::unique_ptr<transform::Transform>> 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 <typename TRANSFORM, typename... ARGS>
+ std::string Transform(std::string in, ARGS&&... args) {
+ return Transform(std::move(in),
+ std::make_unique<TRANSFORM>(std::forward<ARGS>(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 129a4f9..87e9a0c 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -16,1008 +16,369 @@
#include <utility>
-#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<Manager>();
- auto transform = std::make_unique<VertexPulling>();
- 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::StageDecoration>(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<ast::LocationDecoration>(location),
- });
-
- mod->AddGlobalVariable(var);
- }
-
- Manager* manager() { return manager_.get(); }
- VertexPulling* transform() { return transform_; }
-
- private:
- std::unique_ptr<Manager> 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<VertexPulling>(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<VertexPulling>();
+ 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<VertexPulling>();
+ 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::StageDecoration>(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<VertexPulling>();
+ 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<u32>;
+};
+
+[[stage(vertex)]]
+fn main() -> void {
+ {
+ var _tint_pulling_pos : i32;
+ }
+}
+)";
+
+ auto transform = std::make_unique<VertexPulling>();
+ 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<in> 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<u32>;
+};
- auto result = manager()->Run(mod);
- ASSERT_FALSE(result.diagnostics.contains_errors())
- << diag::Formatter().format(result.diagnostics);
+[[builtin(vertex_idx)]] var<in> _tint_pulling_vertex_index : i32;
+[[binding(0), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+var<private> 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<f32>(_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<VertexPulling>();
+ 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<in> 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<u32>;
+};
- auto result = manager()->Run(mod);
- ASSERT_FALSE(result.diagnostics.contains_errors())
- << diag::Formatter().format(result.diagnostics);
+[[builtin(instance_idx)]] var<in> _tint_pulling_instance_index : i32;
+[[binding(0), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+var<private> 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<f32>(_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<VertexPulling>();
+ 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<in> 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<u32>;
+};
- auto result = manager()->Run(mod);
- ASSERT_FALSE(result.diagnostics.contains_errors())
- << diag::Formatter().format(result.diagnostics);
+[[builtin(vertex_idx)]] var<in> _tint_pulling_vertex_index : i32;
+[[binding(0), set(5)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+var<private> 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<f32>(_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<VertexPulling>();
+ 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<in> var_a : f32;
+[[location(1)]] var<in> var_b : f32;
+[[builtin(vertex_idx)]] var<in> custom_vertex_index : i32;
+[[builtin(instance_idx)]] var<in> 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::BuiltinDecoration>(ast::Builtin::kVertexIdx),
- }));
+ auto* expect = R"(
+[[block]]
+struct TintVertexData {
+ [[offset(0)]]
+ _tint_vertex_data : [[stride(4)]] array<u32>;
+};
- mod->AddGlobalVariable(
- Var("custom_instance_index", ast::StorageClass::kInput, ty.i32, nullptr,
- ast::VariableDecorationList{
- create<ast::BuiltinDecoration>(ast::Builtin::kInstanceIdx),
- }));
+[[binding(0), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+[[binding(1), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_1 : TintVertexData;
+var<private> var_a : f32;
+var<private> var_b : f32;
+[[builtin(vertex_idx)]] var<in> custom_vertex_index : i32;
+[[builtin(instance_idx)]] var<in> 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<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]);
+ _tint_pulling_pos = ((custom_instance_index * 4u) + 0u);
+ var_b = bitcast<f32>(_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<VertexPulling>();
+ 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<in> var_a : f32;
+[[location(1)]] var<in> var_b : array<f32, 4>;
- AddVertexInputVariable(0, "var_a", ty.f32);
- AddVertexInputVariable(1, "var_b", ty.array<f32, 4>());
+[[stage(vertex)]]
+fn main() -> void {}
+)";
- InitTransform(
+ auto* expect = R"(
+[[block]]
+struct TintVertexData {
+ [[offset(0)]]
+ _tint_vertex_data : [[stride(4)]] array<u32>;
+};
+
+[[builtin(vertex_idx)]] var<in> _tint_pulling_vertex_index : i32;
+[[binding(0), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+var<private> var_a : f32;
+var<private> var_b : array<f32, 4>;
+
+[[stage(vertex)]]
+fn main() -> void {
+ {
+ var _tint_pulling_pos : i32;
+ _tint_pulling_pos = ((_tint_pulling_vertex_index * 16u) + 0u);
+ var_a = bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[(_tint_pulling_pos / 4u)]);
+ _tint_pulling_pos = ((_tint_pulling_vertex_index * 16u) + 0u);
+ var_b = vec4<f32>(bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 8u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 12u) / 4u)]));
+ }
+}
+)";
+
+ auto transform = std::make_unique<VertexPulling>();
+ 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<f32, 2>());
- AddVertexInputVariable(1, "var_b", ty.array<f32, 3>());
- AddVertexInputVariable(2, "var_c", ty.array<f32, 4>());
+ auto* src = R"(
+[[location(0)]] var<in> var_a : array<f32, 2>;
+[[location(1)]] var<in> var_b : array<f32, 3>;
+[[location(2)]] var<in> var_c : array<f32, 4>;
- InitTransform(
+[[stage(vertex)]]
+fn main() -> void {}
+)";
+
+ auto* expect = R"(
+[[block]]
+struct TintVertexData {
+ [[offset(0)]]
+ _tint_vertex_data : [[stride(4)]] array<u32>;
+};
+
+[[builtin(vertex_idx)]] var<in> _tint_pulling_vertex_index : i32;
+[[binding(0), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_0 : TintVertexData;
+[[binding(1), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_1 : TintVertexData;
+[[binding(2), set(4)]] var<storage_buffer> _tint_pulling_vertex_buffer_2 : TintVertexData;
+var<private> var_a : array<f32, 2>;
+var<private> var_b : array<f32, 3>;
+var<private> var_c : array<f32, 4>;
+
+[[stage(vertex)]]
+fn main() -> void {
+ {
+ var _tint_pulling_pos : i32;
+ _tint_pulling_pos = ((_tint_pulling_vertex_index * 8u) + 0u);
+ var_a = vec2<f32>(bitcast<f32>(_tint_pulling_vertex_buffer_0._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast<f32>(_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<f32>(bitcast<f32>(_tint_pulling_vertex_buffer_1._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_1._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast<f32>(_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<f32>(bitcast<f32>(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 0u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 4u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 8u) / 4u)]), bitcast<f32>(_tint_pulling_vertex_buffer_2._tint_vertex_data[((_tint_pulling_pos + 12u) / 4u)]));
+ }
+}
+)";
+
+ auto transform = std::make_unique<VertexPulling>();
+ 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