[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:
parent
0089d5e6e2
commit
f55ef5e48b
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue