From 36aa48ce36053a10993f6eae1ad1224b7a912abf Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 15 May 2023 20:26:43 +0000 Subject: [PATCH] [tint][ir] Clean up tests Remove the direct use of BuilderImpl from TestHelperBase to cut down the amount of internal state management required by the tests, and removing confusing conflation between the BuilderImpl and Builder. This change removes the following methods from TestHelperBase: * CreateBuilder() * InjectFlowBlock() * CreateEmptyBuilder() * FlowNodeForAstNode() Tests now just use FromProgram() function for testing AST -> IR. The downside to the black-box testing is that the per-method granularity of the unit testing increases to whole FromProgram() granularity. However, my personal opinion is that this is more than offset by the lack of state leakage from the implementation to the tests. Bug tint:1718 Change-Id: Iba2560e0fbcbd3dfb936694e50997d716f09fbd8 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132960 Kokoro: Ben Clayton Reviewed-by: Dan Sinclair Commit-Queue: Ben Clayton --- src/tint/ir/binary_test.cc | 100 ++-- src/tint/ir/bitcast_test.cc | 12 +- src/tint/ir/builder_impl.cc | 9 +- src/tint/ir/builder_impl_binary_test.cc | 466 +++++++++------- src/tint/ir/builder_impl_call_test.cc | 80 +-- src/tint/ir/builder_impl_literal_test.cc | 76 +-- src/tint/ir/builder_impl_materialize_test.cc | 7 +- src/tint/ir/builder_impl_store_test.cc | 7 +- src/tint/ir/builder_impl_test.cc | 533 ++++++++----------- src/tint/ir/builder_impl_unary_test.cc | 83 +-- src/tint/ir/builder_impl_var_test.cc | 28 +- src/tint/ir/constant_test.cc | 23 +- src/tint/ir/discard_test.cc | 5 +- src/tint/ir/module_test.cc | 1 + src/tint/ir/store_test.cc | 13 +- src/tint/ir/test_helper.h | 78 +-- src/tint/ir/unary_test.cc | 32 +- 17 files changed, 733 insertions(+), 820 deletions(-) diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc index 7baf0cd566..6705f63e1e 100644 --- a/src/tint/ir/binary_test.cc +++ b/src/tint/ir/binary_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/test_helper.h" @@ -23,10 +24,9 @@ using namespace tint::number_suffixes; // NOLINT using IR_InstructionTest = TestHelper; TEST_F(IR_InstructionTest, CreateAnd) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.And(b.builder.ir.types.Get(), b.builder.Constant(4_i), - b.builder.Constant(2_i)); + const auto* inst = b.And(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kAnd); @@ -45,10 +45,9 @@ TEST_F(IR_InstructionTest, CreateAnd) { } TEST_F(IR_InstructionTest, CreateOr) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Or(b.builder.ir.types.Get(), b.builder.Constant(4_i), - b.builder.Constant(2_i)); + const auto* inst = b.Or(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kOr); @@ -65,10 +64,9 @@ TEST_F(IR_InstructionTest, CreateOr) { } TEST_F(IR_InstructionTest, CreateXor) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Xor(b.builder.ir.types.Get(), b.builder.Constant(4_i), - b.builder.Constant(2_i)); + const auto* inst = b.Xor(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kXor); @@ -85,10 +83,9 @@ TEST_F(IR_InstructionTest, CreateXor) { } TEST_F(IR_InstructionTest, CreateEqual) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Equal(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.Equal(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kEqual); @@ -105,10 +102,9 @@ TEST_F(IR_InstructionTest, CreateEqual) { } TEST_F(IR_InstructionTest, CreateNotEqual) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.NotEqual(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.NotEqual(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kNotEqual); @@ -125,10 +121,9 @@ TEST_F(IR_InstructionTest, CreateNotEqual) { } TEST_F(IR_InstructionTest, CreateLessThan) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.LessThan(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.LessThan(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kLessThan); @@ -145,10 +140,10 @@ TEST_F(IR_InstructionTest, CreateLessThan) { } TEST_F(IR_InstructionTest, CreateGreaterThan) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.GreaterThan(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = + b.GreaterThan(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kGreaterThan); @@ -165,10 +160,10 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) { } TEST_F(IR_InstructionTest, CreateLessThanEqual) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.LessThanEqual(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = + b.LessThanEqual(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kLessThanEqual); @@ -185,10 +180,10 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) { } TEST_F(IR_InstructionTest, CreateGreaterThanEqual) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.GreaterThanEqual(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = + b.GreaterThanEqual(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kGreaterThanEqual); @@ -205,9 +200,8 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) { } TEST_F(IR_InstructionTest, CreateNot) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Not(b.builder.ir.types.Get(), b.builder.Constant(true)); + Builder b; + const auto* inst = b.Not(b.ir.types.Get(), b.Constant(true)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kEqual); @@ -224,10 +218,9 @@ TEST_F(IR_InstructionTest, CreateNot) { } TEST_F(IR_InstructionTest, CreateShiftLeft) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.ShiftLeft(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.ShiftLeft(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kShiftLeft); @@ -244,10 +237,9 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) { } TEST_F(IR_InstructionTest, CreateShiftRight) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.ShiftRight(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.ShiftRight(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kShiftRight); @@ -264,10 +256,9 @@ TEST_F(IR_InstructionTest, CreateShiftRight) { } TEST_F(IR_InstructionTest, CreateAdd) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Add(b.builder.ir.types.Get(), b.builder.Constant(4_i), - b.builder.Constant(2_i)); + const auto* inst = b.Add(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kAdd); @@ -284,10 +275,9 @@ TEST_F(IR_InstructionTest, CreateAdd) { } TEST_F(IR_InstructionTest, CreateSubtract) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Subtract(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.Subtract(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kSubtract); @@ -304,10 +294,9 @@ TEST_F(IR_InstructionTest, CreateSubtract) { } TEST_F(IR_InstructionTest, CreateMultiply) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Multiply(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.Multiply(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kMultiply); @@ -324,10 +313,9 @@ TEST_F(IR_InstructionTest, CreateMultiply) { } TEST_F(IR_InstructionTest, CreateDivide) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Divide(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.Divide(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kDivide); @@ -344,10 +332,9 @@ TEST_F(IR_InstructionTest, CreateDivide) { } TEST_F(IR_InstructionTest, CreateModulo) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Modulo(b.builder.ir.types.Get(), - b.builder.Constant(4_i), b.builder.Constant(2_i)); + const auto* inst = b.Modulo(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Binary::Kind::kModulo); @@ -364,9 +351,8 @@ TEST_F(IR_InstructionTest, CreateModulo) { } TEST_F(IR_InstructionTest, Binary_Usage) { - auto& b = CreateEmptyBuilder(); - const auto* inst = b.builder.And(b.builder.ir.types.Get(), b.builder.Constant(4_i), - b.builder.Constant(2_i)); + Builder b; + const auto* inst = b.And(b.ir.types.Get(), b.Constant(4_i), b.Constant(2_i)); EXPECT_EQ(inst->kind, Binary::Kind::kAnd); @@ -380,9 +366,9 @@ TEST_F(IR_InstructionTest, Binary_Usage) { } TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) { - auto& b = CreateEmptyBuilder(); - auto val = b.builder.Constant(4_i); - const auto* inst = b.builder.And(b.builder.ir.types.Get(), val, val); + Builder b; + auto val = b.Constant(4_i); + const auto* inst = b.And(b.ir.types.Get(), val, val); EXPECT_EQ(inst->kind, Binary::Kind::kAnd); ASSERT_EQ(inst->LHS(), inst->RHS()); diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc index dfe74613d4..0062deb60c 100644 --- a/src/tint/ir/bitcast_test.cc +++ b/src/tint/ir/bitcast_test.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" +#include "src/tint/ir/constant.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/test_helper.h" @@ -23,9 +25,8 @@ using namespace tint::number_suffixes; // NOLINT using IR_InstructionTest = TestHelper; TEST_F(IR_InstructionTest, Bitcast) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Bitcast(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + Builder b; + const auto* inst = b.Bitcast(b.ir.types.Get(), b.Constant(4_i)); ASSERT_TRUE(inst->Is()); ASSERT_NE(inst->Type(), nullptr); @@ -38,9 +39,8 @@ TEST_F(IR_InstructionTest, Bitcast) { } TEST_F(IR_InstructionTest, Bitcast_Usage) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Bitcast(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + Builder b; + const auto* inst = b.Bitcast(b.ir.types.Get(), b.Constant(4_i)); ASSERT_EQ(inst->args.Length(), 1u); ASSERT_NE(inst->args[0], nullptr); diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc index bf6a0e725f..4ac0c7c146 100644 --- a/src/tint/ir/builder_impl.cc +++ b/src/tint/ir/builder_impl.cc @@ -31,6 +31,7 @@ #include "src/tint/ast/const_assert.h" #include "src/tint/ast/continue_statement.h" #include "src/tint/ast/discard_statement.h" +#include "src/tint/ast/enable.h" #include "src/tint/ast/float_literal_expression.h" #include "src/tint/ast/for_loop_statement.h" #include "src/tint/ast/function.h" @@ -182,10 +183,10 @@ ResultType BuilderImpl::Build() { EmitVariable(var); }, [&](const ast::Function* func) { EmitFunction(func); }, - // [&](const ast::Enable*) { - // TODO(dsinclair): Implement? I think these need to be passed along so further stages - // know what is enabled. - // }, + [&](const ast::Enable*) { + // TODO(dsinclair): Implement? I think these need to be passed along so further + // stages know what is enabled. + }, [&](const ast::ConstAssert*) { // Evaluated by the resolver, drop from the IR. }, diff --git a/src/tint/ir/builder_impl_binary_test.cc b/src/tint/ir/builder_impl_binary_test.cc index 3be8405e09..334f6e5471 100644 --- a/src/tint/ir/builder_impl_binary_test.cc +++ b/src/tint/ir/builder_impl_binary_test.cc @@ -31,16 +31,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) { auto* expr = Add(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = add %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = add %1:u32, 4u )"); } @@ -49,11 +54,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundAdd) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kAdd); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -73,16 +77,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) { auto* expr = Sub(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = sub %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = sub %1:u32, 4u )"); } @@ -91,11 +100,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundSubtract) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kSubtract); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -115,16 +123,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) { auto* expr = Mul(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = mul %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = mul %1:u32, 4u )"); } @@ -133,11 +146,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundMultiply) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kMultiply); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -157,16 +169,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) { auto* expr = Div(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = div %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = div %1:u32, 4u )"); } @@ -175,11 +192,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundDiv) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kDivide); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -199,16 +215,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) { auto* expr = Mod(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = mod %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = mod %1:u32, 4u )"); } @@ -217,11 +238,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundModulo) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kModulo); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -241,16 +261,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) { auto* expr = And(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = and %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = and %1:u32, 4u )"); } @@ -259,11 +284,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundAnd) { auto* expr = CompoundAssign("v1", false, ast::BinaryOp::kAnd); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -283,16 +307,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) { auto* expr = Or(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = or %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = or %1:u32, 4u )"); } @@ -301,11 +330,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundOr) { auto* expr = CompoundAssign("v1", false, ast::BinaryOp::kOr); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -325,16 +353,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) { auto* expr = Xor(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = xor %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = xor %1:u32, 4u )"); } @@ -343,11 +376,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundXor) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kXor); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -367,11 +399,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) { auto* expr = LogicalAnd(Call("my_func"), false); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func my_func():bool + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():bool %fn2 = block ret true func_end @@ -402,11 +433,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) { auto* expr = LogicalOr(Call("my_func"), true); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func my_func():bool + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():bool %fn2 = block ret true func_end @@ -438,16 +468,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Equal) { auto* expr = Equal(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = eq %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = eq %1:u32, 4u )"); } @@ -456,16 +491,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) { auto* expr = NotEqual(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = neq %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = neq %1:u32, 4u )"); } @@ -474,16 +514,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) { auto* expr = LessThan(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = lt %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = lt %1:u32, 4u )"); } @@ -492,16 +537,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) { auto* expr = GreaterThan(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = gt %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = gt %1:u32, 4u )"); } @@ -510,16 +560,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) { auto* expr = LessThanEqual(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = lte %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = lte %1:u32, 4u )"); } @@ -528,16 +583,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) { auto* expr = GreaterThanEqual(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:bool = gte %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:bool = gte %1:u32, 4u )"); } @@ -546,16 +606,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) { auto* expr = Shl(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = shiftl %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = shiftl %1:u32, 4u )"); } @@ -564,11 +629,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundShiftLeft) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kShiftLeft); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -588,16 +652,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) { auto* expr = Shr(Call("my_func"), 4_u); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 0u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = shiftr %1:u32, 4u + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = shiftr %1:u32, 4u )"); } @@ -606,11 +675,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_CompoundShiftRight) { auto* expr = CompoundAssign("v1", 1_u, ast::BinaryOp::kShiftRight); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -632,11 +700,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) { GreaterThan(2.5_f, Div(Call("my_func"), Mul(2.3_f, Call("my_func"))))); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func my_func():f32 + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():f32 %fn2 = block ret 0.0f func_end @@ -674,11 +741,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound_WithConstEval) { GreaterThan(2.5_f, Div(10_f, Mul(2.3_f, 9.4_f))))); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func my_func():bool + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():bool %fn2 = block ret true func_end diff --git a/src/tint/ir/builder_impl_call_test.cc b/src/tint/ir/builder_impl_call_test.cc index 0fb070e2e8..be6228f362 100644 --- a/src/tint/ir/builder_impl_call_test.cc +++ b/src/tint/ir/builder_impl_call_test.cc @@ -32,16 +32,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) { auto* expr = Bitcast(Call("my_func")); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():f32 + %fn2 = block + ret 0.0f +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:f32 = call my_func + %tint_symbol:f32 = bitcast %1:f32 + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:f32 = call my_func -%2:f32 = bitcast %1:f32 )"); } @@ -52,14 +57,15 @@ TEST_F(IR_BuilderImplTest, EmitStatement_Discard) { create(ast::PipelineStage::kFragment), }); - auto& b = CreateBuilder(); - InjectFlowBlock(); - b.EmitStatement(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@fragment] + %fn2 = block + discard + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(discard )"); } @@ -68,16 +74,20 @@ TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) { auto* stmt = CallStmt(Call("my_func", Mul(2_a, 3_a))); WrapInFunction(stmt); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto& b = CreateBuilder(); + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():void + %fn2 = block + ret +func_end - InjectFlowBlock(); - b.EmitStatement(stmt); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:void = call my_func, 6.0f + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:void = call my_func, 6.0f )"); } @@ -86,12 +96,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Convert) { auto* expr = Call(ty.f32(), i); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %i:ref = var private, read_write, 1i @@ -109,12 +117,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_ConstructEmpty) { auto* expr = vec3(ty.f32()); GlobalVar("i", builtin::AddressSpace::kPrivate, expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %i:ref, read_write> = var private, read_write, vec3 0.0f @@ -127,12 +133,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Construct) { auto* expr = vec3(ty.f32(), 2_f, 3_f, i); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %i:ref = var private, read_write, 1.0f diff --git a/src/tint/ir/builder_impl_literal_test.cc b/src/tint/ir/builder_impl_literal_test.cc index 090f3f82eb..de5e81e681 100644 --- a/src/tint/ir/builder_impl_literal_test.cc +++ b/src/tint/ir/builder_impl_literal_test.cc @@ -18,10 +18,26 @@ #include "src/tint/ast/case_selector.h" #include "src/tint/ast/int_literal_expression.h" #include "src/tint/constant/scalar.h" +#include "src/tint/ir/block.h" +#include "src/tint/ir/constant.h" +#include "src/tint/ir/var.h" namespace tint::ir { namespace { +Value* GlobalVarInitializer(const Module& m) { + if (m.root_block->instructions.Length() == 0u) { + ADD_FAILURE() << "m.root_block has no instruction"; + return nullptr; + } + auto* var = m.root_block->instructions[0]->As(); + if (!var) { + ADD_FAILURE() << "m.root_block.instructions[0] was not a var"; + return nullptr; + } + return var->initializer; +} + using namespace tint::number_suffixes; // NOLINT using IR_BuilderImplTest = TestHelper; @@ -30,12 +46,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) { auto* expr = Expr(true); GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_TRUE(val->As>()->ValueAs()); } @@ -44,12 +60,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_False) { auto* expr = Expr(false); GlobalVar("a", ty.bool_(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_FALSE(val->As>()->ValueAs()); } @@ -58,12 +74,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F32) { auto* expr = Expr(1.2_f); GlobalVar("a", ty.f32(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_EQ(1.2_f, val->As>()->ValueAs()); } @@ -73,12 +89,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_F16) { auto* expr = Expr(1.2_h); GlobalVar("a", ty.f16(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_EQ(1.2_h, val->As>()->ValueAs()); } @@ -87,12 +103,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_I32) { auto* expr = Expr(-2_i); GlobalVar("a", ty.i32(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_EQ(-2_i, val->As>()->ValueAs()); } @@ -101,12 +117,12 @@ TEST_F(IR_BuilderImplTest, EmitLiteral_U32) { auto* expr = Expr(2_u); GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, expr); - auto& b = CreateBuilder(); - auto r = b.EmitLiteral(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_TRUE(r.Get()->Is()); - auto* val = r.Get()->As()->value; + auto* init = GlobalVarInitializer(m.Get()); + ASSERT_TRUE(Is(init)); + auto* val = init->As()->value; EXPECT_TRUE(val->Is>()); EXPECT_EQ(2_u, val->As>()->ValueAs()); } diff --git a/src/tint/ir/builder_impl_materialize_test.cc b/src/tint/ir/builder_impl_materialize_test.cc index 6b4ae843bf..36ef963fd3 100644 --- a/src/tint/ir/builder_impl_materialize_test.cc +++ b/src/tint/ir/builder_impl_materialize_test.cc @@ -31,11 +31,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_MaterializedCall) { Func("test_function", {}, ty.f32(), expr, utils::Empty); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func test_function():f32 + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():f32 %fn2 = block ret 2.0f func_end diff --git a/src/tint/ir/builder_impl_store_test.cc b/src/tint/ir/builder_impl_store_test.cc index 82fbc0a45f..b69badd7c8 100644 --- a/src/tint/ir/builder_impl_store_test.cc +++ b/src/tint/ir/builder_impl_store_test.cc @@ -32,11 +32,10 @@ TEST_F(IR_BuilderImplTest, EmitStatement_Assign) { auto* expr = Assign("a", 4_u); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %a:ref = var private, read_write diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc index 36eb3b6211..814925ebd0 100644 --- a/src/tint/ir/builder_impl_test.cc +++ b/src/tint/ir/builder_impl_test.cc @@ -1,4 +1,4 @@ -// Copyright 2022 The Tint Authors. +// Copyright 2023 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. @@ -18,31 +18,59 @@ #include "src/tint/ast/case_selector.h" #include "src/tint/ast/int_literal_expression.h" #include "src/tint/constant/scalar.h" +#include "src/tint/ir/block.h" +#include "src/tint/ir/function_terminator.h" +#include "src/tint/ir/if.h" +#include "src/tint/ir/loop.h" +#include "src/tint/ir/switch.h" namespace tint::ir { namespace { +/// Looks for the flow node with the given type T. +/// If no flow node is found, then nullptr is returned. +/// If multiple flow nodes are found with the type T, then an error is raised and the first is +/// returned. +template +const T* FindSingleFlowNode(const Module& mod) { + const T* found = nullptr; + size_t count = 0; + for (auto* node : mod.flow_nodes.Objects()) { + if (auto* as = node->As()) { + count++; + if (!found) { + found = as; + } + } + } + if (count > 1) { + ADD_FAILURE() << "FindSingleFlowNode() found " << count << " nodes of type " + << utils::TypeInfo::Of().name; + } + return found; +} + using namespace tint::number_suffixes; // NOLINT using IR_BuilderImplTest = TestHelper; TEST_F(IR_BuilderImplTest, Func) { Func("f", utils::Empty, ty.void_(), utils::Empty); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); - ASSERT_EQ(0u, m.entry_points.Length()); - ASSERT_EQ(1u, m.functions.Length()); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* f = m.functions[0]; + ASSERT_EQ(0u, m->entry_points.Length()); + ASSERT_EQ(1u, m->functions.Length()); + + auto* f = m->functions[0]; ASSERT_NE(f->start_target, nullptr); ASSERT_NE(f->end_target, nullptr); EXPECT_EQ(1u, f->start_target->inbound_branches.Length()); EXPECT_EQ(1u, f->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), R"(%fn1 = func f():void + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func f():void %fn2 = block ret func_end @@ -53,33 +81,28 @@ func_end TEST_F(IR_BuilderImplTest, EntryPoint) { Func("f", utils::Empty, ty.void_(), utils::Empty, utils::Vector{Stage(ast::PipelineStage::kFragment)}); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); - ASSERT_EQ(1u, m.entry_points.Length()); - EXPECT_EQ(m.functions[0], m.entry_points[0]); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + ASSERT_EQ(1u, m->entry_points.Length()); + EXPECT_EQ(m->functions[0], m->entry_points[0]); } TEST_F(IR_BuilderImplTest, IfStatement) { auto* ast_if = If(true, Block(), Else(Block())); WrapInFunction(ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - EXPECT_TRUE(ir_if->Is()); - - auto* flow = ir_if->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->true_.target, nullptr); ASSERT_NE(flow->false_.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); @@ -88,7 +111,7 @@ TEST_F(IR_BuilderImplTest, IfStatement) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -114,21 +137,16 @@ TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) { auto* ast_if = If(true, Block(Return())); WrapInFunction(ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - EXPECT_TRUE(ir_if->Is()); - - auto* flow = ir_if->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->true_.target, nullptr); ASSERT_NE(flow->false_.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); @@ -137,7 +155,7 @@ TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -162,21 +180,16 @@ TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) { auto* ast_if = If(true, Block(), Else(Block(Return()))); WrapInFunction(ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - EXPECT_TRUE(ir_if->Is()); - - auto* flow = ir_if->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->true_.target, nullptr); ASSERT_NE(flow->false_.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); @@ -185,7 +198,7 @@ TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -210,21 +223,16 @@ TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) { auto* ast_if = If(true, Block(Return()), Else(Block(Return()))); WrapInFunction(ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - EXPECT_TRUE(ir_if->Is()); - - auto* flow = ir_if->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->true_.target, nullptr); ASSERT_NE(flow->false_.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); @@ -233,7 +241,7 @@ TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -255,29 +263,21 @@ TEST_F(IR_BuilderImplTest, IfStatement_JumpChainToMerge) { auto* ast_if = If(true, Block(ast_loop)); WrapInFunction(ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - EXPECT_TRUE(ir_if->Is()); - - auto* if_flow = ir_if->As(); + auto* if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(if_flow->true_.target, nullptr); ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); + ASSERT_NE(loop_flow, nullptr); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -312,21 +312,16 @@ TEST_F(IR_BuilderImplTest, Loop_WithBreak) { auto* ast_loop = Loop(Block(Break())); WrapInFunction(ast_loop); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* flow = ir_loop->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->start.target, nullptr); ASSERT_NE(flow->continuing.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); @@ -335,7 +330,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithBreak) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -358,30 +353,21 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinue) { auto* ast_loop = Loop(Block(ast_if, Continue())); WrapInFunction(ast_loop); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - ASSERT_TRUE(ir_if->Is()); - - auto* if_flow = ir_if->As(); + auto* if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(if_flow->true_.target, nullptr); ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -394,7 +380,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinue) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -434,30 +420,21 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) { auto* ast_loop = Loop(Block(), Block(ast_break_if)); WrapInFunction(ast_loop); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - auto* ir_break_if = FlowNodeForAstNode(ast_break_if); - ASSERT_NE(ir_break_if, nullptr); - ASSERT_TRUE(ir_break_if->Is()); - - auto* break_if_flow = ir_break_if->As(); + auto* break_if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(break_if_flow->true_.target, nullptr); ASSERT_NE(break_if_flow->false_.target, nullptr); ASSERT_NE(break_if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -470,7 +447,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -510,30 +487,21 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) { auto* ast_loop = Loop(Block(ast_if, Continue())); WrapInFunction(ast_loop); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - ASSERT_TRUE(ir_if->Is()); - - auto* if_flow = ir_if->As(); + auto* if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(if_flow->true_.target, nullptr); ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -546,7 +514,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -581,21 +549,16 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) { auto* ast_loop = Loop(Block(Return(), Continue())); WrapInFunction(ast_loop, If(true, Block(Return()))); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -604,7 +567,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -631,33 +594,21 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) { auto* ast_if = If(true, Block(Return())); WrapInFunction(Block(ast_loop, ast_if)); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - auto* ir_if = FlowNodeForAstNode(ast_if); - EXPECT_EQ(ir_if, nullptr); - - auto* ir_break_if = FlowNodeForAstNode(ast_break_if); - ASSERT_NE(ir_break_if, nullptr); - EXPECT_TRUE(ir_break_if->Is()); - - auto* break_if_flow = ir_break_if->As(); + auto* break_if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(break_if_flow->true_.target, nullptr); ASSERT_NE(break_if_flow->false_.target, nullptr); ASSERT_NE(break_if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -667,7 +618,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) { // This is 1 because only the loop branch happens. The subsequent if return is dead code. EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -686,30 +637,21 @@ TEST_F(IR_BuilderImplTest, Loop_WithIf_BothBranchesBreak) { auto* ast_loop = Loop(Block(ast_if, Continue())); WrapInFunction(ast_loop); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop = FlowNodeForAstNode(ast_loop); - ASSERT_NE(ir_loop, nullptr); - EXPECT_TRUE(ir_loop->Is()); - - auto* loop_flow = ir_loop->As(); + auto* loop_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(loop_flow->start.target, nullptr); ASSERT_NE(loop_flow->continuing.target, nullptr); ASSERT_NE(loop_flow->merge.target, nullptr); - auto* ir_if = FlowNodeForAstNode(ast_if); - ASSERT_NE(ir_if, nullptr); - ASSERT_TRUE(ir_if->Is()); - - auto* if_flow = ir_if->As(); + auto* if_flow = FindSingleFlowNode(m.Get()); ASSERT_NE(if_flow->true_.target, nullptr); ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); @@ -722,7 +664,7 @@ TEST_F(IR_BuilderImplTest, Loop_WithIf_BothBranchesBreak) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -763,76 +705,68 @@ TEST_F(IR_BuilderImplTest, Loop_Nested) { WrapInFunction(ast_loop_a); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_loop_a = FlowNodeForAstNode(ast_loop_a); - ASSERT_NE(ir_loop_a, nullptr); - EXPECT_TRUE(ir_loop_a->Is()); - auto* loop_flow_a = ir_loop_a->As(); + ASSERT_EQ(1u, m->functions.Length()); + + auto block_exit = [&](const ir::FlowNode* node) -> const ir::FlowNode* { + if (auto* block = As(node)) { + return block->branch.target; + } + return nullptr; + }; + + auto* loop_flow_a = As(m->functions[0]->start_target->branch.target); + ASSERT_NE(loop_flow_a, nullptr); ASSERT_NE(loop_flow_a->start.target, nullptr); ASSERT_NE(loop_flow_a->continuing.target, nullptr); ASSERT_NE(loop_flow_a->merge.target, nullptr); - auto* ir_loop_b = FlowNodeForAstNode(ast_loop_b); - ASSERT_NE(ir_loop_b, nullptr); - EXPECT_TRUE(ir_loop_b->Is()); - auto* loop_flow_b = ir_loop_b->As(); + auto* loop_flow_b = As(block_exit(loop_flow_a->start.target)); + ASSERT_NE(loop_flow_b, nullptr); ASSERT_NE(loop_flow_b->start.target, nullptr); ASSERT_NE(loop_flow_b->continuing.target, nullptr); ASSERT_NE(loop_flow_b->merge.target, nullptr); - auto* ir_loop_c = FlowNodeForAstNode(ast_loop_c); - ASSERT_NE(ir_loop_c, nullptr); - EXPECT_TRUE(ir_loop_c->Is()); - auto* loop_flow_c = ir_loop_c->As(); - ASSERT_NE(loop_flow_c->start.target, nullptr); - ASSERT_NE(loop_flow_c->continuing.target, nullptr); - ASSERT_NE(loop_flow_c->merge.target, nullptr); - - auto* ir_loop_d = FlowNodeForAstNode(ast_loop_d); - ASSERT_NE(ir_loop_d, nullptr); - EXPECT_TRUE(ir_loop_d->Is()); - auto* loop_flow_d = ir_loop_d->As(); - ASSERT_NE(loop_flow_d->start.target, nullptr); - ASSERT_NE(loop_flow_d->continuing.target, nullptr); - ASSERT_NE(loop_flow_d->merge.target, nullptr); - - auto* ir_if_a = FlowNodeForAstNode(ast_if_a); - ASSERT_NE(ir_if_a, nullptr); - EXPECT_TRUE(ir_if_a->Is()); - auto* if_flow_a = ir_if_a->As(); + auto* if_flow_a = As(block_exit(loop_flow_b->start.target)); + ASSERT_NE(if_flow_a, nullptr); ASSERT_NE(if_flow_a->true_.target, nullptr); ASSERT_NE(if_flow_a->false_.target, nullptr); ASSERT_NE(if_flow_a->merge.target, nullptr); - auto* ir_if_b = FlowNodeForAstNode(ast_if_b); - ASSERT_NE(ir_if_b, nullptr); - EXPECT_TRUE(ir_if_b->Is()); - auto* if_flow_b = ir_if_b->As(); + auto* if_flow_b = As(block_exit(if_flow_a->merge.target)); + ASSERT_NE(if_flow_b, nullptr); ASSERT_NE(if_flow_b->true_.target, nullptr); ASSERT_NE(if_flow_b->false_.target, nullptr); ASSERT_NE(if_flow_b->merge.target, nullptr); - auto* ir_if_c = FlowNodeForAstNode(ast_if_c); - ASSERT_NE(ir_if_c, nullptr); - EXPECT_TRUE(ir_if_c->Is()); - auto* if_flow_c = ir_if_c->As(); + auto* loop_flow_c = As(block_exit(loop_flow_b->continuing.target)); + ASSERT_NE(loop_flow_c, nullptr); + ASSERT_NE(loop_flow_c->start.target, nullptr); + ASSERT_NE(loop_flow_c->continuing.target, nullptr); + ASSERT_NE(loop_flow_c->merge.target, nullptr); + + auto* loop_flow_d = As(block_exit(loop_flow_c->merge.target)); + ASSERT_NE(loop_flow_d, nullptr); + ASSERT_NE(loop_flow_d->start.target, nullptr); + ASSERT_NE(loop_flow_d->continuing.target, nullptr); + ASSERT_NE(loop_flow_d->merge.target, nullptr); + + auto* if_flow_c = As(block_exit(loop_flow_d->continuing.target)); + ASSERT_NE(if_flow_c, nullptr); ASSERT_NE(if_flow_c->true_.target, nullptr); ASSERT_NE(if_flow_c->false_.target, nullptr); ASSERT_NE(if_flow_c->merge.target, nullptr); - auto* ir_if_d = FlowNodeForAstNode(ast_if_d); - ASSERT_NE(ir_if_d, nullptr); - EXPECT_TRUE(ir_if_d->Is()); - auto* if_flow_d = ir_if_d->As(); + auto* if_flow_d = As(block_exit(loop_flow_b->merge.target)); + ASSERT_NE(if_flow_d, nullptr); ASSERT_NE(if_flow_d->true_.target, nullptr); ASSERT_NE(if_flow_d->false_.target, nullptr); ASSERT_NE(if_flow_d->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, loop_flow_a->inbound_branches.Length()); EXPECT_EQ(2u, loop_flow_a->start.target->inbound_branches.Length()); @@ -869,7 +803,7 @@ TEST_F(IR_BuilderImplTest, Loop_Nested) { EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -982,15 +916,10 @@ TEST_F(IR_BuilderImplTest, While) { auto* ast_while = While(false, Block()); WrapInFunction(ast_while); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_while = FlowNodeForAstNode(ast_while); - ASSERT_NE(ir_while, nullptr); - ASSERT_TRUE(ir_while->Is()); - - auto* flow = ir_while->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->start.target, nullptr); ASSERT_NE(flow->continuing.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); @@ -1002,8 +931,8 @@ TEST_F(IR_BuilderImplTest, While) { ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); @@ -1014,7 +943,7 @@ TEST_F(IR_BuilderImplTest, While) { EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1053,15 +982,10 @@ TEST_F(IR_BuilderImplTest, While_Return) { auto* ast_while = While(true, Block(Return())); WrapInFunction(ast_while); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_while = FlowNodeForAstNode(ast_while); - ASSERT_NE(ir_while, nullptr); - ASSERT_TRUE(ir_while->Is()); - - auto* flow = ir_while->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->start.target, nullptr); ASSERT_NE(flow->continuing.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); @@ -1073,8 +997,8 @@ TEST_F(IR_BuilderImplTest, While_Return) { ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); @@ -1085,7 +1009,7 @@ TEST_F(IR_BuilderImplTest, While_Return) { EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1132,15 +1056,10 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) { auto* ast_for = For(Decl(Var("i", ty.i32())), LessThan("i", 10_a), Increment("i"), Block()); WrapInFunction(ast_for); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_for = FlowNodeForAstNode(ast_for); - ASSERT_NE(ir_for, nullptr); - ASSERT_TRUE(ir_for->Is()); - - auto* flow = ir_for->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->start.target, nullptr); ASSERT_NE(flow->continuing.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); @@ -1152,8 +1071,8 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) { ASSERT_NE(if_flow->false_.target, nullptr); ASSERT_NE(if_flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); @@ -1164,28 +1083,23 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) { EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), R"()"); + EXPECT_EQ(Disassemble(m.Get()), R"()"); } TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) { auto* ast_for = For(nullptr, nullptr, nullptr, Block(Break())); WrapInFunction(ast_for); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_for = FlowNodeForAstNode(ast_for); - ASSERT_NE(ir_for, nullptr); - ASSERT_TRUE(ir_for->Is()); - - auto* flow = ir_for->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->start.target, nullptr); ASSERT_NE(flow->continuing.target, nullptr); ASSERT_NE(flow->merge.target, nullptr); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; EXPECT_EQ(1u, flow->inbound_branches.Length()); EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); @@ -1193,7 +1107,7 @@ TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) { EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1218,20 +1132,15 @@ TEST_F(IR_BuilderImplTest, Switch) { WrapInFunction(ast_switch); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_switch = FlowNodeForAstNode(ast_switch); - ASSERT_NE(ir_switch, nullptr); - ASSERT_TRUE(ir_switch->Is()); - - auto* flow = ir_switch->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(3u, flow->cases.Length()); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; ASSERT_EQ(1u, flow->cases[0].selectors.Length()); ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is>()); @@ -1253,7 +1162,7 @@ TEST_F(IR_BuilderImplTest, Switch) { EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1287,20 +1196,15 @@ TEST_F(IR_BuilderImplTest, Switch_MultiSelector) { WrapInFunction(ast_switch); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_switch = FlowNodeForAstNode(ast_switch); - ASSERT_NE(ir_switch, nullptr); - ASSERT_TRUE(ir_switch->Is()); - - auto* flow = ir_switch->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(1u, flow->cases.Length()); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; ASSERT_EQ(3u, flow->cases[0].selectors.Length()); ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is>()); @@ -1318,7 +1222,7 @@ TEST_F(IR_BuilderImplTest, Switch_MultiSelector) { EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1340,20 +1244,15 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) { auto* ast_switch = Switch(1_i, utils::Vector{DefaultCase(Block())}); WrapInFunction(ast_switch); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_switch = FlowNodeForAstNode(ast_switch); - ASSERT_NE(ir_switch, nullptr); - ASSERT_TRUE(ir_switch->Is()); - - auto* flow = ir_switch->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(1u, flow->cases.Length()); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; ASSERT_EQ(1u, flow->cases[0].selectors.Length()); EXPECT_TRUE(flow->cases[0].selectors[0].IsDefault()); @@ -1363,7 +1262,7 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) { EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1387,20 +1286,15 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) { DefaultCase(Block())}); WrapInFunction(ast_switch); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - auto* ir_switch = FlowNodeForAstNode(ast_switch); - ASSERT_NE(ir_switch, nullptr); - ASSERT_TRUE(ir_switch->Is()); - - auto* flow = ir_switch->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(2u, flow->cases.Length()); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; ASSERT_EQ(1u, flow->cases[0].selectors.Length()); ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is>()); @@ -1417,7 +1311,7 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) { // This is 1 because the if is dead-code eliminated and the return doesn't happen. EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 @@ -1446,22 +1340,17 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) { auto* ast_if = If(true, Block(Return())); WrapInFunction(ast_switch, ast_if); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - ASSERT_EQ(FlowNodeForAstNode(ast_if), nullptr); + ASSERT_EQ(FindSingleFlowNode(m.Get()), nullptr); - auto* ir_switch = FlowNodeForAstNode(ast_switch); - ASSERT_NE(ir_switch, nullptr); - ASSERT_TRUE(ir_switch->Is()); - - auto* flow = ir_switch->As(); + auto* flow = FindSingleFlowNode(m.Get()); ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(2u, flow->cases.Length()); - ASSERT_EQ(1u, m.functions.Length()); - auto* func = m.functions[0]; + ASSERT_EQ(1u, m->functions.Length()); + auto* func = m->functions[0]; ASSERT_EQ(1u, flow->cases[0].selectors.Length()); ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is>()); @@ -1477,7 +1366,7 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) { EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block branch %fn3 diff --git a/src/tint/ir/builder_impl_unary_test.cc b/src/tint/ir/builder_impl_unary_test.cc index 2323acbe0d..f72a4dc31d 100644 --- a/src/tint/ir/builder_impl_unary_test.cc +++ b/src/tint/ir/builder_impl_unary_test.cc @@ -31,16 +31,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Unary_Not) { auto* expr = Not(Call("my_func")); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():bool + %fn2 = block + ret false +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:bool = call my_func + %tint_symbol:bool = eq %1:bool, false + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:bool = call my_func -%2:bool = eq %1:bool, false )"); } @@ -49,16 +54,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Unary_Complement) { auto* expr = Complement(Call("my_func")); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():u32 + %fn2 = block + ret 1u +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:u32 = call my_func + %tint_symbol:u32 = complement %1:u32 + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:u32 = call my_func -%2:u32 = complement %1:u32 )"); } @@ -67,16 +77,21 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Unary_Negation) { auto* expr = Negation(Call("my_func")); WrapInFunction(expr); - auto& b = CreateBuilder(); - InjectFlowBlock(); - auto r = b.EmitExpression(expr); - ASSERT_THAT(b.Diagnostics(), testing::IsEmpty()); - ASSERT_TRUE(r); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); + + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func my_func():i32 + %fn2 = block + ret 1i +func_end + +%fn3 = func test_function():void [@compute @workgroup_size(1, 1, 1)] + %fn4 = block + %1:i32 = call my_func + %tint_symbol:i32 = negation %1:i32 + ret +func_end - Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block->As()); - EXPECT_EQ(d.AsString(), R"(%1:i32 = call my_func -%2:i32 = negation %1:i32 )"); } @@ -86,11 +101,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Unary_AddressOf) { auto* expr = Decl(Let("v2", AddressOf("v1"))); WrapInFunction(expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write @@ -112,11 +126,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Unary_Indirection) { }; WrapInFunction(stmts); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %v1:ref = var private, read_write diff --git a/src/tint/ir/builder_impl_var_test.cc b/src/tint/ir/builder_impl_var_test.cc index a3f4d27fee..f8d0eae155 100644 --- a/src/tint/ir/builder_impl_var_test.cc +++ b/src/tint/ir/builder_impl_var_test.cc @@ -29,11 +29,10 @@ using IR_BuilderImplTest = TestHelper; TEST_F(IR_BuilderImplTest, Emit_GlobalVar_NoInit) { GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %a:ref = var private, read_write @@ -45,11 +44,10 @@ TEST_F(IR_BuilderImplTest, Emit_GlobalVar_Init) { auto* expr = Expr(2_u); GlobalVar("a", ty.u32(), builtin::AddressSpace::kPrivate, expr); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), R"(%fn1 = block + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = block %a:ref = var private, read_write, 2u @@ -61,11 +59,10 @@ TEST_F(IR_BuilderImplTest, Emit_Var_NoInit) { auto* a = Var("a", ty.u32(), builtin::AddressSpace::kFunction); WrapInFunction(a); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block %a:ref = var function, read_write @@ -80,11 +77,10 @@ TEST_F(IR_BuilderImplTest, Emit_Var_Init) { auto* a = Var("a", ty.u32(), builtin::AddressSpace::kFunction, expr); WrapInFunction(a); - auto r = Build(); - ASSERT_TRUE(r) << Error(); - auto m = r.Move(); + auto m = Build(); + ASSERT_TRUE(m) << (!m ? m.Failure() : ""); - EXPECT_EQ(Disassemble(m), + EXPECT_EQ(Disassemble(m.Get()), R"(%fn1 = func test_function():void [@compute @workgroup_size(1, 1, 1)] %fn2 = block %a:ref = var function, read_write, 2u diff --git a/src/tint/ir/constant_test.cc b/src/tint/ir/constant_test.cc index c550763502..f5641efc7a 100644 --- a/src/tint/ir/constant_test.cc +++ b/src/tint/ir/constant_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" #include "src/tint/ir/test_helper.h" #include "src/tint/ir/value.h" @@ -23,11 +24,11 @@ using namespace tint::number_suffixes; // NOLINT using IR_ConstantTest = TestHelper; TEST_F(IR_ConstantTest, f32) { - auto& b = CreateEmptyBuilder(); + Builder b; utils::StringStream str; - auto* c = b.builder.Constant(1.2_f); + auto* c = b.Constant(1.2_f); EXPECT_EQ(1.2_f, c->value->As>()->ValueAs()); EXPECT_TRUE(c->value->Is>()); @@ -38,11 +39,11 @@ TEST_F(IR_ConstantTest, f32) { } TEST_F(IR_ConstantTest, f16) { - auto& b = CreateEmptyBuilder(); + Builder b; utils::StringStream str; - auto* c = b.builder.Constant(1.1_h); + auto* c = b.Constant(1.1_h); EXPECT_EQ(1.1_h, c->value->As>()->ValueAs()); EXPECT_FALSE(c->value->Is>()); @@ -53,11 +54,11 @@ TEST_F(IR_ConstantTest, f16) { } TEST_F(IR_ConstantTest, i32) { - auto& b = CreateEmptyBuilder(); + Builder b; utils::StringStream str; - auto* c = b.builder.Constant(1_i); + auto* c = b.Constant(1_i); EXPECT_EQ(1_i, c->value->As>()->ValueAs()); EXPECT_FALSE(c->value->Is>()); @@ -68,11 +69,11 @@ TEST_F(IR_ConstantTest, i32) { } TEST_F(IR_ConstantTest, u32) { - auto& b = CreateEmptyBuilder(); + Builder b; utils::StringStream str; - auto* c = b.builder.Constant(2_u); + auto* c = b.Constant(2_u); EXPECT_EQ(2_u, c->value->As>()->ValueAs()); EXPECT_FALSE(c->value->Is>()); @@ -83,18 +84,18 @@ TEST_F(IR_ConstantTest, u32) { } TEST_F(IR_ConstantTest, bool) { - auto& b = CreateEmptyBuilder(); + Builder b; { utils::StringStream str; - auto* c = b.builder.Constant(false); + auto* c = b.Constant(false); EXPECT_FALSE(c->value->As>()->ValueAs()); } { utils::StringStream str; - auto c = b.builder.Constant(true); + auto c = b.Constant(true); EXPECT_TRUE(c->value->As>()->ValueAs()); EXPECT_FALSE(c->value->Is>()); diff --git a/src/tint/ir/discard_test.cc b/src/tint/ir/discard_test.cc index b1bf8c232d..942f02c78a 100644 --- a/src/tint/ir/discard_test.cc +++ b/src/tint/ir/discard_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/test_helper.h" @@ -21,9 +22,9 @@ namespace { using IR_InstructionTest = TestHelper; TEST_F(IR_InstructionTest, Discard) { - auto& b = CreateEmptyBuilder(); + Builder b; - const auto* inst = b.builder.Discard(); + const auto* inst = b.Discard(); ASSERT_TRUE(inst->Is()); } diff --git a/src/tint/ir/module_test.cc b/src/tint/ir/module_test.cc index 15d5cb18d4..c9b11500ce 100644 --- a/src/tint/ir/module_test.cc +++ b/src/tint/ir/module_test.cc @@ -14,6 +14,7 @@ #include "src/tint/ir/module.h" #include "src/tint/ir/test_helper.h" +#include "src/tint/ir/var.h" namespace tint::ir { namespace { diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc index 0005c800c5..8288b9a3cc 100644 --- a/src/tint/ir/store_test.cc +++ b/src/tint/ir/store_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/test_helper.h" @@ -23,12 +24,12 @@ using namespace tint::number_suffixes; // NOLINT using IR_InstructionTest = TestHelper; TEST_F(IR_InstructionTest, CreateStore) { - auto& b = CreateEmptyBuilder(); + Builder b; // TODO(dsinclair): This is wrong, but we don't have anything correct to store too at the // moment. - auto* to = b.builder.Discard(); - const auto* inst = b.builder.Store(to, b.builder.Constant(4_i)); + auto* to = b.Discard(); + const auto* inst = b.Store(to, b.Constant(4_i)); ASSERT_TRUE(inst->Is()); ASSERT_EQ(inst->to, to); @@ -40,10 +41,10 @@ TEST_F(IR_InstructionTest, CreateStore) { } TEST_F(IR_InstructionTest, Store_Usage) { - auto& b = CreateEmptyBuilder(); + Builder b; - auto* to = b.builder.Discard(); - const auto* inst = b.builder.Store(to, b.builder.Constant(4_i)); + auto* to = b.Discard(); + const auto* inst = b.Store(to, b.Constant(4_i)); ASSERT_NE(inst->to, nullptr); ASSERT_EQ(inst->to->Usage().Length(), 1u); diff --git a/src/tint/ir/test_helper.h b/src/tint/ir/test_helper.h index d8568c2abb..d9055cee86 100644 --- a/src/tint/ir/test_helper.h +++ b/src/tint/ir/test_helper.h @@ -20,8 +20,8 @@ #include #include "gtest/gtest.h" -#include "src/tint/ir/builder_impl.h" #include "src/tint/ir/disassembler.h" +#include "src/tint/ir/from_program.h" #include "src/tint/number.h" #include "src/tint/program_builder.h" #include "src/tint/utils/string_stream.h" @@ -36,84 +36,28 @@ class TestHelperBase : public BASE, public ProgramBuilder { ~TestHelperBase() override = default; - /// Builds and returns a BuilderImpl from the program. - /// @note The builder is only created once. Multiple calls to Build() will - /// return the same builder without rebuilding. - /// @return the builder - BuilderImpl& CreateBuilder() { - SetResolveOnBuild(true); - - if (gen_) { - return *gen_; - } - diag::Formatter formatter; - - program_ = std::make_unique(std::move(*this)); - [&]() { ASSERT_TRUE(program_->IsValid()) << formatter.format(program_->Diagnostics()); }(); - gen_ = std::make_unique(program_.get()); - return *gen_; - } - - /// Injects a flow block into the builder - /// @returns the injected block - ir::Block* InjectFlowBlock() { - auto* block = gen_->builder.CreateBlock(); - gen_->current_flow_block = block; - return block; - } - - /// Creates a BuilderImpl without an originating program. This is used for testing the - /// expressions which don't require the full builder implementation. The current flow block - /// is initialized with an empty block. - /// @returns the BuilderImpl for testing. - BuilderImpl& CreateEmptyBuilder() { - program_ = std::make_unique(); - gen_ = std::make_unique(program_.get()); - gen_->current_flow_block = gen_->builder.CreateBlock(); - return *gen_; - } - /// Build the module, cleaning up the program before returning. /// @returns the generated module - utils::Result Build() { - auto& b = CreateBuilder(); - auto m = b.Build(); + utils::Result Build() { + SetResolveOnBuild(true); - // Store the error away in case we need it - error_ = b.Diagnostics().str(); + auto program = std::make_unique(std::move(*this)); + [&]() { + diag::Formatter formatter; + ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); + }(); - // Explicitly remove program to guard against pointers back to ast. Note, this does mean the - // BuilderImpl is pointing to an invalid program. We keep the BuilderImpl around because we - // need to be able to map from ast pointers to flow nodes in tests. - program_ = nullptr; - return m; - } - - /// @param node the ast node to lookup - /// @returns the IR flow node for the given ast node. - const ir::FlowNode* FlowNodeForAstNode(const ast::Node* node) const { - return gen_->FlowNodeForAstNode(node); + return FromProgram(program.get()); } /// @param mod the module /// @returns the disassembly string of the module - std::string Disassemble(Module& mod) const { + std::string Disassemble(const Module& mod) const { Disassembler d(mod); return d.Disassemble(); } - - /// @returns the error generated during build, if any - std::string Error() const { return error_; } - - private: - std::unique_ptr gen_; - - /// The program built with a call to Build() - std::unique_ptr program_; - - /// Error generated when calling `Build` - std::string error_; }; + using TestHelper = TestHelperBase; template diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc index 86a3993f5b..198dc9ed8c 100644 --- a/src/tint/ir/unary_test.cc +++ b/src/tint/ir/unary_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/tint/ir/builder.h" #include "src/tint/ir/instruction.h" #include "src/tint/ir/test_helper.h" @@ -23,14 +24,13 @@ using namespace tint::number_suffixes; // NOLINT using IR_InstructionTest = TestHelper; TEST_F(IR_InstructionTest, CreateAddressOf) { - auto& b = CreateEmptyBuilder(); + Builder b; // TODO(dsinclair): This would be better as an identifier, but works for now. - const auto* inst = - b.builder.AddressOf(b.builder.ir.types.Get( - b.builder.ir.types.Get(), - builtin::AddressSpace::kPrivate, builtin::Access::kReadWrite), - b.builder.Constant(4_i)); + const auto* inst = b.AddressOf( + b.ir.types.Get(b.ir.types.Get(), builtin::AddressSpace::kPrivate, + builtin::Access::kReadWrite), + b.Constant(4_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Unary::Kind::kAddressOf); @@ -44,9 +44,8 @@ TEST_F(IR_InstructionTest, CreateAddressOf) { } TEST_F(IR_InstructionTest, CreateComplement) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Complement(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + Builder b; + const auto* inst = b.Complement(b.ir.types.Get(), b.Constant(4_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Unary::Kind::kComplement); @@ -58,11 +57,10 @@ TEST_F(IR_InstructionTest, CreateComplement) { } TEST_F(IR_InstructionTest, CreateIndirection) { - auto& b = CreateEmptyBuilder(); + Builder b; // TODO(dsinclair): This would be better as an identifier, but works for now. - const auto* inst = - b.builder.Indirection(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + const auto* inst = b.Indirection(b.ir.types.Get(), b.Constant(4_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Unary::Kind::kIndirection); @@ -74,9 +72,8 @@ TEST_F(IR_InstructionTest, CreateIndirection) { } TEST_F(IR_InstructionTest, CreateNegation) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Negation(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + Builder b; + const auto* inst = b.Negation(b.ir.types.Get(), b.Constant(4_i)); ASSERT_TRUE(inst->Is()); EXPECT_EQ(inst->kind, Unary::Kind::kNegation); @@ -88,9 +85,8 @@ TEST_F(IR_InstructionTest, CreateNegation) { } TEST_F(IR_InstructionTest, Unary_Usage) { - auto& b = CreateEmptyBuilder(); - const auto* inst = - b.builder.Negation(b.builder.ir.types.Get(), b.builder.Constant(4_i)); + Builder b; + const auto* inst = b.Negation(b.ir.types.Get(), b.Constant(4_i)); EXPECT_EQ(inst->kind, Unary::Kind::kNegation);