| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/control-flow-optimizer.h" | 5 #include "src/compiler/control-flow-optimizer.h" |
| 6 | 6 |
| 7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
| 8 #include "src/compiler/graph.h" | 8 #include "src/compiler/graph.h" |
| 9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
| 10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 if (NodeProperties::IsControlEdge(edge)) { | 56 if (NodeProperties::IsControlEdge(edge)) { |
| 57 Enqueue(edge.from()); | 57 Enqueue(edge.from()); |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 void ControlFlowOptimizer::VisitBranch(Node* node) { | 63 void ControlFlowOptimizer::VisitBranch(Node* node) { |
| 64 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 64 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
| 65 if (TryBuildSwitch(node)) return; | 65 if (TryBuildSwitch(node)) return; |
| 66 if (TryCloneBranch(node)) return; | |
| 67 VisitNode(node); | 66 VisitNode(node); |
| 68 } | 67 } |
| 69 | 68 |
| 70 | 69 |
| 71 bool ControlFlowOptimizer::TryCloneBranch(Node* node) { | |
| 72 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | |
| 73 | |
| 74 // This optimization is a special case of (super)block cloning. It takes an | |
| 75 // input graph as shown below and clones the Branch node for every predecessor | |
| 76 // to the Merge, essentially removing the Merge completely. This avoids | |
| 77 // materializing the bit for the Phi and may offer potential for further | |
| 78 // branch folding optimizations (i.e. because one or more inputs to the Phi is | |
| 79 // a constant). Note that there may be more Phi nodes hanging off the Merge, | |
| 80 // but we can only a certain subset of them currently (actually only Phi and | |
| 81 // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control | |
| 82 // input). | |
| 83 | |
| 84 // Control1 ... ControlN | |
| 85 // ^ ^ | |
| 86 // | | Cond1 ... CondN | |
| 87 // +----+ +----+ ^ ^ | |
| 88 // | | | | | |
| 89 // | | +----+ | | |
| 90 // Merge<--+ | +------------+ | |
| 91 // ^ \|/ | |
| 92 // | Phi | |
| 93 // | | | |
| 94 // Branch----+ | |
| 95 // ^ | |
| 96 // | | |
| 97 // +-----+-----+ | |
| 98 // | | | |
| 99 // IfTrue IfFalse | |
| 100 // ^ ^ | |
| 101 // | | | |
| 102 | |
| 103 // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: | |
| 104 | |
| 105 // Control1 Cond1 ... ControlN CondN | |
| 106 // ^ ^ ^ ^ | |
| 107 // \ / \ / | |
| 108 // Branch ... Branch | |
| 109 // ^ ^ | |
| 110 // | | | |
| 111 // +---+---+ +---+----+ | |
| 112 // | | | | | |
| 113 // IfTrue IfFalse ... IfTrue IfFalse | |
| 114 // ^ ^ ^ ^ | |
| 115 // | | | | | |
| 116 // +--+ +-------------+ | | |
| 117 // | | +--------------+ +--+ | |
| 118 // | | | | | |
| 119 // Merge Merge | |
| 120 // ^ ^ | |
| 121 // | | | |
| 122 | |
| 123 Node* branch = node; | |
| 124 Node* cond = NodeProperties::GetValueInput(branch, 0); | |
| 125 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false; | |
| 126 Node* merge = NodeProperties::GetControlInput(branch); | |
| 127 if (merge->opcode() != IrOpcode::kMerge || | |
| 128 NodeProperties::GetControlInput(cond) != merge) { | |
| 129 return false; | |
| 130 } | |
| 131 // Grab the IfTrue/IfFalse projections of the Branch. | |
| 132 BranchMatcher matcher(branch); | |
| 133 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. | |
| 134 NodeVector phis(zone()); | |
| 135 for (Node* const use : merge->uses()) { | |
| 136 if (use == branch || use == cond) continue; | |
| 137 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the | |
| 138 // Merge. Ideally, we would just clone the nodes (and everything that | |
| 139 // depends on it to some distant join point), but that requires knowledge | |
| 140 // about dominance/post-dominance. | |
| 141 if (!NodeProperties::IsPhi(use)) return false; | |
| 142 for (Edge edge : use->use_edges()) { | |
| 143 // Right now we can only handle Phi/EffectPhi nodes whose uses are | |
| 144 // directly control-dependend on either the IfTrue or the IfFalse | |
| 145 // successor, because we know exactly how to update those uses. | |
| 146 // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using | |
| 147 // dominance/post-dominance on the sea of nodes. | |
| 148 if (edge.from()->op()->ControlInputCount() != 1) return false; | |
| 149 Node* control = NodeProperties::GetControlInput(edge.from()); | |
| 150 if (NodeProperties::IsPhi(edge.from())) { | |
| 151 control = NodeProperties::GetControlInput(control, edge.index()); | |
| 152 } | |
| 153 if (control != matcher.IfTrue() && control != matcher.IfFalse()) | |
| 154 return false; | |
| 155 } | |
| 156 phis.push_back(use); | |
| 157 } | |
| 158 BranchHint const hint = BranchHintOf(branch->op()); | |
| 159 int const input_count = merge->op()->ControlInputCount(); | |
| 160 DCHECK_LE(1, input_count); | |
| 161 Node** const inputs = zone()->NewArray<Node*>(2 * input_count); | |
| 162 Node** const merge_true_inputs = &inputs[0]; | |
| 163 Node** const merge_false_inputs = &inputs[input_count]; | |
| 164 for (int index = 0; index < input_count; ++index) { | |
| 165 Node* cond1 = NodeProperties::GetValueInput(cond, index); | |
| 166 Node* control1 = NodeProperties::GetControlInput(merge, index); | |
| 167 Node* branch1 = graph()->NewNode(common()->Branch(hint), cond1, control1); | |
| 168 merge_true_inputs[index] = graph()->NewNode(common()->IfTrue(), branch1); | |
| 169 merge_false_inputs[index] = graph()->NewNode(common()->IfFalse(), branch1); | |
| 170 Enqueue(branch1); | |
| 171 } | |
| 172 Node* const merge_true = graph()->NewNode(common()->Merge(input_count), | |
| 173 input_count, merge_true_inputs); | |
| 174 Node* const merge_false = graph()->NewNode(common()->Merge(input_count), | |
| 175 input_count, merge_false_inputs); | |
| 176 for (Node* const phi : phis) { | |
| 177 for (int index = 0; index < input_count; ++index) { | |
| 178 inputs[index] = phi->InputAt(index); | |
| 179 } | |
| 180 inputs[input_count] = merge_true; | |
| 181 Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs); | |
| 182 inputs[input_count] = merge_false; | |
| 183 Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs); | |
| 184 for (Edge edge : phi->use_edges()) { | |
| 185 Node* control = NodeProperties::GetControlInput(edge.from()); | |
| 186 if (NodeProperties::IsPhi(edge.from())) { | |
| 187 control = NodeProperties::GetControlInput(control, edge.index()); | |
| 188 } | |
| 189 DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); | |
| 190 edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); | |
| 191 } | |
| 192 phi->Kill(); | |
| 193 } | |
| 194 // Fix up IfTrue and IfFalse and kill all dead nodes. | |
| 195 matcher.IfFalse()->ReplaceUses(merge_false); | |
| 196 matcher.IfTrue()->ReplaceUses(merge_true); | |
| 197 matcher.IfFalse()->Kill(); | |
| 198 matcher.IfTrue()->Kill(); | |
| 199 branch->Kill(); | |
| 200 cond->Kill(); | |
| 201 merge->Kill(); | |
| 202 return true; | |
| 203 } | |
| 204 | |
| 205 | |
| 206 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { | 70 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { |
| 207 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 71 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
| 208 | 72 |
| 209 Node* branch = node; | 73 Node* branch = node; |
| 210 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; | 74 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; |
| 211 Node* cond = NodeProperties::GetValueInput(branch, 0); | 75 Node* cond = NodeProperties::GetValueInput(branch, 0); |
| 212 if (cond->opcode() != IrOpcode::kWord32Equal) return false; | 76 if (cond->opcode() != IrOpcode::kWord32Equal) return false; |
| 213 Int32BinopMatcher m(cond); | 77 Int32BinopMatcher m(cond); |
| 214 Node* index = m.left().node(); | 78 Node* index = m.left().node(); |
| 215 if (!m.right().HasValue()) return false; | 79 if (!m.right().HasValue()) return false; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 if_false->ReplaceInput(0, node); | 133 if_false->ReplaceInput(0, node); |
| 270 NodeProperties::ChangeOp(if_false, common()->IfDefault()); | 134 NodeProperties::ChangeOp(if_false, common()->IfDefault()); |
| 271 Enqueue(if_false); | 135 Enqueue(if_false); |
| 272 branch->NullAllInputs(); | 136 branch->NullAllInputs(); |
| 273 return true; | 137 return true; |
| 274 } | 138 } |
| 275 | 139 |
| 276 } // namespace compiler | 140 } // namespace compiler |
| 277 } // namespace internal | 141 } // namespace internal |
| 278 } // namespace v8 | 142 } // namespace v8 |
| OLD | NEW |