Index: src/compiler/control-reducer.cc |
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc |
index 08182703b4bac886e4112ae517f17c822c738df4..9856eee6957602b0cb677acbf9b1d878dcfd86ce 100644 |
--- a/src/compiler/control-reducer.cc |
+++ b/src/compiler/control-reducer.cc |
@@ -56,7 +56,8 @@ class ControlReducerImpl { |
common_(common), |
state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), |
stack_(zone_), |
- revisit_(zone_) {} |
+ revisit_(zone_), |
+ max_phis_for_select_(0) {} |
Zone* zone_; |
JSGraph* jsgraph_; |
@@ -64,6 +65,7 @@ class ControlReducerImpl { |
ZoneVector<VisitState> state_; |
ZoneDeque<Node*> stack_; |
ZoneDeque<Node*> revisit_; |
+ int max_phis_for_select_; |
void Reduce() { |
Push(graph()->end()); |
@@ -536,7 +538,7 @@ class ControlReducerImpl { |
if (live == 0) return dead(); // no remaining inputs. |
// Gather phis and effect phis to be edited. |
- ZoneVector<Node*> phis(zone_); |
+ NodeVector phis(zone_); |
for (Node* const use : node->uses()) { |
if (NodeProperties::IsPhi(use)) phis.push_back(use); |
} |
@@ -564,25 +566,49 @@ class ControlReducerImpl { |
DCHECK_EQ(live, node->InputCount()); |
- // Check if it's an unused diamond. |
- if (live == 2 && phis.empty()) { |
+ // Try to remove dead diamonds or introduce selects. |
+ if (live == 2 && CheckPhisForSelect(phis)) { |
DiamondMatcher matcher(node); |
if (matcher.Matched() && matcher.IfProjectionsAreOwned()) { |
- // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
- // have uses except for the Merge and the Merge has no Phi or |
- // EffectPhi uses, so replace the Merge with the control input of the |
- // diamond. |
- TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", |
- matcher.Branch()->id(), matcher.IfTrue()->id(), |
- matcher.IfFalse()->id()); |
- // TODO(turbofan): replace single-phi diamonds with selects. |
- return NodeProperties::GetControlInput(matcher.Branch()); |
+ // Dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
+ // have uses except for the Merge. Remove the branch if there |
+ // are no phis or replace phis with selects. |
+ Node* control = NodeProperties::GetControlInput(matcher.Branch()); |
+ if (phis.size() == 0) { |
+ // No phis. Remove the branch altogether. |
+ TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", |
+ matcher.Branch()->id(), matcher.IfTrue()->id(), |
+ matcher.IfFalse()->id()); |
+ return control; |
+ } else { |
+ // A small number of phis. Replace with selects. |
+ Node* cond = matcher.Branch()->InputAt(0); |
+ for (Node* phi : phis) { |
+ Node* select = graph()->NewNode( |
+ common_->Select(OpParameter<MachineType>(phi), |
+ BranchHintOf(matcher.Branch()->op())), |
+ cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi)); |
+ TRACE(" MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n", |
+ matcher.Branch()->id(), matcher.IfTrue()->id(), |
+ matcher.IfFalse()->id(), select->id()); |
+ ReplaceNode(phi, select); |
+ } |
+ return control; |
+ } |
} |
} |
return node; |
} |
+ bool CheckPhisForSelect(const NodeVector& phis) { |
+ if (phis.size() > static_cast<size_t>(max_phis_for_select_)) return false; |
+ for (Node* phi : phis) { |
+ if (phi->opcode() != IrOpcode::kPhi) return false; // no EffectPhis. |
+ } |
+ return true; |
+ } |
+ |
// Reduce if projections if the branch has a constant input. |
Node* ReduceIfProjection(Node* node, Decision decision) { |
Node* branch = node->InputAt(0); |
@@ -638,8 +664,10 @@ class ControlReducerImpl { |
void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, |
- CommonOperatorBuilder* common) { |
+ CommonOperatorBuilder* common, |
+ int max_phis_for_select) { |
ControlReducerImpl impl(zone, jsgraph, common); |
+ impl.max_phis_for_select_ = max_phis_for_select; |
impl.Reduce(); |
} |
@@ -651,9 +679,11 @@ void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { |
Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, |
- CommonOperatorBuilder* common, Node* node) { |
+ CommonOperatorBuilder* common, Node* node, |
+ int max_phis_for_select) { |
Zone zone; |
ControlReducerImpl impl(&zone, jsgraph, common); |
+ impl.max_phis_for_select_ = max_phis_for_select; |
return impl.ReduceMerge(node); |
} |