diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h index ac9028bfb0..02e81a517d 100644 --- a/src/tint/ir/block.h +++ b/src/tint/ir/block.h @@ -15,6 +15,7 @@ #ifndef SRC_TINT_IR_BLOCK_H_ #define SRC_TINT_IR_BLOCK_H_ +#include "src/tint/ir/branch.h" #include "src/tint/ir/flow_node.h" #include "src/tint/ir/instruction.h" #include "src/tint/utils/vector.h" @@ -31,7 +32,7 @@ class Block : public Castable { ~Block() override; /// The node this block branches too. - const FlowNode* branch_target = nullptr; + Branch branch = {}; /// The instructions in the block utils::Vector instructions; diff --git a/src/tint/ir/branch.h b/src/tint/ir/branch.h new file mode 100644 index 0000000000..4fc8d7c1f6 --- /dev/null +++ b/src/tint/ir/branch.h @@ -0,0 +1,36 @@ +// 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. +// 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_TINT_IR_BRANCH_H_ +#define SRC_TINT_IR_BRANCH_H_ + +#include "src/tint/ir/flow_node.h" +#include "src/tint/ir/value.h" + +namespace tint::ir { + +/// A information on a branch to another block +struct Branch { + /// The block being branched too. + FlowNode* target = nullptr; + + /// The arguments provided for that branch. These arguments could be the + /// return value in the case of a branch to the terminator, or they could + /// be the basic block arguments passed into the block. + utils::Vector args; +}; + +} // namespace tint::ir + +#endif // SRC_TINT_IR_BRANCH_H_ diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc index 0f43e236b4..1452dc4e03 100644 --- a/src/tint/ir/builder.cc +++ b/src/tint/ir/builder.cc @@ -47,48 +47,49 @@ Function* Builder::CreateFunction() { If* Builder::CreateIf() { auto* ir_if = ir.flow_nodes.Create(); - ir_if->true_target = CreateBlock(); - ir_if->false_target = CreateBlock(); - ir_if->merge_target = CreateBlock(); + ir_if->true_.target = CreateBlock(); + ir_if->false_.target = CreateBlock(); + ir_if->merge.target = CreateBlock(); // An if always branches to both the true and false block. - ir_if->true_target->inbound_branches.Push(ir_if); - ir_if->false_target->inbound_branches.Push(ir_if); + ir_if->true_.target->inbound_branches.Push(ir_if); + ir_if->false_.target->inbound_branches.Push(ir_if); return ir_if; } Loop* Builder::CreateLoop() { auto* ir_loop = ir.flow_nodes.Create(); - ir_loop->start_target = CreateBlock(); - ir_loop->continuing_target = CreateBlock(); - ir_loop->merge_target = CreateBlock(); + ir_loop->start.target = CreateBlock(); + ir_loop->continuing.target = CreateBlock(); + ir_loop->merge.target = CreateBlock(); // A loop always branches to the start block. - ir_loop->start_target->inbound_branches.Push(ir_loop); + ir_loop->start.target->inbound_branches.Push(ir_loop); return ir_loop; } Switch* Builder::CreateSwitch() { auto* ir_switch = ir.flow_nodes.Create(); - ir_switch->merge_target = CreateBlock(); + ir_switch->merge.target = CreateBlock(); return ir_switch; } Block* Builder::CreateCase(Switch* s, utils::VectorRef selectors) { - s->cases.Push(Switch::Case{selectors, CreateBlock()}); + s->cases.Push(Switch::Case{selectors, {CreateBlock(), utils::Empty}}); - Block* b = s->cases.Back().start_target; + Block* b = s->cases.Back().start.target->As(); // Switch branches into the case block b->inbound_branches.Push(s); return b; } -void Builder::Branch(Block* from, FlowNode* to) { +void Builder::Branch(Block* from, FlowNode* to, utils::VectorRef args) { TINT_ASSERT(IR, from); TINT_ASSERT(IR, to); - from->branch_target = to; + from->branch.target = to; + from->branch.args = args; to->inbound_branches.Push(from); } diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h index f760b5c2b5..147e4c4fcd 100644 --- a/src/tint/ir/builder.h +++ b/src/tint/ir/builder.h @@ -79,7 +79,8 @@ class Builder { /// Branches the given block to the given flow node. /// @param from the block to branch from /// @param to the node to branch too - void Branch(Block* from, FlowNode* to); + /// @param args arguments to the branch + void Branch(Block* from, FlowNode* to, utils::VectorRef args); /// Creates a constant::Value /// @param args the arguments diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc index cf7321d455..dbcad5efa4 100644 --- a/src/tint/ir/builder_impl.cc +++ b/src/tint/ir/builder_impl.cc @@ -64,7 +64,7 @@ class FlowStackScope { }; bool IsBranched(const Block* b) { - return b->branch_target != nullptr; + return b->branch.target != nullptr; } bool IsConnected(const FlowNode* b) { @@ -92,11 +92,11 @@ BuilderImpl::BuilderImpl(const Program* program) BuilderImpl::~BuilderImpl() = default; -void BuilderImpl::BranchTo(FlowNode* node) { +void BuilderImpl::BranchTo(FlowNode* node, utils::VectorRef args) { TINT_ASSERT(IR, current_flow_block); TINT_ASSERT(IR, !IsBranched(current_flow_block)); - builder.Branch(current_flow_block, node); + builder.Branch(current_flow_block, node, args); current_flow_block = nullptr; } @@ -265,27 +265,27 @@ bool BuilderImpl::EmitIf(const ast::IfStatement* stmt) { { FlowStackScope scope(this, if_node); - current_flow_block = if_node->true_target; + current_flow_block = if_node->true_.target->As(); if (!EmitStatement(stmt->body)) { return false; } // If the true branch did not execute control flow, then go to the merge target - BranchToIfNeeded(if_node->merge_target); + BranchToIfNeeded(if_node->merge.target); - current_flow_block = if_node->false_target; + current_flow_block = if_node->false_.target->As(); if (stmt->else_statement && !EmitStatement(stmt->else_statement)) { return false; } // If the false branch did not execute control flow, then go to the merge target - BranchToIfNeeded(if_node->merge_target); + BranchToIfNeeded(if_node->merge.target); } current_flow_block = nullptr; // If both branches went somewhere, then they both returned, continued or broke. So, // there is no need for the if merge-block and there is nothing to branch to the merge // block anyway. - if (IsConnected(if_node->merge_target)) { - current_flow_block = if_node->merge_target; + if (IsConnected(if_node->merge.target)) { + current_flow_block = if_node->merge.target->As(); } return true; @@ -301,15 +301,15 @@ bool BuilderImpl::EmitLoop(const ast::LoopStatement* stmt) { { FlowStackScope scope(this, loop_node); - current_flow_block = loop_node->start_target; + current_flow_block = loop_node->start.target->As(); if (!EmitStatement(stmt->body)) { return false; } // The current block didn't `break`, `return` or `continue`, go to the continuing block. - BranchToIfNeeded(loop_node->continuing_target); + BranchToIfNeeded(loop_node->continuing.target); - current_flow_block = loop_node->continuing_target; + current_flow_block = loop_node->continuing.target->As(); if (stmt->continuing) { if (!EmitStatement(stmt->continuing)) { return false; @@ -317,13 +317,13 @@ bool BuilderImpl::EmitLoop(const ast::LoopStatement* stmt) { } // Branch back to the start node if the continue target didn't branch out already - BranchToIfNeeded(loop_node->start_target); + BranchToIfNeeded(loop_node->start.target); } // The loop merge can get disconnected if the loop returns directly, or the continuing target // branches, eventually, to the merge, but nothing branched to the continuing target. - current_flow_block = loop_node->merge_target; - if (!IsConnected(loop_node->merge_target)) { + current_flow_block = loop_node->merge.target->As(); + if (!IsConnected(loop_node->merge.target)) { current_flow_block = nullptr; } return true; @@ -332,7 +332,9 @@ bool BuilderImpl::EmitLoop(const ast::LoopStatement* stmt) { bool BuilderImpl::EmitWhile(const ast::WhileStatement* stmt) { auto* loop_node = builder.CreateLoop(); // Continue is always empty, just go back to the start - builder.Branch(loop_node->continuing_target, loop_node->start_target); + TINT_ASSERT(IR, loop_node->continuing.target->Is()); + builder.Branch(loop_node->continuing.target->As(), loop_node->start.target, + utils::Empty); BranchTo(loop_node); @@ -341,7 +343,7 @@ bool BuilderImpl::EmitWhile(const ast::WhileStatement* stmt) { { FlowStackScope scope(this, loop_node); - current_flow_block = loop_node->start_target; + current_flow_block = loop_node->start.target->As(); // Emit the while condition into the start target of the loop auto reg = EmitExpression(stmt->condition); @@ -351,28 +353,33 @@ bool BuilderImpl::EmitWhile(const ast::WhileStatement* stmt) { // Create an `if (cond) {} else {break;}` control flow auto* if_node = builder.CreateIf(); - builder.Branch(if_node->true_target, if_node->merge_target); - builder.Branch(if_node->false_target, loop_node->merge_target); + TINT_ASSERT(IR, if_node->true_.target->Is()); + builder.Branch(if_node->true_.target->As(), if_node->merge.target, utils::Empty); + + TINT_ASSERT(IR, if_node->false_.target->Is()); + builder.Branch(if_node->false_.target->As(), loop_node->merge.target, utils::Empty); if_node->condition = reg.Get(); BranchTo(if_node); - current_flow_block = if_node->merge_target; + current_flow_block = if_node->merge.target->As(); if (!EmitStatement(stmt->body)) { return false; } - BranchToIfNeeded(loop_node->continuing_target); + BranchToIfNeeded(loop_node->continuing.target); } // The while loop always has a path to the merge target as the break statement comes before // anything inside the loop. - current_flow_block = loop_node->merge_target; + current_flow_block = loop_node->merge.target->As(); return true; } bool BuilderImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { auto* loop_node = builder.CreateLoop(); - builder.Branch(loop_node->continuing_target, loop_node->start_target); + TINT_ASSERT(IR, loop_node->continuing.target->Is()); + builder.Branch(loop_node->continuing.target->As(), loop_node->start.target, + utils::Empty); if (stmt->initializer) { // Emit the for initializer before branching to the loop @@ -388,7 +395,7 @@ bool BuilderImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { { FlowStackScope scope(this, loop_node); - current_flow_block = loop_node->start_target; + current_flow_block = loop_node->start.target->As(); if (stmt->condition) { // Emit the condition into the target target of the loop @@ -399,22 +406,26 @@ bool BuilderImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { // Create an `if (cond) {} else {break;}` control flow auto* if_node = builder.CreateIf(); - builder.Branch(if_node->true_target, if_node->merge_target); - builder.Branch(if_node->false_target, loop_node->merge_target); + TINT_ASSERT(IR, if_node->true_.target->Is()); + builder.Branch(if_node->true_.target->As(), if_node->merge.target, utils::Empty); + + TINT_ASSERT(IR, if_node->false_.target->Is()); + builder.Branch(if_node->false_.target->As(), loop_node->merge.target, + utils::Empty); if_node->condition = reg.Get(); BranchTo(if_node); - current_flow_block = if_node->merge_target; + current_flow_block = if_node->merge.target->As(); } if (!EmitStatement(stmt->body)) { return false; } - BranchToIfNeeded(loop_node->continuing_target); + BranchToIfNeeded(loop_node->continuing.target); if (stmt->continuing) { - current_flow_block = loop_node->continuing_target; + current_flow_block = loop_node->continuing.target->As(); if (!EmitStatement(stmt->continuing)) { return false; } @@ -422,7 +433,7 @@ bool BuilderImpl::EmitForLoop(const ast::ForLoopStatement* stmt) { } // The while loop always has a path to the merge target as the break statement comes before // anything inside the loop. - current_flow_block = loop_node->merge_target; + current_flow_block = loop_node->merge.target->As(); return true; } @@ -458,24 +469,29 @@ bool BuilderImpl::EmitSwitch(const ast::SwitchStatement* stmt) { if (!EmitStatement(c->Body()->Declaration())) { return false; } - BranchToIfNeeded(switch_node->merge_target); + BranchToIfNeeded(switch_node->merge.target); } } current_flow_block = nullptr; - if (IsConnected(switch_node->merge_target)) { - current_flow_block = switch_node->merge_target; + if (IsConnected(switch_node->merge.target)) { + current_flow_block = switch_node->merge.target->As(); } return true; } -bool BuilderImpl::EmitReturn(const ast::ReturnStatement*) { - // TODO(dsinclair): Emit the return value. Need to determine how we want to - // emit this. Emit a `return_value %yy` instruction? There is no `return` - // instruction as we just branch. +bool BuilderImpl::EmitReturn(const ast::ReturnStatement* stmt) { + utils::Vector ret_value; + if (stmt->value) { + auto ret = EmitExpression(stmt->value); + if (!ret) { + return false; + } + ret_value.Push(ret.Get()); + } - BranchTo(current_function_->end_target); + BranchTo(current_function_->end_target, std::move(ret_value)); return true; } @@ -484,9 +500,9 @@ bool BuilderImpl::EmitBreak(const ast::BreakStatement*) { TINT_ASSERT(IR, current_control); if (auto* c = current_control->As()) { - BranchTo(c->merge_target); + BranchTo(c->merge.target); } else if (auto* s = current_control->As()) { - BranchTo(s->merge_target); + BranchTo(s->merge.target); } else { TINT_UNREACHABLE(IR, diagnostics_); return false; @@ -500,7 +516,7 @@ bool BuilderImpl::EmitContinue(const ast::ContinueStatement*) { TINT_ASSERT(IR, current_control); if (auto* c = current_control->As()) { - BranchTo(c->continuing_target); + BranchTo(c->continuing.target); } else { TINT_UNREACHABLE(IR, diagnostics_); } @@ -528,17 +544,17 @@ bool BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) { auto* loop = current_control->As(); - current_flow_block = if_node->true_target; - BranchTo(loop->merge_target); + current_flow_block = if_node->true_.target->As(); + BranchTo(loop->merge.target); - current_flow_block = if_node->false_target; - BranchTo(if_node->merge_target); + current_flow_block = if_node->false_.target->As(); + BranchTo(if_node->merge.target); - current_flow_block = if_node->merge_target; + current_flow_block = if_node->merge.target->As(); // The `break-if` has to be the last item in the continuing block. The false branch of the // `break-if` will always take us back to the start of the loop. - BranchTo(loop->start_target); + BranchTo(loop->start.target); return true; } diff --git a/src/tint/ir/builder_impl.h b/src/tint/ir/builder_impl.h index 8c81319bb4..c086677532 100644 --- a/src/tint/ir/builder_impl.h +++ b/src/tint/ir/builder_impl.h @@ -202,7 +202,7 @@ class BuilderImpl { private: enum class ControlFlags { kNone, kExcludeSwitch }; - void BranchTo(ir::FlowNode* node); + void BranchTo(ir::FlowNode* node, utils::VectorRef args = {}); void BranchToIfNeeded(ir::FlowNode* node); FlowNode* FindEnclosingControl(ControlFlags flags); diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc index c8b0b9fa6d..eb3811ebd5 100644 --- a/src/tint/ir/builder_impl_test.cc +++ b/src/tint/ir/builder_impl_test.cc @@ -43,7 +43,7 @@ TEST_F(IR_BuilderImplTest, Func) { EXPECT_EQ(1u, f->start_target->inbound_branches.Length()); EXPECT_EQ(1u, f->end_target->inbound_branches.Length()); - EXPECT_EQ(f->start_target->branch_target, f->end_target); + EXPECT_EQ(f->start_target->branch.target, f->end_target); } TEST_F(IR_BuilderImplTest, EntryPoint) { @@ -76,24 +76,24 @@ TEST_F(IR_BuilderImplTest, IfStatement) { EXPECT_TRUE(ir_if->Is()); auto* flow = ir_if->As(); - ASSERT_NE(flow->true_target, nullptr); - ASSERT_NE(flow->false_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->false_target->inbound_branches.Length()); - EXPECT_EQ(2u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->true_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->false_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->true_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->false_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); // Check condition ASSERT_TRUE(flow->condition->Is()); @@ -121,24 +121,24 @@ TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) { EXPECT_TRUE(ir_if->Is()); auto* flow = ir_if->As(); - ASSERT_NE(flow->true_target, nullptr); - ASSERT_NE(flow->false_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->true_target->branch_target, func->end_target); - EXPECT_EQ(flow->false_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->true_.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->false_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) { @@ -160,24 +160,24 @@ TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) { EXPECT_TRUE(ir_if->Is()); auto* flow = ir_if->As(); - ASSERT_NE(flow->true_target, nullptr); - ASSERT_NE(flow->false_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->true_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->false_target->branch_target, func->end_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->true_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->false_.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) { @@ -199,23 +199,23 @@ TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) { EXPECT_TRUE(ir_if->Is()); auto* flow = ir_if->As(); - ASSERT_NE(flow->true_target, nullptr); - ASSERT_NE(flow->false_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->false_target->inbound_branches.Length()); - EXPECT_EQ(0u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->true_target->branch_target, func->end_target); - EXPECT_EQ(flow->false_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->true_.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->false_.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, IfStatement_JumpChainToMerge) { @@ -248,29 +248,30 @@ TEST_F(IR_BuilderImplTest, IfStatement_JumpChainToMerge) { EXPECT_TRUE(ir_if->Is()); auto* if_flow = ir_if->As(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + 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(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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]; - EXPECT_EQ(func->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, loop_flow); - EXPECT_EQ(loop_flow->start_target->branch_target, loop_flow->merge_target); - EXPECT_EQ(loop_flow->merge_target->branch_target, if_flow->merge_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, loop_flow->start_target); - EXPECT_EQ(if_flow->false_target->branch_target, if_flow->merge_target); - EXPECT_EQ(if_flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, loop_flow); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, loop_flow->merge.target); + EXPECT_EQ(loop_flow->merge.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, + loop_flow->start.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(if_flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Loop_WithBreak) { @@ -289,24 +290,24 @@ TEST_F(IR_BuilderImplTest, Loop_WithBreak) { EXPECT_TRUE(ir_loop->Is()); auto* flow = ir_loop->As(); - ASSERT_NE(flow->start_target, nullptr); - ASSERT_NE(flow->continuing_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(2u, flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->continuing_target->branch_target, flow->start_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->As()->branch.target, flow); + EXPECT_EQ(flow->start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->continuing.target->As()->branch.target, flow->start.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Loop_WithContinue) { @@ -331,39 +332,40 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinue) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, loop_flow); - EXPECT_EQ(loop_flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, loop_flow->merge_target); - EXPECT_EQ(if_flow->false_target->branch_target, if_flow->merge_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, loop_flow->start_target); - EXPECT_EQ(loop_flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, loop_flow); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, loop_flow->merge.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, + loop_flow->start.target); + EXPECT_EQ(loop_flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) { @@ -388,40 +390,42 @@ TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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(); - 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_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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, break_if_flow->inbound_branches.Length()); - EXPECT_EQ(1u, break_if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, break_if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, break_if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, break_if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, break_if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, break_if_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, loop_flow); - EXPECT_EQ(loop_flow->start_target->branch_target, loop_flow->continuing_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, break_if_flow); - EXPECT_EQ(break_if_flow->true_target->branch_target, loop_flow->merge_target); - EXPECT_EQ(break_if_flow->false_target->branch_target, break_if_flow->merge_target); - EXPECT_EQ(break_if_flow->merge_target->branch_target, loop_flow->start_target); - EXPECT_EQ(loop_flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, loop_flow); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, + loop_flow->continuing.target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, break_if_flow); + EXPECT_EQ(break_if_flow->true_.target->As()->branch.target, loop_flow->merge.target); + EXPECT_EQ(break_if_flow->false_.target->As()->branch.target, + break_if_flow->merge.target); + EXPECT_EQ(break_if_flow->merge.target->As()->branch.target, loop_flow->start.target); + EXPECT_EQ(loop_flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Loop_WithReturn) { @@ -446,40 +450,41 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(loop_flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, func->end_target); - EXPECT_EQ(if_flow->false_target->branch_target, if_flow->merge_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, loop_flow->start_target); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, func->end_target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, + loop_flow->start.target); - EXPECT_EQ(func->start_target->branch_target, ir_loop); - EXPECT_EQ(loop_flow->merge_target->branch_target, nullptr); + EXPECT_EQ(func->start_target->branch.target, ir_loop); + EXPECT_EQ(loop_flow->merge.target->As()->branch.target, nullptr); // Check condition ASSERT_TRUE(if_flow->condition->Is()); @@ -518,24 +523,25 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(loop_flow->start_target->branch_target, func->end_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, loop_flow->start_target); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, func->end_target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, + loop_flow->start.target); - EXPECT_EQ(func->start_target->branch_target, ir_loop); + EXPECT_EQ(func->start_target->branch.target, ir_loop); } TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) { @@ -574,9 +580,9 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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); @@ -586,25 +592,25 @@ TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn_ContinuingBreakIf) { EXPECT_TRUE(ir_break_if->Is()); auto* break_if_flow = ir_break_if->As(); - 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_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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); // 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(loop_flow->start_target->branch_target, func->end_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, break_if_flow); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, func->end_target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, break_if_flow); - EXPECT_EQ(func->start_target->branch_target, ir_loop); + EXPECT_EQ(func->start_target->branch.target, ir_loop); } TEST_F(IR_BuilderImplTest, Loop_WithIf_BothBranchesBreak) { @@ -629,42 +635,43 @@ TEST_F(IR_BuilderImplTest, Loop_WithIf_BothBranchesBreak) { EXPECT_TRUE(ir_loop->Is()); auto* loop_flow = ir_loop->As(); - ASSERT_NE(loop_flow->start_target, nullptr); - ASSERT_NE(loop_flow->continuing_target, nullptr); - ASSERT_NE(loop_flow->merge_target, nullptr); + 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(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, loop_flow->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(0u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(0u, if_flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); // Note, the `continue` is dead code because both if branches go out of loop, so it just gets // dropped. - EXPECT_EQ(func->start_target->branch_target, loop_flow); - EXPECT_EQ(loop_flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, loop_flow->merge_target); - EXPECT_EQ(if_flow->false_target->branch_target, loop_flow->merge_target); - EXPECT_EQ(loop_flow->continuing_target->branch_target, loop_flow->start_target); - EXPECT_EQ(loop_flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, loop_flow); + EXPECT_EQ(loop_flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, loop_flow->merge.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, loop_flow->merge.target); + EXPECT_EQ(loop_flow->continuing.target->As()->branch.target, + loop_flow->start.target); + EXPECT_EQ(loop_flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Loop_Nested) { @@ -735,129 +742,135 @@ TEST_F(IR_BuilderImplTest, Loop_Nested) { ASSERT_NE(ir_loop_a, nullptr); EXPECT_TRUE(ir_loop_a->Is()); auto* loop_flow_a = ir_loop_a->As(); - ASSERT_NE(loop_flow_a->start_target, nullptr); - ASSERT_NE(loop_flow_a->continuing_target, nullptr); - ASSERT_NE(loop_flow_a->merge_target, 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(); - ASSERT_NE(loop_flow_b->start_target, nullptr); - ASSERT_NE(loop_flow_b->continuing_target, nullptr); - ASSERT_NE(loop_flow_b->merge_target, 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); + 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); + 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(); - ASSERT_NE(if_flow_a->true_target, nullptr); - ASSERT_NE(if_flow_a->false_target, nullptr); - ASSERT_NE(if_flow_a->merge_target, 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(); - ASSERT_NE(if_flow_b->true_target, nullptr); - ASSERT_NE(if_flow_b->false_target, nullptr); - ASSERT_NE(if_flow_b->merge_target, 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(); - ASSERT_NE(if_flow_c->true_target, nullptr); - ASSERT_NE(if_flow_c->false_target, nullptr); - ASSERT_NE(if_flow_c->merge_target, 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(); - 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_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]; EXPECT_EQ(1u, loop_flow_a->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow_a->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_a->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_a->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow_a->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_a->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_a->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, loop_flow_b->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow_b->start_target->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow_b->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_b->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow_b->start.target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow_b->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_b->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, loop_flow_c->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow_c->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, loop_flow_c->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_c->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow_c->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, loop_flow_c->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_c->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, loop_flow_d->inbound_branches.Length()); - EXPECT_EQ(2u, loop_flow_d->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_d->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, loop_flow_d->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, loop_flow_d->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_d->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, loop_flow_d->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow_a->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_a->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_a->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_a->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_a->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_a->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_a->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow_b->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_b->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_b->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_b->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_b->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_b->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_b->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow_c->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_c->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_c->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_c->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_c->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_c->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_c->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, if_flow_d->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_d->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_d->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow_d->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_d->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_d->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow_d->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->start_target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, loop_flow_a); - EXPECT_EQ(loop_flow_a->start_target->branch_target, loop_flow_b); - EXPECT_EQ(loop_flow_b->start_target->branch_target, if_flow_a); - EXPECT_EQ(if_flow_a->true_target->branch_target, loop_flow_b->merge_target); - EXPECT_EQ(if_flow_a->false_target->branch_target, if_flow_a->merge_target); - EXPECT_EQ(if_flow_a->merge_target->branch_target, if_flow_b); - EXPECT_EQ(if_flow_b->true_target->branch_target, loop_flow_b->continuing_target); - EXPECT_EQ(if_flow_b->false_target->branch_target, if_flow_b->merge_target); - EXPECT_EQ(if_flow_b->merge_target->branch_target, loop_flow_b->continuing_target); - EXPECT_EQ(loop_flow_b->continuing_target->branch_target, loop_flow_c); - EXPECT_EQ(loop_flow_c->start_target->branch_target, loop_flow_c->merge_target); - EXPECT_EQ(loop_flow_c->continuing_target->branch_target, loop_flow_c->start_target); - EXPECT_EQ(loop_flow_c->merge_target->branch_target, loop_flow_d); - EXPECT_EQ(loop_flow_d->start_target->branch_target, loop_flow_d->continuing_target); - EXPECT_EQ(loop_flow_d->continuing_target->branch_target, if_flow_c); - EXPECT_EQ(if_flow_c->true_target->branch_target, loop_flow_d->merge_target); - EXPECT_EQ(if_flow_c->false_target->branch_target, if_flow_c->merge_target); - EXPECT_EQ(if_flow_c->merge_target->branch_target, loop_flow_d->start_target); - EXPECT_EQ(loop_flow_d->merge_target->branch_target, loop_flow_b->start_target); - EXPECT_EQ(loop_flow_b->merge_target->branch_target, if_flow_d); - EXPECT_EQ(if_flow_d->true_target->branch_target, loop_flow_a->merge_target); - EXPECT_EQ(if_flow_d->false_target->branch_target, if_flow_d->merge_target); - EXPECT_EQ(if_flow_d->merge_target->branch_target, loop_flow_a->continuing_target); - EXPECT_EQ(loop_flow_a->continuing_target->branch_target, loop_flow_a->start_target); - EXPECT_EQ(loop_flow_a->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, loop_flow_a); + EXPECT_EQ(loop_flow_a->start.target->As()->branch.target, loop_flow_b); + EXPECT_EQ(loop_flow_b->start.target->As()->branch.target, if_flow_a); + EXPECT_EQ(if_flow_a->true_.target->As()->branch.target, loop_flow_b->merge.target); + EXPECT_EQ(if_flow_a->false_.target->As()->branch.target, if_flow_a->merge.target); + EXPECT_EQ(if_flow_a->merge.target->As()->branch.target, if_flow_b); + EXPECT_EQ(if_flow_b->true_.target->As()->branch.target, + loop_flow_b->continuing.target); + EXPECT_EQ(if_flow_b->false_.target->As()->branch.target, if_flow_b->merge.target); + EXPECT_EQ(if_flow_b->merge.target->As()->branch.target, + loop_flow_b->continuing.target); + EXPECT_EQ(loop_flow_b->continuing.target->As()->branch.target, loop_flow_c); + EXPECT_EQ(loop_flow_c->start.target->As()->branch.target, loop_flow_c->merge.target); + EXPECT_EQ(loop_flow_c->continuing.target->As()->branch.target, + loop_flow_c->start.target); + EXPECT_EQ(loop_flow_c->merge.target->As()->branch.target, loop_flow_d); + EXPECT_EQ(loop_flow_d->start.target->As()->branch.target, + loop_flow_d->continuing.target); + EXPECT_EQ(loop_flow_d->continuing.target->As()->branch.target, if_flow_c); + EXPECT_EQ(if_flow_c->true_.target->As()->branch.target, loop_flow_d->merge.target); + EXPECT_EQ(if_flow_c->false_.target->As()->branch.target, if_flow_c->merge.target); + EXPECT_EQ(if_flow_c->merge.target->As()->branch.target, loop_flow_d->start.target); + EXPECT_EQ(loop_flow_d->merge.target->As()->branch.target, loop_flow_b->start.target); + EXPECT_EQ(loop_flow_b->merge.target->As()->branch.target, if_flow_d); + EXPECT_EQ(if_flow_d->true_.target->As()->branch.target, loop_flow_a->merge.target); + EXPECT_EQ(if_flow_d->false_.target->As()->branch.target, if_flow_d->merge.target); + EXPECT_EQ(if_flow_d->merge.target->As()->branch.target, + loop_flow_a->continuing.target); + EXPECT_EQ(loop_flow_a->continuing.target->As()->branch.target, + loop_flow_a->start.target); + EXPECT_EQ(loop_flow_a->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, While) { @@ -886,36 +899,36 @@ TEST_F(IR_BuilderImplTest, While) { ASSERT_TRUE(ir_while->Is()); auto* flow = ir_while->As(); - ASSERT_NE(flow->start_target, nullptr); - ASSERT_NE(flow->continuing_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->start.target, nullptr); + ASSERT_NE(flow->continuing.target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); - ASSERT_NE(flow->start_target->branch_target, nullptr); - ASSERT_TRUE(flow->start_target->branch_target->Is()); - auto* if_flow = flow->start_target->branch_target->As(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + ASSERT_NE(flow->start.target->As()->branch.target, nullptr); + ASSERT_TRUE(flow->start.target->As()->branch.target->Is()); + auto* if_flow = flow->start.target->As()->branch.target->As(); + 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]; EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(2u, flow->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, if_flow->merge_target); - EXPECT_EQ(if_flow->false_target->branch_target, flow->merge_target); - EXPECT_EQ(if_flow->merge_target->branch_target, flow->continuing_target); - EXPECT_EQ(flow->continuing_target->branch_target, flow->start_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(if_flow->merge.target->As()->branch.target, flow->continuing.target); + EXPECT_EQ(flow->continuing.target->As()->branch.target, flow->start.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); // Check condition ASSERT_TRUE(if_flow->condition->Is()); @@ -950,36 +963,36 @@ TEST_F(IR_BuilderImplTest, While_Return) { ASSERT_TRUE(ir_while->Is()); auto* flow = ir_while->As(); - ASSERT_NE(flow->start_target, nullptr); - ASSERT_NE(flow->continuing_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->start.target, nullptr); + ASSERT_NE(flow->continuing.target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); - ASSERT_NE(flow->start_target->branch_target, nullptr); - ASSERT_TRUE(flow->start_target->branch_target->Is()); - auto* if_flow = flow->start_target->branch_target->As(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + ASSERT_NE(flow->start.target->As()->branch.target, nullptr); + ASSERT_TRUE(flow->start.target->As()->branch.target->Is()); + auto* if_flow = flow->start.target->As()->branch.target->As(); + 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]; EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(2u, flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, if_flow->merge_target); - EXPECT_EQ(if_flow->false_target->branch_target, flow->merge_target); - EXPECT_EQ(if_flow->merge_target->branch_target, func->end_target); - EXPECT_EQ(flow->continuing_target->branch_target, flow->start_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(if_flow->merge.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->continuing.target->As()->branch.target, flow->start.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } // TODO(dsinclair): Enable when variable declarations and increment are supported @@ -1007,36 +1020,36 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) { ASSERT_TRUE(ir_for->Is()); auto* flow = ir_for->As(); - ASSERT_NE(flow->start_target, nullptr); - ASSERT_NE(flow->continuing_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->start.target, nullptr); + ASSERT_NE(flow->continuing.target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); - ASSERT_NE(flow->start_target->branch_target, nullptr); - ASSERT_TRUE(flow->start_target->branch_target->Is()); - auto* if_flow = flow->start_target->branch_target->As(); - ASSERT_NE(if_flow->true_target, nullptr); - ASSERT_NE(if_flow->false_target, nullptr); - ASSERT_NE(if_flow->merge_target, nullptr); + ASSERT_NE(flow->start.target->As()->branch.target, nullptr); + ASSERT_TRUE(flow->start.target->As()->branch.target->Is()); + auto* if_flow = flow->start.target->As()->branch.target->As(); + 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]; EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(2u, flow->start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->true_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->false_target->inbound_branches.Length()); - EXPECT_EQ(1u, if_flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->true_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length()); + EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, flow); - EXPECT_EQ(flow->start_target->branch_target, if_flow); - EXPECT_EQ(if_flow->true_target->branch_target, if_flow->merge_target); - EXPECT_EQ(if_flow->false_target->branch_target, flow->merge_target); - EXPECT_EQ(if_flow->merge_target->branch_target, flow->continuing_target); - EXPECT_EQ(flow->continuing_target->branch_target, flow->start_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, flow); + EXPECT_EQ(flow->start.target->As()->branch.target, if_flow); + EXPECT_EQ(if_flow->true_.target->As()->branch.target, if_flow->merge.target); + EXPECT_EQ(if_flow->false_.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(if_flow->merge.target->As()->branch.target, flow->continuing.target); + EXPECT_EQ(flow->continuing.target->As()->branch.target, flow->start.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); // Check condition ASSERT_TRUE(if_flow->condition->Is()); @@ -1063,22 +1076,22 @@ TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) { ASSERT_TRUE(ir_for->Is()); auto* flow = ir_for->As(); - ASSERT_NE(flow->start_target, nullptr); - ASSERT_NE(flow->continuing_target, nullptr); - ASSERT_NE(flow->merge_target, nullptr); + 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]; EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(2u, flow->start_target->inbound_branches.Length()); - EXPECT_EQ(0u, flow->continuing_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->start.target->inbound_branches.Length()); + EXPECT_EQ(0u, flow->continuing.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(flow->start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->continuing_target->branch_target, flow->start_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(flow->start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->continuing.target->As()->branch.target, flow->start.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Switch) { @@ -1105,7 +1118,7 @@ TEST_F(IR_BuilderImplTest, Switch) { ASSERT_TRUE(ir_switch->Is()); auto* flow = ir_switch->As(); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(3u, flow->cases.Length()); ASSERT_EQ(1u, m.functions.Length()); @@ -1123,17 +1136,17 @@ TEST_F(IR_BuilderImplTest, Switch) { EXPECT_TRUE(flow->cases[2].selectors[0].IsDefault()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[1].start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[2].start_target->inbound_branches.Length()); - EXPECT_EQ(3u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[2].start.target->inbound_branches.Length()); + EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, ir_switch); - EXPECT_EQ(flow->cases[0].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->cases[1].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->cases[2].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, ir_switch); + EXPECT_EQ(flow->cases[0].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->cases[1].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->cases[2].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); // Check condition ASSERT_TRUE(flow->condition->Is()); @@ -1157,7 +1170,7 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) { ASSERT_TRUE(ir_switch->Is()); auto* flow = ir_switch->As(); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(1u, flow->cases.Length()); ASSERT_EQ(1u, m.functions.Length()); @@ -1167,13 +1180,13 @@ TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) { EXPECT_TRUE(flow->cases[0].selectors[0].IsDefault()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(1u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, ir_switch); - EXPECT_EQ(flow->cases[0].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, ir_switch); + EXPECT_EQ(flow->cases[0].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Switch_WithBreak) { @@ -1207,7 +1220,7 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) { ASSERT_TRUE(ir_switch->Is()); auto* flow = ir_switch->As(); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(2u, flow->cases.Length()); ASSERT_EQ(1u, m.functions.Length()); @@ -1221,16 +1234,16 @@ TEST_F(IR_BuilderImplTest, Switch_WithBreak) { EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[1].start_target->inbound_branches.Length()); - EXPECT_EQ(2u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length()); + EXPECT_EQ(2u, flow->merge.target->inbound_branches.Length()); // 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(func->start_target->branch_target, ir_switch); - EXPECT_EQ(flow->cases[0].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->cases[1].start_target->branch_target, flow->merge_target); - EXPECT_EQ(flow->merge_target->branch_target, func->end_target); + EXPECT_EQ(func->start_target->branch.target, ir_switch); + EXPECT_EQ(flow->cases[0].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->cases[1].start.target->As()->branch.target, flow->merge.target); + EXPECT_EQ(flow->merge.target->As()->branch.target, func->end_target); } TEST_F(IR_BuilderImplTest, Switch_AllReturn) { @@ -1271,7 +1284,7 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) { ASSERT_TRUE(ir_switch->Is()); auto* flow = ir_switch->As(); - ASSERT_NE(flow->merge_target, nullptr); + ASSERT_NE(flow->merge.target, nullptr); ASSERT_EQ(2u, flow->cases.Length()); ASSERT_EQ(1u, m.functions.Length()); @@ -1285,15 +1298,15 @@ TEST_F(IR_BuilderImplTest, Switch_AllReturn) { EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault()); EXPECT_EQ(1u, flow->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[0].start_target->inbound_branches.Length()); - EXPECT_EQ(1u, flow->cases[1].start_target->inbound_branches.Length()); - EXPECT_EQ(0u, flow->merge_target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length()); + EXPECT_EQ(1u, flow->cases[1].start.target->inbound_branches.Length()); + EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length()); EXPECT_EQ(2u, func->end_target->inbound_branches.Length()); - EXPECT_EQ(func->start_target->branch_target, ir_switch); - EXPECT_EQ(flow->cases[0].start_target->branch_target, func->end_target); - EXPECT_EQ(flow->cases[1].start_target->branch_target, func->end_target); - EXPECT_EQ(flow->merge_target->branch_target, nullptr); + EXPECT_EQ(func->start_target->branch.target, ir_switch); + EXPECT_EQ(flow->cases[0].start.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->cases[1].start.target->As()->branch.target, func->end_target); + EXPECT_EQ(flow->merge.target->As()->branch.target, nullptr); } TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) { @@ -1391,7 +1404,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 + 4 )"); } @@ -1406,7 +1419,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 - 4 )"); } @@ -1421,7 +1434,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 * 4 )"); } @@ -1436,7 +1449,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 / 4 )"); } @@ -1451,7 +1464,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 % 4 )"); } @@ -1466,7 +1479,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 & 4 )"); } @@ -1481,7 +1494,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 | 4 )"); } @@ -1496,7 +1509,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 ^ 4 )"); } @@ -1511,7 +1524,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = true && false )"); } @@ -1526,7 +1539,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = false || true )"); } @@ -1541,7 +1554,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Equal) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 == 4 )"); } @@ -1556,7 +1569,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 != 4 )"); } @@ -1571,7 +1584,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 < 4 )"); } @@ -1586,7 +1599,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 > 4 )"); } @@ -1601,7 +1614,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 <= 4 )"); } @@ -1616,7 +1629,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 >= 4 )"); } @@ -1631,7 +1644,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 << 4 )"); } @@ -1646,7 +1659,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4 )"); } @@ -1662,7 +1675,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4 %2 (u32) = %1 (u32) + 9 %3 (bool) = 1 < %2 (u32) @@ -1683,9 +1696,10 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) { ASSERT_TRUE(r) << b.error(); Disassembler d(b.builder.ir); - d.EmitBlockInstructions(b.current_flow_block); + d.EmitBlockInstructions(b.current_flow_block->As()); EXPECT_EQ(d.AsString(), R"(%1 (f32) = bitcast(3) )"); } + } // namespace } // namespace tint::ir diff --git a/src/tint/ir/debug.cc b/src/tint/ir/debug.cc index aaff6665aa..617b207ad2 100644 --- a/src/tint/ir/debug.cc +++ b/src/tint/ir/debug.cc @@ -59,24 +59,24 @@ std::string Debug::AsDotGraph(const Module* mod) { if (node_to_name.count(b) == 0) { out << name_for(b) << R"( [label="block"])" << std::endl; } - out << name_for(b) << " -> " << name_for(b->branch_target); + out << name_for(b) << " -> " << name_for(b->branch.target); // Dashed lines to merge blocks - if (merge_nodes.count(b->branch_target) != 0) { + if (merge_nodes.count(b->branch.target) != 0) { out << " [style=dashed]"; } out << std::endl; - Graph(b->branch_target); + Graph(b->branch.target); }, [&](const ir::Switch* s) { out << name_for(s) << R"( [label="switch"])" << std::endl; - out << name_for(s->merge_target) << R"( [label="switch merge"])" << std::endl; - merge_nodes.insert(s->merge_target); + out << name_for(s->merge.target) << R"( [label="switch merge"])" << std::endl; + merge_nodes.insert(s->merge.target); size_t i = 0; for (const auto& c : s->cases) { - out << name_for(c.start_target) + out << name_for(c.start.target) << R"( [label="case )" + std::to_string(i++) + R"("])" << std::endl; } out << name_for(s) << " -> {"; @@ -84,56 +84,56 @@ std::string Debug::AsDotGraph(const Module* mod) { if (&c != &(s->cases[0])) { out << ", "; } - out << name_for(c.start_target); + out << name_for(c.start.target); } out << "}" << std::endl; for (const auto& c : s->cases) { - Graph(c.start_target); + Graph(c.start.target); } - Graph(s->merge_target); + Graph(s->merge.target); }, [&](const ir::If* i) { out << name_for(i) << R"( [label="if"])" << std::endl; - out << name_for(i->true_target) << R"( [label="true"])" << std::endl; - out << name_for(i->false_target) << R"( [label="false"])" << std::endl; - out << name_for(i->merge_target) << R"( [label="if merge"])" << std::endl; - merge_nodes.insert(i->merge_target); + out << name_for(i->true_.target) << R"( [label="true"])" << std::endl; + out << name_for(i->false_.target) << R"( [label="false"])" << std::endl; + out << name_for(i->merge.target) << R"( [label="if merge"])" << std::endl; + merge_nodes.insert(i->merge.target); out << name_for(i) << " -> {"; - out << name_for(i->true_target) << ", " << name_for(i->false_target); + out << name_for(i->true_.target) << ", " << name_for(i->false_.target); out << "}" << std::endl; // Subgraph if true/false branches so they draw on the same line out << "subgraph sub_" << name_for(i) << " {" << std::endl; out << R"(rank="same")" << std::endl; - out << name_for(i->true_target) << std::endl; - out << name_for(i->false_target) << std::endl; + out << name_for(i->true_.target) << std::endl; + out << name_for(i->false_.target) << std::endl; out << "}" << std::endl; - Graph(i->true_target); - Graph(i->false_target); - Graph(i->merge_target); + Graph(i->true_.target); + Graph(i->false_.target); + Graph(i->merge.target); }, [&](const ir::Loop* l) { out << name_for(l) << R"( [label="loop"])" << std::endl; - out << name_for(l->start_target) << R"( [label="start"])" << std::endl; - out << name_for(l->continuing_target) << R"( [label="continuing"])" << std::endl; - out << name_for(l->merge_target) << R"( [label="loop merge"])" << std::endl; - merge_nodes.insert(l->merge_target); + out << name_for(l->start.target) << R"( [label="start"])" << std::endl; + out << name_for(l->continuing.target) << R"( [label="continuing"])" << std::endl; + out << name_for(l->merge.target) << R"( [label="loop merge"])" << std::endl; + merge_nodes.insert(l->merge.target); // Subgraph the continuing and merge so they get drawn on the same line out << "subgraph sub_" << name_for(l) << " {" << std::endl; out << R"(rank="same")" << std::endl; - out << name_for(l->continuing_target) << std::endl; - out << name_for(l->merge_target) << std::endl; + out << name_for(l->continuing.target) << std::endl; + out << name_for(l->merge.target) << std::endl; out << "}" << std::endl; - out << name_for(l) << " -> " << name_for(l->start_target) << std::endl; + out << name_for(l) << " -> " << name_for(l->start.target) << std::endl; - Graph(l->start_target); - Graph(l->continuing_target); - Graph(l->merge_target); + Graph(l->start.target); + Graph(l->continuing.target); + Graph(l->merge.target); }, [&](const ir::Terminator*) { // Already done diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc index c2b9f98066..e65bccafcf 100644 --- a/src/tint/ir/disassembler.cc +++ b/src/tint/ir/disassembler.cc @@ -66,6 +66,16 @@ void Disassembler::EmitBlockInstructions(const Block* b) { } } +size_t Disassembler::GetIdForNode(const FlowNode* node) { + auto it = flow_node_to_id_.find(node); + if (it != flow_node_to_id_.end()) { + return it->second; + } + size_t id = next_node_id_++; + flow_node_to_id_[node] = id; + return id; +} + void Disassembler::Walk(const FlowNode* node) { if ((visited_.count(node) > 0) || (stop_nodes_.count(node) > 0)) { return; @@ -75,7 +85,7 @@ void Disassembler::Walk(const FlowNode* node) { tint::Switch( node, [&](const ir::Function* f) { - Indent() << "Function" << std::endl; + Indent() << "%" << GetIdForNode(f) << " = Function" << std::endl; { ScopedIndent func_indent(&indent_size_); @@ -85,60 +95,74 @@ void Disassembler::Walk(const FlowNode* node) { Walk(f->end_target); }, [&](const ir::Block* b) { - Indent() << "Block" << std::endl; + Indent() << "%" << GetIdForNode(b) << " = Block" << std::endl; EmitBlockInstructions(b); - Walk(b->branch_target); + + if (b->branch.target->Is()) { + Indent() << "Return "; + } else { + Indent() << "Branch "; + } + out_ << GetIdForNode(b->branch.target); + + for (const auto* v : b->branch.args) { + out_ << " "; + v->ToString(out_, mod_.symbols); + } + out_ << std::endl; + + Walk(b->branch.target); }, [&](const ir::Switch* s) { - Indent() << "Switch (" << s->condition << ")" << std::endl; + Indent() << "%" << GetIdForNode(s) << " = Switch (" << s->condition << ")" << std::endl; { ScopedIndent switch_indent(&indent_size_); - ScopedStopNode scope(&stop_nodes_, s->merge_target); + ScopedStopNode scope(&stop_nodes_, s->merge.target); for (const auto& c : s->cases) { Indent() << "Case" << std::endl; ScopedIndent case_indent(&indent_size_); - Walk(c.start_target); + Walk(c.start.target); } } Indent() << "Switch Merge" << std::endl; - Walk(s->merge_target); + Walk(s->merge.target); }, [&](const ir::If* i) { - Indent() << "if (" << i->condition << ")" << std::endl; + Indent() << "%" << GetIdForNode(i) << " = if (" << i->condition << ")" << std::endl; { ScopedIndent if_indent(&indent_size_); - ScopedStopNode scope(&stop_nodes_, i->merge_target); + ScopedStopNode scope(&stop_nodes_, i->merge.target); Indent() << "true branch" << std::endl; - Walk(i->true_target); + Walk(i->true_.target); Indent() << "false branch" << std::endl; - Walk(i->false_target); + Walk(i->false_.target); } Indent() << "if merge" << std::endl; - Walk(i->merge_target); + Walk(i->merge.target); }, [&](const ir::Loop* l) { - Indent() << "loop" << std::endl; + Indent() << "%" << GetIdForNode(l) << " = loop" << std::endl; { - ScopedStopNode loop_scope(&stop_nodes_, l->merge_target); + ScopedStopNode loop_scope(&stop_nodes_, l->merge.target); ScopedIndent loop_indent(&indent_size_); { - ScopedStopNode inner_scope(&stop_nodes_, l->continuing_target); + ScopedStopNode inner_scope(&stop_nodes_, l->continuing.target); Indent() << "loop start" << std::endl; - Walk(l->start_target); + Walk(l->start.target); } Indent() << "loop continuing" << std::endl; ScopedIndent continuing_indent(&indent_size_); - Walk(l->continuing_target); + Walk(l->continuing.target); } Indent() << "loop merge" << std::endl; - Walk(l->merge_target); + Walk(l->merge.target); }, [&](const ir::Terminator*) { Indent() << "Function end" << std::endl; }); } diff --git a/src/tint/ir/disassembler.h b/src/tint/ir/disassembler.h index 46b4ffdae4..03cbea1800 100644 --- a/src/tint/ir/disassembler.h +++ b/src/tint/ir/disassembler.h @@ -17,6 +17,7 @@ #include #include +#include #include #include "src/tint/ir/flow_node.h" @@ -46,11 +47,14 @@ class Disassembler { private: std::ostream& Indent(); void Walk(const FlowNode* node); + size_t GetIdForNode(const FlowNode* node); const Module& mod_; std::stringstream out_; std::unordered_set visited_; std::unordered_set stop_nodes_; + std::unordered_map flow_node_to_id_; + size_t next_node_id_ = 0; uint32_t indent_size_ = 0; }; diff --git a/src/tint/ir/if.h b/src/tint/ir/if.h index 3a366b377f..5c4acaa972 100644 --- a/src/tint/ir/if.h +++ b/src/tint/ir/if.h @@ -15,6 +15,7 @@ #ifndef SRC_TINT_IR_IF_H_ #define SRC_TINT_IR_IF_H_ +#include "src/tint/ir/branch.h" #include "src/tint/ir/flow_node.h" #include "src/tint/ir/value.h" @@ -33,12 +34,12 @@ class If : public Castable { ~If() override; /// The true branch block - Block* true_target = nullptr; + Branch true_ = {}; /// The false branch block - Block* false_target = nullptr; + Branch false_ = {}; /// An block to reconvert the true/false barnches. The block always exists, but there maybe no /// branches into it. (e.g. if both branches `return`) - Block* merge_target = nullptr; + Branch merge = {}; /// Value holding the condition result const Value* condition = nullptr; }; diff --git a/src/tint/ir/loop.h b/src/tint/ir/loop.h index 5db8379673..2b026e6f37 100644 --- a/src/tint/ir/loop.h +++ b/src/tint/ir/loop.h @@ -16,6 +16,7 @@ #define SRC_TINT_IR_LOOP_H_ #include "src/tint/ir/block.h" +#include "src/tint/ir/branch.h" #include "src/tint/ir/flow_node.h" namespace tint::ir { @@ -28,13 +29,13 @@ class Loop : public Castable { ~Loop() override; /// The start block is the first block in a loop. - Block* start_target = nullptr; + Branch start = {}; /// The continue target of the block. - Block* continuing_target = nullptr; + Branch continuing = {}; /// The loop merge target. If the `loop` does a `return` then this block may not actually /// end up in the control flow. We need it if the loop does a `break` we know where to break /// too. - Block* merge_target = nullptr; + Branch merge = {}; }; } // namespace tint::ir diff --git a/src/tint/ir/switch.h b/src/tint/ir/switch.h index 7fad9485a0..6d3a952ce4 100644 --- a/src/tint/ir/switch.h +++ b/src/tint/ir/switch.h @@ -17,6 +17,7 @@ #include "src/tint/constant/value.h" #include "src/tint/ir/block.h" +#include "src/tint/ir/branch.h" #include "src/tint/ir/flow_node.h" #include "src/tint/ir/value.h" @@ -39,7 +40,7 @@ class Switch : public Castable { /// The case selector for this node utils::Vector selectors; /// The start block for the case block. - Block* start_target; + Branch start = {}; }; /// Constructor @@ -47,7 +48,7 @@ class Switch : public Castable { ~Switch() override; /// The switch merge target - Block* merge_target; + Branch merge = {}; /// The switch case statements utils::Vector cases;