[ir] Allow branching arguments.
When branching to a different flow node, there is a need to pass
arguments to the branch. These arguments could be the value of the
return.
This extracts a `Branch` out to an object with a target and arguments
and then updates the IR to use the new Branch structure.
Bug: tint:1718
Change-Id: Ic8de8046f58056327a04c8afe3b597810c80ccdb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116546
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index ac9028b..02e81a5 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 @@
~Block() override;
/// The node this block branches too.
- const FlowNode* branch_target = nullptr;
+ Branch branch = {};
/// The instructions in the block
utils::Vector<const Instruction*, 16> instructions;
diff --git a/src/tint/ir/branch.h b/src/tint/ir/branch.h
new file mode 100644
index 0000000..4fc8d7c
--- /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<Value*, 2> 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 0f43e23..1452dc4 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -47,48 +47,49 @@
If* Builder::CreateIf() {
auto* ir_if = ir.flow_nodes.Create<If>();
- 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<Loop>();
- 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<Switch>();
- ir_switch->merge_target = CreateBlock();
+ ir_switch->merge.target = CreateBlock();
return ir_switch;
}
Block* Builder::CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> 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<Block>();
// 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<Value*> 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 f760b5c..147e4c4 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -79,7 +79,8 @@
/// 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<Value*> 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 cf7321d..dbcad5e 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -64,7 +64,7 @@
};
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() = default;
-void BuilderImpl::BranchTo(FlowNode* node) {
+void BuilderImpl::BranchTo(FlowNode* node, utils::VectorRef<Value*> 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 @@
{
FlowStackScope scope(this, if_node);
- current_flow_block = if_node->true_target;
+ current_flow_block = if_node->true_.target->As<Block>();
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<Block>();
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<Block>();
}
return true;
@@ -301,15 +301,15 @@
{
FlowStackScope scope(this, loop_node);
- current_flow_block = loop_node->start_target;
+ current_flow_block = loop_node->start.target->As<Block>();
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<Block>();
if (stmt->continuing) {
if (!EmitStatement(stmt->continuing)) {
return false;
@@ -317,13 +317,13 @@
}
// 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<Block>();
+ if (!IsConnected(loop_node->merge.target)) {
current_flow_block = nullptr;
}
return true;
@@ -332,7 +332,9 @@
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<Block>());
+ builder.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
+ utils::Empty);
BranchTo(loop_node);
@@ -341,7 +343,7 @@
{
FlowStackScope scope(this, loop_node);
- current_flow_block = loop_node->start_target;
+ current_flow_block = loop_node->start.target->As<Block>();
// Emit the while condition into the start target of the loop
auto reg = EmitExpression(stmt->condition);
@@ -351,28 +353,33 @@
// 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<Block>());
+ builder.Branch(if_node->true_.target->As<Block>(), if_node->merge.target, utils::Empty);
+
+ TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
+ builder.Branch(if_node->false_.target->As<Block>(), 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<Block>();
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<Block>();
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<Block>());
+ builder.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
+ utils::Empty);
if (stmt->initializer) {
// Emit the for initializer before branching to the loop
@@ -388,7 +395,7 @@
{
FlowStackScope scope(this, loop_node);
- current_flow_block = loop_node->start_target;
+ current_flow_block = loop_node->start.target->As<Block>();
if (stmt->condition) {
// Emit the condition into the target target of the loop
@@ -399,22 +406,26 @@
// 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<Block>());
+ builder.Branch(if_node->true_.target->As<Block>(), if_node->merge.target, utils::Empty);
+
+ TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
+ builder.Branch(if_node->false_.target->As<Block>(), 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<Block>();
}
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<Block>();
if (!EmitStatement(stmt->continuing)) {
return false;
}
@@ -422,7 +433,7 @@
}
// 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<Block>();
return true;
}
@@ -458,24 +469,29 @@
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<Block>();
}
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<Value*, 1> 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 @@
TINT_ASSERT(IR, current_control);
if (auto* c = current_control->As<Loop>()) {
- BranchTo(c->merge_target);
+ BranchTo(c->merge.target);
} else if (auto* s = current_control->As<Switch>()) {
- BranchTo(s->merge_target);
+ BranchTo(s->merge.target);
} else {
TINT_UNREACHABLE(IR, diagnostics_);
return false;
@@ -500,7 +516,7 @@
TINT_ASSERT(IR, current_control);
if (auto* c = current_control->As<Loop>()) {
- BranchTo(c->continuing_target);
+ BranchTo(c->continuing.target);
} else {
TINT_UNREACHABLE(IR, diagnostics_);
}
@@ -528,17 +544,17 @@
auto* loop = current_control->As<Loop>();
- current_flow_block = if_node->true_target;
- BranchTo(loop->merge_target);
+ current_flow_block = if_node->true_.target->As<Block>();
+ BranchTo(loop->merge.target);
- current_flow_block = if_node->false_target;
- BranchTo(if_node->merge_target);
+ current_flow_block = if_node->false_.target->As<Block>();
+ BranchTo(if_node->merge.target);
- current_flow_block = if_node->merge_target;
+ current_flow_block = if_node->merge.target->As<Block>();
// 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 8c81319..c086677 100644
--- a/src/tint/ir/builder_impl.h
+++ b/src/tint/ir/builder_impl.h
@@ -202,7 +202,7 @@
private:
enum class ControlFlags { kNone, kExcludeSwitch };
- void BranchTo(ir::FlowNode* node);
+ void BranchTo(ir::FlowNode* node, utils::VectorRef<Value*> 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 c8b0b9f..eb3811e 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -43,7 +43,7 @@
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 @@
EXPECT_TRUE(ir_if->Is<ir::If>());
auto* flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->false_.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
// Check condition
ASSERT_TRUE(flow->condition->Is<Constant>());
@@ -121,24 +121,24 @@
EXPECT_TRUE(ir_if->Is<ir::If>());
auto* flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->false_.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, IfStatement_FalseReturns) {
@@ -160,24 +160,24 @@
EXPECT_TRUE(ir_if->Is<ir::If>());
auto* flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->false_.target->As<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, IfStatement_BothReturn) {
@@ -199,23 +199,23 @@
EXPECT_TRUE(ir_if->Is<ir::If>());
auto* flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->false_.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, IfStatement_JumpChainToMerge) {
@@ -248,29 +248,30 @@
EXPECT_TRUE(ir_if->Is<ir::If>());
auto* if_flow = ir_if->As<ir::If>();
- 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<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::Block>()->branch.target, loop_flow);
+ EXPECT_EQ(loop_flow->start.target->As<ir::Block>()->branch.target, loop_flow->merge.target);
+ EXPECT_EQ(loop_flow->merge.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->branch.target,
+ loop_flow->start.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(if_flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Loop_WithBreak) {
@@ -289,24 +290,24 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* flow = ir_loop->As<ir::Loop>();
- 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<ir::Block>()->branch.target, flow);
+ EXPECT_EQ(flow->start.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->continuing.target->As<ir::Block>()->branch.target, flow->start.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Loop_WithContinue) {
@@ -331,39 +332,40 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::If>());
auto* if_flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, loop_flow->merge.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->branch.target,
+ loop_flow->start.target);
+ EXPECT_EQ(loop_flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Loop_WithContinuing_BreakIf) {
@@ -388,40 +390,42 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::If>());
auto* break_if_flow = ir_break_if->As<ir::If>();
- 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<ir::Block>()->branch.target,
+ loop_flow->continuing.target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->branch.target, break_if_flow);
+ EXPECT_EQ(break_if_flow->true_.target->As<ir::Block>()->branch.target, loop_flow->merge.target);
+ EXPECT_EQ(break_if_flow->false_.target->As<ir::Block>()->branch.target,
+ break_if_flow->merge.target);
+ EXPECT_EQ(break_if_flow->merge.target->As<ir::Block>()->branch.target, loop_flow->start.target);
+ EXPECT_EQ(loop_flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Loop_WithReturn) {
@@ -446,40 +450,41 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::If>());
auto* if_flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->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<ir::Block>()->branch.target, nullptr);
// Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>());
@@ -518,24 +523,25 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->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 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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 @@
EXPECT_TRUE(ir_break_if->Is<ir::If>());
auto* break_if_flow = ir_break_if->As<ir::If>();
- 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<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->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 @@
EXPECT_TRUE(ir_loop->Is<ir::Loop>());
auto* loop_flow = ir_loop->As<ir::Loop>();
- 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<ir::If>());
auto* if_flow = ir_if->As<ir::If>();
- 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, loop_flow->merge.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, loop_flow->merge.target);
+ EXPECT_EQ(loop_flow->continuing.target->As<ir::Block>()->branch.target,
+ loop_flow->start.target);
+ EXPECT_EQ(loop_flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Loop_Nested) {
@@ -735,129 +742,135 @@
ASSERT_NE(ir_loop_a, nullptr);
EXPECT_TRUE(ir_loop_a->Is<ir::Loop>());
auto* loop_flow_a = ir_loop_a->As<ir::Loop>();
- 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<ir::Loop>());
auto* loop_flow_b = ir_loop_b->As<ir::Loop>();
- 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<ir::Loop>());
auto* loop_flow_c = ir_loop_c->As<ir::Loop>();
- 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<ir::Loop>());
auto* loop_flow_d = ir_loop_d->As<ir::Loop>();
- 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<ir::If>());
auto* if_flow_a = ir_if_a->As<ir::If>();
- 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<ir::If>());
auto* if_flow_b = ir_if_b->As<ir::If>();
- 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<ir::If>());
auto* if_flow_c = ir_if_c->As<ir::If>();
- 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<ir::If>());
auto* if_flow_d = ir_if_d->As<ir::If>();
- 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<ir::Block>()->branch.target, loop_flow_b);
+ EXPECT_EQ(loop_flow_b->start.target->As<ir::Block>()->branch.target, if_flow_a);
+ EXPECT_EQ(if_flow_a->true_.target->As<ir::Block>()->branch.target, loop_flow_b->merge.target);
+ EXPECT_EQ(if_flow_a->false_.target->As<ir::Block>()->branch.target, if_flow_a->merge.target);
+ EXPECT_EQ(if_flow_a->merge.target->As<ir::Block>()->branch.target, if_flow_b);
+ EXPECT_EQ(if_flow_b->true_.target->As<ir::Block>()->branch.target,
+ loop_flow_b->continuing.target);
+ EXPECT_EQ(if_flow_b->false_.target->As<ir::Block>()->branch.target, if_flow_b->merge.target);
+ EXPECT_EQ(if_flow_b->merge.target->As<ir::Block>()->branch.target,
+ loop_flow_b->continuing.target);
+ EXPECT_EQ(loop_flow_b->continuing.target->As<ir::Block>()->branch.target, loop_flow_c);
+ EXPECT_EQ(loop_flow_c->start.target->As<ir::Block>()->branch.target, loop_flow_c->merge.target);
+ EXPECT_EQ(loop_flow_c->continuing.target->As<ir::Block>()->branch.target,
+ loop_flow_c->start.target);
+ EXPECT_EQ(loop_flow_c->merge.target->As<ir::Block>()->branch.target, loop_flow_d);
+ EXPECT_EQ(loop_flow_d->start.target->As<ir::Block>()->branch.target,
+ loop_flow_d->continuing.target);
+ EXPECT_EQ(loop_flow_d->continuing.target->As<ir::Block>()->branch.target, if_flow_c);
+ EXPECT_EQ(if_flow_c->true_.target->As<ir::Block>()->branch.target, loop_flow_d->merge.target);
+ EXPECT_EQ(if_flow_c->false_.target->As<ir::Block>()->branch.target, if_flow_c->merge.target);
+ EXPECT_EQ(if_flow_c->merge.target->As<ir::Block>()->branch.target, loop_flow_d->start.target);
+ EXPECT_EQ(loop_flow_d->merge.target->As<ir::Block>()->branch.target, loop_flow_b->start.target);
+ EXPECT_EQ(loop_flow_b->merge.target->As<ir::Block>()->branch.target, if_flow_d);
+ EXPECT_EQ(if_flow_d->true_.target->As<ir::Block>()->branch.target, loop_flow_a->merge.target);
+ EXPECT_EQ(if_flow_d->false_.target->As<ir::Block>()->branch.target, if_flow_d->merge.target);
+ EXPECT_EQ(if_flow_d->merge.target->As<ir::Block>()->branch.target,
+ loop_flow_a->continuing.target);
+ EXPECT_EQ(loop_flow_a->continuing.target->As<ir::Block>()->branch.target,
+ loop_flow_a->start.target);
+ EXPECT_EQ(loop_flow_a->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, While) {
@@ -886,36 +899,36 @@
ASSERT_TRUE(ir_while->Is<ir::Loop>());
auto* flow = ir_while->As<ir::Loop>();
- 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<ir::If>());
- auto* if_flow = flow->start_target->branch_target->As<ir::If>();
- 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<ir::Block>()->branch.target, nullptr);
+ ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
+ auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
+ 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(if_flow->merge.target->As<ir::Block>()->branch.target, flow->continuing.target);
+ EXPECT_EQ(flow->continuing.target->As<ir::Block>()->branch.target, flow->start.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
// Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>());
@@ -950,36 +963,36 @@
ASSERT_TRUE(ir_while->Is<ir::Loop>());
auto* flow = ir_while->As<ir::Loop>();
- 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<ir::If>());
- auto* if_flow = flow->start_target->branch_target->As<ir::If>();
- 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<ir::Block>()->branch.target, nullptr);
+ ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
+ auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
+ 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(if_flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->continuing.target->As<ir::Block>()->branch.target, flow->start.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
// TODO(dsinclair): Enable when variable declarations and increment are supported
@@ -1007,36 +1020,36 @@
ASSERT_TRUE(ir_for->Is<ir::Loop>());
auto* flow = ir_for->As<ir::Loop>();
- 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<ir::If>());
- auto* if_flow = flow->start_target->branch_target->As<ir::If>();
- 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<ir::Block>()->branch.target, nullptr);
+ ASSERT_TRUE(flow->start.target->As<ir::Block>()->branch.target->Is<ir::If>());
+ auto* if_flow = flow->start.target->As<ir::Block>()->branch.target->As<ir::If>();
+ 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<ir::Block>()->branch.target, if_flow);
+ EXPECT_EQ(if_flow->true_.target->As<ir::Block>()->branch.target, if_flow->merge.target);
+ EXPECT_EQ(if_flow->false_.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(if_flow->merge.target->As<ir::Block>()->branch.target, flow->continuing.target);
+ EXPECT_EQ(flow->continuing.target->As<ir::Block>()->branch.target, flow->start.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
// Check condition
ASSERT_TRUE(if_flow->condition->Is<Constant>());
@@ -1063,22 +1076,22 @@
ASSERT_TRUE(ir_for->Is<ir::Loop>());
auto* flow = ir_for->As<ir::Loop>();
- 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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->continuing.target->As<ir::Block>()->branch.target, flow->start.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Switch) {
@@ -1105,7 +1118,7 @@
ASSERT_TRUE(ir_switch->Is<ir::Switch>());
auto* flow = ir_switch->As<ir::Switch>();
- 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 @@
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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->cases[1].start.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->cases[2].start.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
// Check condition
ASSERT_TRUE(flow->condition->Is<Constant>());
@@ -1157,7 +1170,7 @@
ASSERT_TRUE(ir_switch->Is<ir::Switch>());
auto* flow = ir_switch->As<ir::Switch>();
- 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 @@
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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Switch_WithBreak) {
@@ -1207,7 +1220,7 @@
ASSERT_TRUE(ir_switch->Is<ir::Switch>());
auto* flow = ir_switch->As<ir::Switch>();
- 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 @@
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<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->cases[1].start.target->As<ir::Block>()->branch.target, flow->merge.target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, func->end_target);
}
TEST_F(IR_BuilderImplTest, Switch_AllReturn) {
@@ -1271,7 +1284,7 @@
ASSERT_TRUE(ir_switch->Is<ir::Switch>());
auto* flow = ir_switch->As<ir::Switch>();
- 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 @@
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<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->cases[1].start.target->As<ir::Block>()->branch.target, func->end_target);
+ EXPECT_EQ(flow->merge.target->As<ir::Block>()->branch.target, nullptr);
}
TEST_F(IR_BuilderImplTest, EmitLiteral_Bool_True) {
@@ -1391,7 +1404,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 + 4
)");
}
@@ -1406,7 +1419,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 - 4
)");
}
@@ -1421,7 +1434,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 * 4
)");
}
@@ -1436,7 +1449,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 / 4
)");
}
@@ -1451,7 +1464,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 % 4
)");
}
@@ -1466,7 +1479,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 & 4
)");
}
@@ -1481,7 +1494,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 | 4
)");
}
@@ -1496,7 +1509,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 ^ 4
)");
}
@@ -1511,7 +1524,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = true && false
)");
}
@@ -1526,7 +1539,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = false || true
)");
}
@@ -1541,7 +1554,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 == 4
)");
}
@@ -1556,7 +1569,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 != 4
)");
}
@@ -1571,7 +1584,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 < 4
)");
}
@@ -1586,7 +1599,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 > 4
)");
}
@@ -1601,7 +1614,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 <= 4
)");
}
@@ -1616,7 +1629,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 >= 4
)");
}
@@ -1631,7 +1644,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 << 4
)");
}
@@ -1646,7 +1659,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
)");
}
@@ -1662,7 +1675,7 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
%2 (u32) = %1 (u32) + 9
%3 (bool) = 1 < %2 (u32)
@@ -1683,9 +1696,10 @@
ASSERT_TRUE(r) << b.error();
Disassembler d(b.builder.ir);
- d.EmitBlockInstructions(b.current_flow_block);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
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 aaff666..617b207 100644
--- a/src/tint/ir/debug.cc
+++ b/src/tint/ir/debug.cc
@@ -59,24 +59,24 @@
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 @@
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 c2b9f98..e65bcca 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -66,6 +66,16 @@
}
}
+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 @@
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 @@
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<Terminator>()) {
+ 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 46b4ffd..03cbea1 100644
--- a/src/tint/ir/disassembler.h
+++ b/src/tint/ir/disassembler.h
@@ -17,6 +17,7 @@
#include <sstream>
#include <string>
+#include <unordered_map>
#include <unordered_set>
#include "src/tint/ir/flow_node.h"
@@ -46,11 +47,14 @@
private:
std::ostream& Indent();
void Walk(const FlowNode* node);
+ size_t GetIdForNode(const FlowNode* node);
const Module& mod_;
std::stringstream out_;
std::unordered_set<const FlowNode*> visited_;
std::unordered_set<const FlowNode*> stop_nodes_;
+ std::unordered_map<const FlowNode*, size_t> 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 3a366b3..5c4acaa 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 @@
~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 5db8379..2b026e6 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 @@
~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 7fad948..6d3a952 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 @@
/// The case selector for this node
utils::Vector<CaseSelector, 4> selectors;
/// The start block for the case block.
- Block* start_target;
+ Branch start = {};
};
/// Constructor
@@ -47,7 +48,7 @@
~Switch() override;
/// The switch merge target
- Block* merge_target;
+ Branch merge = {};
/// The switch case statements
utils::Vector<Case, 4> cases;