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 |