[ir] Convert FlowNode to Block where possible.

This CL updates a bunch of uses of FlowNode to use Block instead. The
InboundBranches are moved from FlowNode to Block.

Bug: tint:1718
Change-Id: Ic1c07dae103e25364a3a6b3333cfcb57d10b30c2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/134260
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2023-05-24 20:14:14 +00:00 committed by Dawn LUCI CQ
parent 0089d5e6e2
commit f55ef5e48b
9 changed files with 41 additions and 50 deletions

View File

@ -35,7 +35,7 @@ class Block : public utils::Castable<Block, FlowNode> {
~Block() override; ~Block() override;
/// @returns true if this is block has a branch target set /// @returns true if this is block has a branch target set
bool HasBranchTarget() const override { bool HasBranchTarget() const {
return !instructions_.IsEmpty() && instructions_.Back()->Is<ir::Branch>(); return !instructions_.IsEmpty() && instructions_.Back()->Is<ir::Branch>();
} }
@ -49,7 +49,7 @@ class Block : public utils::Castable<Block, FlowNode> {
/// @param target the block to see if we trampoline too /// @param target the block to see if we trampoline too
/// @returns if this block just branches to the provided target. /// @returns if this block just branches to the provided target.
bool IsTrampoline(const FlowNode* target) const { bool IsTrampoline(const Block* target) const {
if (instructions_.Length() != 1) { if (instructions_.Length() != 1) {
return false; return false;
} }
@ -78,9 +78,26 @@ class Block : public utils::Castable<Block, FlowNode> {
/// @returns the params to the block /// @returns the params to the block
utils::Vector<const BlockParam*, 0>& Params() { return params_; } utils::Vector<const BlockParam*, 0>& Params() { return params_; }
/// @returns true if this node has inbound branches and branches out
bool IsConnected() const { return HasBranchTarget(); }
/// @returns the inbound branch list for the flow node
utils::VectorRef<ir::Branch*> InboundBranches() const { return inbound_branches_; }
/// Adds the given node to the inbound branches
/// @param node the node to add
void AddInboundBranch(ir::Branch* node) { inbound_branches_.Push(node); }
private: private:
utils::Vector<const Instruction*, 16> instructions_; utils::Vector<const Instruction*, 16> instructions_;
utils::Vector<const BlockParam*, 0> params_; utils::Vector<const BlockParam*, 0> params_;
/// The list of flow nodes which branch into this node. This list maybe empty for several
/// reasons:
/// - Node is a start node
/// - Node is a merge target outside control flow (e.g. an if that returns in both branches)
/// - Node is a continue target outside control flow (e.g. a loop that returns)
utils::Vector<ir::Branch*, 2> inbound_branches_;
}; };
} // namespace tint::ir } // namespace tint::ir

View File

@ -16,13 +16,13 @@
#include <utility> #include <utility>
#include "src/tint/ir/flow_node.h" #include "src/tint/ir/block.h"
TINT_INSTANTIATE_TYPEINFO(tint::ir::Branch); TINT_INSTANTIATE_TYPEINFO(tint::ir::Branch);
namespace tint::ir { namespace tint::ir {
Branch::Branch(FlowNode* to, utils::VectorRef<Value*> args) : to_(to), args_(std::move(args)) { Branch::Branch(Block* to, utils::VectorRef<Value*> args) : to_(to), args_(std::move(args)) {
TINT_ASSERT(IR, to_); TINT_ASSERT(IR, to_);
to_->AddInboundBranch(this); to_->AddInboundBranch(this);
for (auto* arg : args) { for (auto* arg : args) {

View File

@ -21,7 +21,7 @@
// Forward declarations // Forward declarations
namespace tint::ir { namespace tint::ir {
class FlowNode; class Block;
} // namespace tint::ir } // namespace tint::ir
namespace tint::ir { namespace tint::ir {
@ -32,17 +32,17 @@ class Branch : public utils::Castable<Branch, Instruction> {
/// Constructor /// Constructor
/// @param to the block to branch too /// @param to the block to branch too
/// @param args the branch arguments /// @param args the branch arguments
explicit Branch(FlowNode* to, utils::VectorRef<Value*> args = {}); explicit Branch(Block* to, utils::VectorRef<Value*> args = {});
~Branch() override; ~Branch() override;
/// @returns the block being branched too. /// @returns the block being branched too.
const FlowNode* To() const { return to_; } const Block* To() const { return to_; }
/// @returns the branch arguments /// @returns the branch arguments
utils::VectorRef<Value*> Args() const { return args_; } utils::VectorRef<Value*> Args() const { return args_; }
private: private:
FlowNode* to_; Block* to_;
utils::Vector<Value*, 2> args_; utils::Vector<Value*, 2> args_;
}; };

View File

@ -217,7 +217,7 @@ ir::Var* Builder::Declare(const type::Type* type) {
return ir.values.Create<ir::Var>(type); return ir.values.Create<ir::Var>(type);
} }
ir::Branch* Builder::Branch(FlowNode* to, utils::VectorRef<Value*> args) { ir::Branch* Builder::Branch(Block* to, utils::VectorRef<Value*> args) {
return ir.values.Create<ir::Branch>(to, args); return ir.values.Create<ir::Branch>(to, args);
} }

View File

@ -402,7 +402,7 @@ class Builder {
/// @param to the node being branched too /// @param to the node being branched too
/// @param args the branch arguments /// @param args the branch arguments
/// @returns the instruction /// @returns the instruction
ir::Branch* Branch(FlowNode* to, utils::VectorRef<Value*> args = {}); ir::Branch* Branch(Block* to, utils::VectorRef<Value*> args = {});
/// Creates a new `BlockParam` /// Creates a new `BlockParam`
/// @param type the parameter type /// @param type the parameter type

View File

@ -31,8 +31,8 @@ namespace tint::ir {
std::string Debug::AsDotGraph(const Module* mod) { std::string Debug::AsDotGraph(const Module* mod) {
size_t node_count = 0; size_t node_count = 0;
std::unordered_set<const FlowNode*> visited; std::unordered_set<const Block*> visited;
std::unordered_set<const FlowNode*> merge_nodes; std::unordered_set<const Block*> merge_nodes;
std::unordered_map<const FlowNode*, std::string> node_to_name; std::unordered_map<const FlowNode*, std::string> node_to_name;
utils::StringStream out; utils::StringStream out;
@ -48,7 +48,7 @@ std::string Debug::AsDotGraph(const Module* mod) {
return name; return name;
}; };
std::function<void(const FlowNode*)> Graph = [&](const FlowNode* node) { std::function<void(const Block*)> Graph = [&](const Block* node) {
if (visited.count(node) > 0) { if (visited.count(node) > 0) {
return; return;
} }

View File

@ -16,7 +16,6 @@
#define SRC_TINT_IR_FLOW_NODE_H_ #define SRC_TINT_IR_FLOW_NODE_H_
#include "src/tint/utils/castable.h" #include "src/tint/utils/castable.h"
#include "src/tint/utils/vector.h"
// Forward Declarations // Forward Declarations
namespace tint::ir { namespace tint::ir {
@ -30,30 +29,9 @@ class FlowNode : public utils::Castable<FlowNode> {
public: public:
~FlowNode() override; ~FlowNode() override;
/// @returns true if this node has inbound branches and branches out
bool IsConnected() const { return HasBranchTarget(); }
/// @returns true if the node has a branch target
virtual bool HasBranchTarget() const { return false; }
/// @returns the inbound branch list for the flow node
utils::VectorRef<Branch*> InboundBranches() const { return inbound_branches_; }
/// Adds the given node to the inbound branches
/// @param node the node to add
void AddInboundBranch(Branch* node) { inbound_branches_.Push(node); }
protected: protected:
/// Constructor /// Constructor
FlowNode(); FlowNode();
private:
/// The list of flow nodes which branch into this node. This list maybe empty for several
/// reasons:
/// - Node is a start node
/// - Node is a merge target outside control flow (e.g. an if that returns in both branches)
/// - Node is a continue target outside control flow (e.g. a loop that returns)
utils::Vector<Branch*, 2> inbound_branches_;
}; };
} // namespace tint::ir } // namespace tint::ir

View File

@ -101,11 +101,7 @@ using ResultType = utils::Result<Module, diag::List>;
// For an `if` and `switch` block, the merge has a registered incoming branch instruction of the // For an `if` and `switch` block, the merge has a registered incoming branch instruction of the
// `if` and `switch. So, to determine if the merge is connected to any of the branches that happend // `if` and `switch. So, to determine if the merge is connected to any of the branches that happend
// in the `if` or `switch` we need a `count` value that is larger then 1. // in the `if` or `switch` we need a `count` value that is larger then 1.
bool IsConnected(const FlowNode* b, uint32_t count) { bool IsConnected(const Block* b, uint32_t count) {
// Function is always connected as it's the start.
if (b->Is<ir::Function>()) {
return true;
}
return b->InboundBranches().Length() > count; return b->InboundBranches().Length() > count;
} }
@ -170,7 +166,7 @@ class Impl {
diagnostics_.add_error(tint::diag::System::IR, err, s); diagnostics_.add_error(tint::diag::System::IR, err, s);
} }
void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) { void BranchTo(Block* node, utils::VectorRef<Value*> args = {}) {
TINT_ASSERT(IR, current_flow_block_); TINT_ASSERT(IR, current_flow_block_);
TINT_ASSERT(IR, !current_flow_block_->HasBranchTarget()); TINT_ASSERT(IR, !current_flow_block_->HasBranchTarget());
@ -178,7 +174,7 @@ class Impl {
current_flow_block_ = nullptr; current_flow_block_ = nullptr;
} }
void BranchToIfNeeded(FlowNode* node) { void BranchToIfNeeded(Block* node) {
if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) { if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
return; return;
} }
@ -752,7 +748,7 @@ class Impl {
// Discard is being treated as an instruction. The semantics in WGSL is demote_to_helper, so // Discard is being treated as an instruction. The semantics in WGSL is demote_to_helper, so
// the code has to continue as before it just predicates writes. If WGSL grows some kind of // the code has to continue as before it just predicates writes. If WGSL grows some kind of
// terminating discard that would probably make sense as a FlowNode but would then require // terminating discard that would probably make sense as a Block but would then require
// figuring out the multi-level exit that is triggered. // figuring out the multi-level exit that is triggered.
void EmitDiscard(const ast::DiscardStatement*) { void EmitDiscard(const ast::DiscardStatement*) {
auto* inst = builder_.Discard(); auto* inst = builder_.Discard();

View File

@ -98,7 +98,7 @@ class State {
if (!ret_ty) { if (!ret_ty) {
return nullptr; return nullptr;
} }
auto* body = FlowNodeGraph(fn->StartTarget()); auto* body = BlockGraph(fn->StartTarget());
if (!body) { if (!body) {
return nullptr; return nullptr;
} }
@ -108,13 +108,13 @@ class State {
std::move(ret_attrs)); std::move(ret_attrs));
} }
const ast::BlockStatement* FlowNodeGraph(const ir::Block* start_node) { const ast::BlockStatement* BlockGraph(const ir::Block* start_node) {
// TODO(crbug.com/tint/1902): Check if the block is dead // TODO(crbug.com/tint/1902): Check if the block is dead
utils::Vector<const ast::Statement*, utils::Vector<const ast::Statement*,
decltype(ast::BlockStatement::statements)::static_length> decltype(ast::BlockStatement::statements)::static_length>
stmts; stmts;
const ir::FlowNode* block = start_node; const ir::Block* block = start_node;
// TODO(crbug.com/tint/1902): Handle block arguments. // TODO(crbug.com/tint/1902): Handle block arguments.
@ -171,7 +171,7 @@ class State {
const ast::IfStatement* If(const ir::If* i) { const ast::IfStatement* If(const ir::If* i) {
SCOPED_NESTING(); SCOPED_NESTING();
auto* cond = Expr(i->Condition()); auto* cond = Expr(i->Condition());
auto* t = FlowNodeGraph(i->True()); auto* t = BlockGraph(i->True());
if (TINT_UNLIKELY(!t)) { if (TINT_UNLIKELY(!t)) {
return nullptr; return nullptr;
} }
@ -187,7 +187,7 @@ class State {
} }
return b.If(cond, t, b.Else(f)); return b.If(cond, t, b.Else(f));
} else { } else {
auto* f = FlowNodeGraph(i->False()); auto* f = BlockGraph(i->False());
if (!f) { if (!f) {
return nullptr; return nullptr;
} }
@ -210,7 +210,7 @@ class State {
s->Cases(), // s->Cases(), //
[&](const ir::Switch::Case c) -> const tint::ast::CaseStatement* { [&](const ir::Switch::Case c) -> const tint::ast::CaseStatement* {
SCOPED_NESTING(); SCOPED_NESTING();
auto* body = FlowNodeGraph(c.start); auto* body = BlockGraph(c.start);
if (!body) { if (!body) {
return nullptr; return nullptr;
} }
@ -270,7 +270,7 @@ class State {
} }
/// @return true if there are no instructions between @p node and and @p stop_at /// @return true if there are no instructions between @p node and and @p stop_at
bool IsEmpty(const ir::Block* node, const ir::FlowNode* stop_at) { bool IsEmpty(const ir::Block* node, const ir::Block* stop_at) {
if (node->Instructions().IsEmpty()) { if (node->Instructions().IsEmpty()) {
return true; return true;
} }