[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;
/// @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>();
}
@ -49,7 +49,7 @@ class Block : public utils::Castable<Block, FlowNode> {
/// @param target the block to see if we trampoline too
/// @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) {
return false;
}
@ -78,9 +78,26 @@ class Block : public utils::Castable<Block, FlowNode> {
/// @returns the params to the block
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:
utils::Vector<const Instruction*, 16> instructions_;
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

View File

@ -16,13 +16,13 @@
#include <utility>
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/block.h"
TINT_INSTANTIATE_TYPEINFO(tint::ir::Branch);
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_);
to_->AddInboundBranch(this);
for (auto* arg : args) {

View File

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

View File

@ -402,7 +402,7 @@ class Builder {
/// @param to the node being branched too
/// @param args the branch arguments
/// @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`
/// @param type the parameter type

View File

@ -31,8 +31,8 @@ namespace tint::ir {
std::string Debug::AsDotGraph(const Module* mod) {
size_t node_count = 0;
std::unordered_set<const FlowNode*> visited;
std::unordered_set<const FlowNode*> merge_nodes;
std::unordered_set<const Block*> visited;
std::unordered_set<const Block*> merge_nodes;
std::unordered_map<const FlowNode*, std::string> node_to_name;
utils::StringStream out;
@ -48,7 +48,7 @@ std::string Debug::AsDotGraph(const Module* mod) {
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) {
return;
}

View File

@ -16,7 +16,6 @@
#define SRC_TINT_IR_FLOW_NODE_H_
#include "src/tint/utils/castable.h"
#include "src/tint/utils/vector.h"
// Forward Declarations
namespace tint::ir {
@ -30,30 +29,9 @@ class FlowNode : public utils::Castable<FlowNode> {
public:
~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:
/// Constructor
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

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
// `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.
bool IsConnected(const FlowNode* b, uint32_t count) {
// Function is always connected as it's the start.
if (b->Is<ir::Function>()) {
return true;
}
bool IsConnected(const Block* b, uint32_t count) {
return b->InboundBranches().Length() > count;
}
@ -170,7 +166,7 @@ class Impl {
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_->HasBranchTarget());
@ -178,7 +174,7 @@ class Impl {
current_flow_block_ = nullptr;
}
void BranchToIfNeeded(FlowNode* node) {
void BranchToIfNeeded(Block* node) {
if (!current_flow_block_ || current_flow_block_->HasBranchTarget()) {
return;
}
@ -752,7 +748,7 @@ class Impl {
// 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
// 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.
void EmitDiscard(const ast::DiscardStatement*) {
auto* inst = builder_.Discard();

View File

@ -98,7 +98,7 @@ class State {
if (!ret_ty) {
return nullptr;
}
auto* body = FlowNodeGraph(fn->StartTarget());
auto* body = BlockGraph(fn->StartTarget());
if (!body) {
return nullptr;
}
@ -108,13 +108,13 @@ class State {
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
utils::Vector<const ast::Statement*,
decltype(ast::BlockStatement::statements)::static_length>
stmts;
const ir::FlowNode* block = start_node;
const ir::Block* block = start_node;
// TODO(crbug.com/tint/1902): Handle block arguments.
@ -171,7 +171,7 @@ class State {
const ast::IfStatement* If(const ir::If* i) {
SCOPED_NESTING();
auto* cond = Expr(i->Condition());
auto* t = FlowNodeGraph(i->True());
auto* t = BlockGraph(i->True());
if (TINT_UNLIKELY(!t)) {
return nullptr;
}
@ -187,7 +187,7 @@ class State {
}
return b.If(cond, t, b.Else(f));
} else {
auto* f = FlowNodeGraph(i->False());
auto* f = BlockGraph(i->False());
if (!f) {
return nullptr;
}
@ -210,7 +210,7 @@ class State {
s->Cases(), //
[&](const ir::Switch::Case c) -> const tint::ast::CaseStatement* {
SCOPED_NESTING();
auto* body = FlowNodeGraph(c.start);
auto* body = BlockGraph(c.start);
if (!body) {
return nullptr;
}
@ -270,7 +270,7 @@ class State {
}
/// @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()) {
return true;
}