Index: src/compiler/control-flow-optimizer.cc |
diff --git a/src/compiler/control-flow-optimizer.cc b/src/compiler/control-flow-optimizer.cc |
index 3fc3bcefaca43f67292ca90827362139117f02e5..6027c8201cf6dd8c860aac21099af6cf1f6a770e 100644 |
--- a/src/compiler/control-flow-optimizer.cc |
+++ b/src/compiler/control-flow-optimizer.cc |
@@ -63,146 +63,10 @@ void ControlFlowOptimizer::VisitNode(Node* node) { |
void ControlFlowOptimizer::VisitBranch(Node* node) { |
DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
if (TryBuildSwitch(node)) return; |
- if (TryCloneBranch(node)) return; |
VisitNode(node); |
} |
-bool ControlFlowOptimizer::TryCloneBranch(Node* node) { |
- DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
- |
- // This optimization is a special case of (super)block cloning. It takes an |
- // input graph as shown below and clones the Branch node for every predecessor |
- // to the Merge, essentially removing the Merge completely. This avoids |
- // materializing the bit for the Phi and may offer potential for further |
- // branch folding optimizations (i.e. because one or more inputs to the Phi is |
- // a constant). Note that there may be more Phi nodes hanging off the Merge, |
- // but we can only a certain subset of them currently (actually only Phi and |
- // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control |
- // input). |
- |
- // Control1 ... ControlN |
- // ^ ^ |
- // | | Cond1 ... CondN |
- // +----+ +----+ ^ ^ |
- // | | | | |
- // | | +----+ | |
- // Merge<--+ | +------------+ |
- // ^ \|/ |
- // | Phi |
- // | | |
- // Branch----+ |
- // ^ |
- // | |
- // +-----+-----+ |
- // | | |
- // IfTrue IfFalse |
- // ^ ^ |
- // | | |
- |
- // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: |
- |
- // Control1 Cond1 ... ControlN CondN |
- // ^ ^ ^ ^ |
- // \ / \ / |
- // Branch ... Branch |
- // ^ ^ |
- // | | |
- // +---+---+ +---+----+ |
- // | | | | |
- // IfTrue IfFalse ... IfTrue IfFalse |
- // ^ ^ ^ ^ |
- // | | | | |
- // +--+ +-------------+ | |
- // | | +--------------+ +--+ |
- // | | | | |
- // Merge Merge |
- // ^ ^ |
- // | | |
- |
- Node* branch = node; |
- Node* cond = NodeProperties::GetValueInput(branch, 0); |
- if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false; |
- Node* merge = NodeProperties::GetControlInput(branch); |
- if (merge->opcode() != IrOpcode::kMerge || |
- NodeProperties::GetControlInput(cond) != merge) { |
- return false; |
- } |
- // Grab the IfTrue/IfFalse projections of the Branch. |
- BranchMatcher matcher(branch); |
- // Check/collect other Phi/EffectPhi nodes hanging off the Merge. |
- NodeVector phis(zone()); |
- for (Node* const use : merge->uses()) { |
- if (use == branch || use == cond) continue; |
- // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the |
- // Merge. Ideally, we would just clone the nodes (and everything that |
- // depends on it to some distant join point), but that requires knowledge |
- // about dominance/post-dominance. |
- if (!NodeProperties::IsPhi(use)) return false; |
- for (Edge edge : use->use_edges()) { |
- // Right now we can only handle Phi/EffectPhi nodes whose uses are |
- // directly control-dependend on either the IfTrue or the IfFalse |
- // successor, because we know exactly how to update those uses. |
- // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using |
- // dominance/post-dominance on the sea of nodes. |
- if (edge.from()->op()->ControlInputCount() != 1) return false; |
- Node* control = NodeProperties::GetControlInput(edge.from()); |
- if (NodeProperties::IsPhi(edge.from())) { |
- control = NodeProperties::GetControlInput(control, edge.index()); |
- } |
- if (control != matcher.IfTrue() && control != matcher.IfFalse()) |
- return false; |
- } |
- phis.push_back(use); |
- } |
- BranchHint const hint = BranchHintOf(branch->op()); |
- int const input_count = merge->op()->ControlInputCount(); |
- DCHECK_LE(1, input_count); |
- Node** const inputs = zone()->NewArray<Node*>(2 * input_count); |
- Node** const merge_true_inputs = &inputs[0]; |
- Node** const merge_false_inputs = &inputs[input_count]; |
- for (int index = 0; index < input_count; ++index) { |
- Node* cond1 = NodeProperties::GetValueInput(cond, index); |
- Node* control1 = NodeProperties::GetControlInput(merge, index); |
- Node* branch1 = graph()->NewNode(common()->Branch(hint), cond1, control1); |
- merge_true_inputs[index] = graph()->NewNode(common()->IfTrue(), branch1); |
- merge_false_inputs[index] = graph()->NewNode(common()->IfFalse(), branch1); |
- Enqueue(branch1); |
- } |
- Node* const merge_true = graph()->NewNode(common()->Merge(input_count), |
- input_count, merge_true_inputs); |
- Node* const merge_false = graph()->NewNode(common()->Merge(input_count), |
- input_count, merge_false_inputs); |
- for (Node* const phi : phis) { |
- for (int index = 0; index < input_count; ++index) { |
- inputs[index] = phi->InputAt(index); |
- } |
- inputs[input_count] = merge_true; |
- Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs); |
- inputs[input_count] = merge_false; |
- Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs); |
- for (Edge edge : phi->use_edges()) { |
- Node* control = NodeProperties::GetControlInput(edge.from()); |
- if (NodeProperties::IsPhi(edge.from())) { |
- control = NodeProperties::GetControlInput(control, edge.index()); |
- } |
- DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); |
- edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); |
- } |
- phi->Kill(); |
- } |
- // Fix up IfTrue and IfFalse and kill all dead nodes. |
- matcher.IfFalse()->ReplaceUses(merge_false); |
- matcher.IfTrue()->ReplaceUses(merge_true); |
- matcher.IfFalse()->Kill(); |
- matcher.IfTrue()->Kill(); |
- branch->Kill(); |
- cond->Kill(); |
- merge->Kill(); |
- return true; |
-} |
- |
- |
bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { |
DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |