| 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/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
| 9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
| 10 | 10 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 116 |
| 117 Node* branch = node; | 117 Node* branch = node; |
| 118 Node* cond = NodeProperties::GetValueInput(branch, 0); | 118 Node* cond = NodeProperties::GetValueInput(branch, 0); |
| 119 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false; | 119 if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return false; |
| 120 Node* merge = NodeProperties::GetControlInput(branch); | 120 Node* merge = NodeProperties::GetControlInput(branch); |
| 121 if (merge->opcode() != IrOpcode::kMerge || | 121 if (merge->opcode() != IrOpcode::kMerge || |
| 122 NodeProperties::GetControlInput(cond) != merge) { | 122 NodeProperties::GetControlInput(cond) != merge) { |
| 123 return false; | 123 return false; |
| 124 } | 124 } |
| 125 // Grab the IfTrue/IfFalse projections of the Branch. | 125 // Grab the IfTrue/IfFalse projections of the Branch. |
| 126 Node* control_projections[2]; | 126 BranchMatcher matcher(branch); |
| 127 NodeProperties::CollectControlProjections(branch, control_projections, | |
| 128 arraysize(control_projections)); | |
| 129 Node* if_true = control_projections[0]; | |
| 130 Node* if_false = control_projections[1]; | |
| 131 DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode()); | |
| 132 DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode()); | |
| 133 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. | 127 // Check/collect other Phi/EffectPhi nodes hanging off the Merge. |
| 134 NodeVector phis(zone()); | 128 NodeVector phis(zone()); |
| 135 for (Node* const use : merge->uses()) { | 129 for (Node* const use : merge->uses()) { |
| 136 if (use == branch || use == cond) continue; | 130 if (use == branch || use == cond) continue; |
| 137 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the | 131 // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the |
| 138 // Merge. Ideally, we would just clone the nodes (and everything that | 132 // Merge. Ideally, we would just clone the nodes (and everything that |
| 139 // depends on it to some distant join point), but that requires knowledge | 133 // depends on it to some distant join point), but that requires knowledge |
| 140 // about dominance/post-dominance. | 134 // about dominance/post-dominance. |
| 141 if (!NodeProperties::IsPhi(use)) return false; | 135 if (!NodeProperties::IsPhi(use)) return false; |
| 142 for (Edge edge : use->use_edges()) { | 136 for (Edge edge : use->use_edges()) { |
| 143 // Right now we can only handle Phi/EffectPhi nodes whose uses are | 137 // Right now we can only handle Phi/EffectPhi nodes whose uses are |
| 144 // directly control-dependend on either the IfTrue or the IfFalse | 138 // directly control-dependend on either the IfTrue or the IfFalse |
| 145 // successor, because we know exactly how to update those uses. | 139 // successor, because we know exactly how to update those uses. |
| 146 // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using | 140 // TODO(turbofan): Generalize this to all Phi/EffectPhi nodes using |
| 147 // dominance/post-dominance on the sea of nodes. | 141 // dominance/post-dominance on the sea of nodes. |
| 148 if (edge.from()->op()->ControlInputCount() != 1) return false; | 142 if (edge.from()->op()->ControlInputCount() != 1) return false; |
| 149 Node* control = NodeProperties::GetControlInput(edge.from()); | 143 Node* control = NodeProperties::GetControlInput(edge.from()); |
| 150 if (NodeProperties::IsPhi(edge.from())) { | 144 if (NodeProperties::IsPhi(edge.from())) { |
| 151 control = NodeProperties::GetControlInput(control, edge.index()); | 145 control = NodeProperties::GetControlInput(control, edge.index()); |
| 152 } | 146 } |
| 153 if (control != if_true && control != if_false) return false; | 147 if (control != matcher.IfTrue() && control != matcher.IfFalse()) |
| 148 return false; |
| 154 } | 149 } |
| 155 phis.push_back(use); | 150 phis.push_back(use); |
| 156 } | 151 } |
| 157 BranchHint const hint = BranchHintOf(branch->op()); | 152 BranchHint const hint = BranchHintOf(branch->op()); |
| 158 int const input_count = merge->op()->ControlInputCount(); | 153 int const input_count = merge->op()->ControlInputCount(); |
| 159 DCHECK_LE(1, input_count); | 154 DCHECK_LE(1, input_count); |
| 160 Node** const inputs = zone()->NewArray<Node*>(2 * input_count); | 155 Node** const inputs = zone()->NewArray<Node*>(2 * input_count); |
| 161 Node** const merge_true_inputs = &inputs[0]; | 156 Node** const merge_true_inputs = &inputs[0]; |
| 162 Node** const merge_false_inputs = &inputs[input_count]; | 157 Node** const merge_false_inputs = &inputs[input_count]; |
| 163 for (int index = 0; index < input_count; ++index) { | 158 for (int index = 0; index < input_count; ++index) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 178 } | 173 } |
| 179 inputs[input_count] = merge_true; | 174 inputs[input_count] = merge_true; |
| 180 Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs); | 175 Node* phi_true = graph()->NewNode(phi->op(), input_count + 1, inputs); |
| 181 inputs[input_count] = merge_false; | 176 inputs[input_count] = merge_false; |
| 182 Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs); | 177 Node* phi_false = graph()->NewNode(phi->op(), input_count + 1, inputs); |
| 183 for (Edge edge : phi->use_edges()) { | 178 for (Edge edge : phi->use_edges()) { |
| 184 Node* control = NodeProperties::GetControlInput(edge.from()); | 179 Node* control = NodeProperties::GetControlInput(edge.from()); |
| 185 if (NodeProperties::IsPhi(edge.from())) { | 180 if (NodeProperties::IsPhi(edge.from())) { |
| 186 control = NodeProperties::GetControlInput(control, edge.index()); | 181 control = NodeProperties::GetControlInput(control, edge.index()); |
| 187 } | 182 } |
| 188 DCHECK(control == if_true || control == if_false); | 183 DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); |
| 189 edge.UpdateTo((control == if_true) ? phi_true : phi_false); | 184 edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); |
| 190 } | 185 } |
| 191 phi->Kill(); | 186 phi->Kill(); |
| 192 } | 187 } |
| 193 // Fix up IfTrue and IfFalse and kill all dead nodes. | 188 // Fix up IfTrue and IfFalse and kill all dead nodes. |
| 194 if_false->ReplaceUses(merge_false); | 189 matcher.IfFalse()->ReplaceUses(merge_false); |
| 195 if_true->ReplaceUses(merge_true); | 190 matcher.IfTrue()->ReplaceUses(merge_true); |
| 196 if_false->Kill(); | 191 matcher.IfFalse()->Kill(); |
| 197 if_true->Kill(); | 192 matcher.IfTrue()->Kill(); |
| 198 branch->Kill(); | 193 branch->Kill(); |
| 199 cond->Kill(); | 194 cond->Kill(); |
| 200 merge->Kill(); | 195 merge->Kill(); |
| 201 return true; | 196 return true; |
| 202 } | 197 } |
| 203 | 198 |
| 204 | 199 |
| 205 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { | 200 bool ControlFlowOptimizer::TryBuildSwitch(Node* node) { |
| 206 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 201 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
| 207 | 202 |
| 208 Node* branch = node; | 203 Node* branch = node; |
| 209 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; | 204 if (BranchHintOf(branch->op()) != BranchHint::kNone) return false; |
| 210 Node* cond = NodeProperties::GetValueInput(branch, 0); | 205 Node* cond = NodeProperties::GetValueInput(branch, 0); |
| 211 if (cond->opcode() != IrOpcode::kWord32Equal) return false; | 206 if (cond->opcode() != IrOpcode::kWord32Equal) return false; |
| 212 Int32BinopMatcher m(cond); | 207 Int32BinopMatcher m(cond); |
| 213 Node* index = m.left().node(); | 208 Node* index = m.left().node(); |
| 214 if (!m.right().HasValue()) return false; | 209 if (!m.right().HasValue()) return false; |
| 215 int32_t value = m.right().Value(); | 210 int32_t value = m.right().Value(); |
| 216 ZoneSet<int32_t> values(zone()); | 211 ZoneSet<int32_t> values(zone()); |
| 217 values.insert(value); | 212 values.insert(value); |
| 218 | 213 |
| 219 Node* if_false; | 214 Node* if_false; |
| 220 Node* if_true; | 215 Node* if_true; |
| 221 while (true) { | 216 while (true) { |
| 222 Node* control_projections[2]; | 217 BranchMatcher matcher(branch); |
| 223 NodeProperties::CollectControlProjections(branch, control_projections, 2); | 218 DCHECK(matcher.Matched()); |
| 224 if_true = control_projections[0]; | 219 |
| 225 if_false = control_projections[1]; | 220 if_true = matcher.IfTrue(); |
| 226 DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode()); | 221 if_false = matcher.IfFalse(); |
| 227 DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode()); | |
| 228 | 222 |
| 229 auto it = if_false->uses().begin(); | 223 auto it = if_false->uses().begin(); |
| 230 if (it == if_false->uses().end()) break; | 224 if (it == if_false->uses().end()) break; |
| 231 Node* branch1 = *it++; | 225 Node* branch1 = *it++; |
| 232 if (branch1->opcode() != IrOpcode::kBranch) break; | 226 if (branch1->opcode() != IrOpcode::kBranch) break; |
| 233 if (BranchHintOf(branch1->op()) != BranchHint::kNone) break; | 227 if (BranchHintOf(branch1->op()) != BranchHint::kNone) break; |
| 234 if (it != if_false->uses().end()) break; | 228 if (it != if_false->uses().end()) break; |
| 235 Node* cond1 = branch1->InputAt(0); | 229 Node* cond1 = branch1->InputAt(0); |
| 236 if (cond1->opcode() != IrOpcode::kWord32Equal) break; | 230 if (cond1->opcode() != IrOpcode::kWord32Equal) break; |
| 237 Int32BinopMatcher m1(cond1); | 231 Int32BinopMatcher m1(cond1); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 249 if_false->NullAllInputs(); | 243 if_false->NullAllInputs(); |
| 250 Enqueue(if_true); | 244 Enqueue(if_true); |
| 251 | 245 |
| 252 branch = branch1; | 246 branch = branch1; |
| 253 value = value1; | 247 value = value1; |
| 254 values.insert(value); | 248 values.insert(value); |
| 255 } | 249 } |
| 256 | 250 |
| 257 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); | 251 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
| 258 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 252 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 259 DCHECK_EQ(IrOpcode::kIfTrue, if_true->opcode()); | |
| 260 DCHECK_EQ(IrOpcode::kIfFalse, if_false->opcode()); | |
| 261 if (branch == node) { | 253 if (branch == node) { |
| 262 DCHECK_EQ(1u, values.size()); | 254 DCHECK_EQ(1u, values.size()); |
| 263 return false; | 255 return false; |
| 264 } | 256 } |
| 265 DCHECK_LT(1u, values.size()); | 257 DCHECK_LT(1u, values.size()); |
| 266 node->set_op(common()->Switch(values.size() + 1)); | 258 node->set_op(common()->Switch(values.size() + 1)); |
| 267 node->ReplaceInput(0, index); | 259 node->ReplaceInput(0, index); |
| 268 if_true->set_op(common()->IfValue(value)); | 260 if_true->set_op(common()->IfValue(value)); |
| 269 if_true->ReplaceInput(0, node); | 261 if_true->ReplaceInput(0, node); |
| 270 Enqueue(if_true); | 262 Enqueue(if_true); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 284 Graph* ControlFlowOptimizer::graph() const { return jsgraph()->graph(); } | 276 Graph* ControlFlowOptimizer::graph() const { return jsgraph()->graph(); } |
| 285 | 277 |
| 286 | 278 |
| 287 MachineOperatorBuilder* ControlFlowOptimizer::machine() const { | 279 MachineOperatorBuilder* ControlFlowOptimizer::machine() const { |
| 288 return jsgraph()->machine(); | 280 return jsgraph()->machine(); |
| 289 } | 281 } |
| 290 | 282 |
| 291 } // namespace compiler | 283 } // namespace compiler |
| 292 } // namespace internal | 284 } // namespace internal |
| 293 } // namespace v8 | 285 } // namespace v8 |
| OLD | NEW |