Commit c56ffe13 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[csa][torque] eliminate unnecessary phi nodes in the CSA pipeline

This removes the burden from Torque not to emit unnecessary phis.
This is factored out from the Torque IR CL (https://crrev.com/c/1245766).

Change-Id: I302714250e9ea6367f37613c09caa522d56c151c
Reviewed-on: https://chromium-review.googlesource.com/1254121Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56312}
parent 0503f195
......@@ -42,48 +42,36 @@ bool BasicBlock::LoopContains(BasicBlock* block) const {
block->rpo_number_ < loop_end_->rpo_number_;
}
void BasicBlock::AddSuccessor(BasicBlock* successor) {
successors_.push_back(successor);
}
void BasicBlock::AddPredecessor(BasicBlock* predecessor) {
predecessors_.push_back(predecessor);
}
void BasicBlock::AddNode(Node* node) { nodes_.push_back(node); }
void BasicBlock::set_control(Control control) {
control_ = control;
}
void BasicBlock::set_control(Control control) { control_ = control; }
void BasicBlock::set_control_input(Node* control_input) {
control_input_ = control_input;
}
void BasicBlock::set_loop_depth(int32_t loop_depth) {
loop_depth_ = loop_depth;
}
void BasicBlock::set_rpo_number(int32_t rpo_number) {
rpo_number_ = rpo_number;
}
void BasicBlock::set_loop_end(BasicBlock* loop_end) { loop_end_ = loop_end; }
void BasicBlock::set_loop_header(BasicBlock* loop_header) {
loop_header_ = loop_header;
}
// static
BasicBlock* BasicBlock::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
while (b1 != b2) {
......@@ -141,12 +129,10 @@ std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
UNREACHABLE();
}
std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id) {
return os << id.ToSize();
}
Schedule::Schedule(Zone* zone, size_t node_count_hint)
: zone_(zone),
all_blocks_(zone),
......@@ -157,7 +143,6 @@ Schedule::Schedule(Zone* zone, size_t node_count_hint)
nodeid_to_block_.reserve(node_count_hint);
}
BasicBlock* Schedule::block(Node* node) const {
if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) {
return nodeid_to_block_[node->id()];
......@@ -165,25 +150,21 @@ BasicBlock* Schedule::block(Node* node) const {
return nullptr;
}
bool Schedule::IsScheduled(Node* node) {
if (node->id() >= nodeid_to_block_.size()) return false;
return nodeid_to_block_[node->id()] != nullptr;
}
BasicBlock* Schedule::GetBlockById(BasicBlock::Id block_id) {
DCHECK(block_id.ToSize() < all_blocks_.size());
return all_blocks_[block_id.ToSize()];
}
bool Schedule::SameBasicBlock(Node* a, Node* b) const {
BasicBlock* block = this->block(a);
return block != nullptr && block == this->block(b);
}
BasicBlock* Schedule::NewBasicBlock() {
BasicBlock* block = new (zone_)
BasicBlock(zone_, BasicBlock::Id::FromSize(all_blocks_.size()));
......@@ -191,7 +172,6 @@ BasicBlock* Schedule::NewBasicBlock() {
return block;
}
void Schedule::PlanNode(BasicBlock* block, Node* node) {
if (FLAG_trace_turbo_scheduler) {
StdoutStream{} << "Planning #" << node->id() << ":"
......@@ -202,7 +182,6 @@ void Schedule::PlanNode(BasicBlock* block, Node* node) {
SetBlockForNode(block, node);
}
void Schedule::AddNode(BasicBlock* block, Node* node) {
if (FLAG_trace_turbo_scheduler) {
StdoutStream{} << "Adding #" << node->id() << ":" << node->op()->mnemonic()
......@@ -213,7 +192,6 @@ void Schedule::AddNode(BasicBlock* block, Node* node) {
SetBlockForNode(block, node);
}
void Schedule::AddGoto(BasicBlock* block, BasicBlock* succ) {
DCHECK_EQ(BasicBlock::kNone, block->control());
block->set_control(BasicBlock::kGoto);
......@@ -249,7 +227,6 @@ void Schedule::AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
SetControlInput(block, call);
}
void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
BasicBlock* fblock) {
DCHECK_EQ(BasicBlock::kNone, block->control());
......@@ -260,7 +237,6 @@ void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
SetControlInput(block, branch);
}
void Schedule::AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
size_t succ_count) {
DCHECK_EQ(BasicBlock::kNone, block->control());
......@@ -272,7 +248,6 @@ void Schedule::AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
SetControlInput(block, sw);
}
void Schedule::AddTailCall(BasicBlock* block, Node* input) {
DCHECK_EQ(BasicBlock::kNone, block->control());
block->set_control(BasicBlock::kTailCall);
......@@ -280,7 +255,6 @@ void Schedule::AddTailCall(BasicBlock* block, Node* input) {
if (block != end()) AddSuccessor(block, end());
}
void Schedule::AddReturn(BasicBlock* block, Node* input) {
DCHECK_EQ(BasicBlock::kNone, block->control());
block->set_control(BasicBlock::kReturn);
......@@ -288,7 +262,6 @@ void Schedule::AddReturn(BasicBlock* block, Node* input) {
if (block != end()) AddSuccessor(block, end());
}
void Schedule::AddDeoptimize(BasicBlock* block, Node* input) {
DCHECK_EQ(BasicBlock::kNone, block->control());
block->set_control(BasicBlock::kDeoptimize);
......@@ -296,7 +269,6 @@ void Schedule::AddDeoptimize(BasicBlock* block, Node* input) {
if (block != end()) AddSuccessor(block, end());
}
void Schedule::AddThrow(BasicBlock* block, Node* input) {
DCHECK_EQ(BasicBlock::kNone, block->control());
block->set_control(BasicBlock::kThrow);
......@@ -304,7 +276,6 @@ void Schedule::AddThrow(BasicBlock* block, Node* input) {
if (block != end()) AddSuccessor(block, end());
}
void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
BasicBlock* tblock, BasicBlock* fblock) {
DCHECK_NE(BasicBlock::kNone, block->control());
......@@ -320,7 +291,6 @@ void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
SetControlInput(block, branch);
}
void Schedule::InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw,
BasicBlock** succ_blocks, size_t succ_count) {
DCHECK_NE(BasicBlock::kNone, block->control());
......@@ -343,7 +313,7 @@ void Schedule::EnsureCFGWellFormedness() {
BasicBlockVector all_blocks_copy(all_blocks_);
// Insert missing split edge blocks.
for (auto block : all_blocks_copy) {
for (BasicBlock* block : all_blocks_copy) {
if (block->PredecessorCount() > 1) {
if (block != end_) {
EnsureSplitEdgeForm(block);
......@@ -351,24 +321,36 @@ void Schedule::EnsureCFGWellFormedness() {
if (block->deferred()) {
EnsureDeferredCodeSingleEntryPoint(block);
}
} else {
EliminateNoopPhiNodes(block);
}
}
}
void Schedule::EliminateNoopPhiNodes(BasicBlock* block) {
// Ensure that useless phi nodes in blocks that only have a single predecessor
// -- which can happen with the automatically generated code in the CSA and
// torque -- are pruned.
if (block->PredecessorCount() == 1) {
for (size_t i = 0; i < block->NodeCount();) {
Node* node = block->NodeAt(i);
if (node->opcode() == IrOpcode::kPhi) {
node->ReplaceUses(node->InputAt(0));
block->RemoveNode(block->begin() + i);
} else {
++i;
EliminateNoopPhiNodes();
}
void Schedule::EliminateNoopPhiNodes() {
bool reached_fixed_point = false;
while (!reached_fixed_point) {
reached_fixed_point = true;
for (BasicBlock* block : all_blocks_) {
int predecessor_count = static_cast<int>(block->PredecessorCount());
for (size_t node_pos = 0; node_pos < block->NodeCount(); ++node_pos) {
Node* node = block->NodeAt(node_pos);
if (node->opcode() == IrOpcode::kPhi) {
Node* first_input = node->InputAt(0);
bool inputs_equal = true;
for (int i = 1; i < predecessor_count; ++i) {
Node* input = node->InputAt(i);
if (input != first_input && input != node) {
inputs_equal = false;
break;
}
}
if (!inputs_equal) continue;
node->ReplaceUses(first_input);
block->RemoveNode(block->begin() + node_pos);
--node_pos;
reached_fixed_point = false;
}
}
}
}
......@@ -481,7 +463,6 @@ void Schedule::AddSuccessor(BasicBlock* block, BasicBlock* succ) {
succ->AddPredecessor(block);
}
void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
for (BasicBlock* const successor : from->successors()) {
to->AddSuccessor(successor);
......@@ -492,13 +473,11 @@ void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
from->ClearSuccessors();
}
void Schedule::SetControlInput(BasicBlock* block, Node* node) {
block->set_control_input(node);
SetBlockForNode(block, node);
}
void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
if (node->id() >= nodeid_to_block_.size()) {
nodeid_to_block_.resize(node->id() + 1);
......@@ -506,7 +485,6 @@ void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
nodeid_to_block_[node->id()] = block;
}
std::ostream& operator<<(std::ostream& os, const Schedule& s) {
for (BasicBlock* block :
((s.RpoBlockCount() == 0) ? *s.all_blocks() : *s.rpo_order())) {
......
......@@ -166,12 +166,12 @@ class V8_EXPORT_PRIVATE BasicBlock final
BasicBlock* loop_header_; // Pointer to dominating loop header basic block,
// nullptr if none. For loop headers, this points to
// enclosing loop header.
BasicBlock* loop_end_; // end of the loop, if this block is a loop header.
int32_t loop_depth_; // loop nesting, 0 is top-level
BasicBlock* loop_end_; // end of the loop, if this block is a loop header.
int32_t loop_depth_; // loop nesting, 0 is top-level
Control control_; // Control at the end of the block.
Node* control_input_; // Input value for control.
NodeVector nodes_; // nodes of this block in forward order.
Control control_; // Control at the end of the block.
Node* control_input_; // Input value for control.
NodeVector nodes_; // nodes of this block in forward order.
BasicBlockVector successors_;
BasicBlockVector predecessors_;
......@@ -187,7 +187,6 @@ std::ostream& operator<<(std::ostream&, const BasicBlock&);
std::ostream& operator<<(std::ostream&, const BasicBlock::Control&);
std::ostream& operator<<(std::ostream&, const BasicBlock::Id&);
// A schedule represents the result of assigning nodes to basic blocks
// and ordering them within basic blocks. Prior to computing a schedule,
// a graph has no notion of control flow ordering other than that induced
......@@ -272,12 +271,13 @@ class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) {
friend class BasicBlockInstrumentor;
friend class RawMachineAssembler;
// Ensure properties of the CFG assumed by further stages.
// For CSA/Torque: Ensure properties of the CFG assumed by further stages.
void EnsureCFGWellFormedness();
// Eliminates no-op phi nodes added for blocks that only have a single
// predecessor. This ensures the property required for SSA deconstruction that
// the target block of a control flow split has no phis.
void EliminateNoopPhiNodes(BasicBlock* block);
// For CSA/Torque: Eliminates unnecessary phi nodes, including phis with a
// single input. The latter is necessary to ensure the property required for
// SSA deconstruction that the target block of a control flow split has no
// phis.
void EliminateNoopPhiNodes();
// Ensure split-edge form for a hand-assembled schedule.
void EnsureSplitEdgeForm(BasicBlock* block);
// Ensure entry into a deferred block happens from a single hot block.
......@@ -294,9 +294,9 @@ class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) {
void SetBlockForNode(BasicBlock* block, Node* node);
Zone* zone_;
BasicBlockVector all_blocks_; // All basic blocks in the schedule.
BasicBlockVector nodeid_to_block_; // Map from node to containing block.
BasicBlockVector rpo_order_; // Reverse-post-order block list.
BasicBlockVector all_blocks_; // All basic blocks in the schedule.
BasicBlockVector nodeid_to_block_; // Map from node to containing block.
BasicBlockVector rpo_order_; // Reverse-post-order block list.
BasicBlock* start_;
BasicBlock* end_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment