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/common-operator.h" | 5 #include "src/compiler/common-operator.h" |
6 #include "src/compiler/graph.h" | 6 #include "src/compiler/graph.h" |
7 #include "src/compiler/loop-peeling.h" | 7 #include "src/compiler/loop-peeling.h" |
8 #include "src/compiler/node.h" | 8 #include "src/compiler/node.h" |
9 #include "src/compiler/node-marker.h" | 9 #include "src/compiler/node-marker.h" |
10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 // TODO(turbofan): we use a simple linear search, since the peeled iteration | 154 // TODO(turbofan): we use a simple linear search, since the peeled iteration |
155 // is really only used in testing. | 155 // is really only used in testing. |
156 PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this); | 156 PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this); |
157 for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) { | 157 for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) { |
158 if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1]; | 158 if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1]; |
159 } | 159 } |
160 return node; | 160 return node; |
161 } | 161 } |
162 | 162 |
163 | 163 |
| 164 static void FindLoopExits(LoopTree* loop_tree, LoopTree::Loop* loop, |
| 165 NodeVector& exits, NodeVector& rets) { |
| 166 // Look for returns and if projections that are outside the loop but whose |
| 167 // control input is inside the loop. |
| 168 for (Node* node : loop_tree->LoopNodes(loop)) { |
| 169 for (Node* use : node->uses()) { |
| 170 if (!loop_tree->Contains(loop, use)) { |
| 171 if (IrOpcode::IsIfProjectionOpcode(use->opcode())) { |
| 172 // This is a branch from inside the loop to outside the loop. |
| 173 exits.push_back(use); |
| 174 } else if (use->opcode() == IrOpcode::kReturn && |
| 175 loop_tree->Contains(loop, |
| 176 NodeProperties::GetControlInput(use))) { |
| 177 // This is a return from inside the loop. |
| 178 rets.push_back(use); |
| 179 } |
| 180 } |
| 181 } |
| 182 } |
| 183 } |
| 184 |
| 185 |
| 186 bool LoopPeeler::CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop) { |
| 187 Zone zone; |
| 188 NodeVector exits(&zone); |
| 189 NodeVector rets(&zone); |
| 190 FindLoopExits(loop_tree, loop, exits, rets); |
| 191 return exits.size() <= 1u; |
| 192 } |
| 193 |
| 194 |
164 PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common, | 195 PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common, |
165 LoopTree* loop_tree, LoopTree::Loop* loop, | 196 LoopTree* loop_tree, LoopTree::Loop* loop, |
166 Zone* tmp_zone) { | 197 Zone* tmp_zone) { |
167 PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone); | 198 //============================================================================ |
168 Peeling peeling(graph, tmp_zone, loop->TotalSize() * 2 + 2, | 199 // Find the loop exit region to determine if this loop can be peeled. |
169 &iter->node_pairs_); | 200 //============================================================================ |
| 201 NodeVector exits(tmp_zone); |
| 202 NodeVector rets(tmp_zone); |
| 203 FindLoopExits(loop_tree, loop, exits, rets); |
| 204 |
| 205 if (exits.size() != 1) return nullptr; // not peelable currently. |
170 | 206 |
171 //============================================================================ | 207 //============================================================================ |
172 // Construct the peeled iteration. | 208 // Construct the peeled iteration. |
173 //============================================================================ | 209 //============================================================================ |
| 210 PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone); |
| 211 size_t estimated_peeled_size = |
| 212 5 + (loop->TotalSize() + exits.size() + rets.size()) * 2; |
| 213 Peeling peeling(graph, tmp_zone, estimated_peeled_size, &iter->node_pairs_); |
| 214 |
174 Node* dead = graph->NewNode(common->Dead()); | 215 Node* dead = graph->NewNode(common->Dead()); |
175 | 216 |
176 // Map the loop header nodes to their entry values. | 217 // Map the loop header nodes to their entry values. |
177 for (Node* node : loop_tree->HeaderNodes(loop)) { | 218 for (Node* node : loop_tree->HeaderNodes(loop)) { |
178 // TODO(titzer): assuming loop entry at index 0. | 219 peeling.Insert(node, node->InputAt(kAssumedLoopEntryIndex)); |
179 peeling.Insert(node, node->InputAt(0)); | |
180 } | 220 } |
181 | 221 |
182 // Copy all the nodes of loop body for the peeled iteration. | 222 // Copy all the nodes of loop body for the peeled iteration. |
183 peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop)); | 223 peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop)); |
184 | 224 |
185 //============================================================================ | 225 //============================================================================ |
186 // Replace the entry to the loop with the output of the peeled iteration. | 226 // Replace the entry to the loop with the output of the peeled iteration. |
187 //============================================================================ | 227 //============================================================================ |
188 Node* loop_node = loop_tree->GetLoopControl(loop); | 228 Node* loop_node = loop_tree->GetLoopControl(loop); |
189 Node* new_entry; | 229 Node* new_entry; |
(...skipping 30 matching lines...) Expand all Loading... |
220 // Only one backedge, simply replace the input to loop with output of | 260 // Only one backedge, simply replace the input to loop with output of |
221 // peeling. | 261 // peeling. |
222 for (Node* node : loop_tree->HeaderNodes(loop)) { | 262 for (Node* node : loop_tree->HeaderNodes(loop)) { |
223 node->ReplaceInput(0, peeling.map(node->InputAt(0))); | 263 node->ReplaceInput(0, peeling.map(node->InputAt(0))); |
224 } | 264 } |
225 new_entry = peeling.map(loop_node->InputAt(1)); | 265 new_entry = peeling.map(loop_node->InputAt(1)); |
226 } | 266 } |
227 loop_node->ReplaceInput(0, new_entry); | 267 loop_node->ReplaceInput(0, new_entry); |
228 | 268 |
229 //============================================================================ | 269 //============================================================================ |
230 // Find the loop exit region. | |
231 //============================================================================ | |
232 NodeVector exits(tmp_zone); | |
233 Node* end = NULL; | |
234 for (Node* node : loop_tree->LoopNodes(loop)) { | |
235 for (Node* use : node->uses()) { | |
236 if (!loop_tree->Contains(loop, use)) { | |
237 if (node->opcode() == IrOpcode::kBranch && | |
238 (use->opcode() == IrOpcode::kIfTrue || | |
239 use->opcode() == IrOpcode::kIfFalse)) { | |
240 // This is a branch from inside the loop to outside the loop. | |
241 exits.push_back(use); | |
242 } | |
243 } | |
244 } | |
245 } | |
246 | |
247 if (exits.size() == 0) return iter; // no exits => NTL | |
248 | |
249 if (exits.size() == 1) { | |
250 // Only one exit, so {end} is that exit. | |
251 end = exits[0]; | |
252 } else { | |
253 // {end} should be the common merge from the exits. | |
254 NodeVector rets(tmp_zone); | |
255 for (Node* exit : exits) { | |
256 Node* found = NULL; | |
257 for (Node* use : exit->uses()) { | |
258 if (use->opcode() == IrOpcode::kMerge) { | |
259 found = use; | |
260 if (end == NULL) { | |
261 end = found; | |
262 } else { | |
263 CHECK_EQ(end, found); // it should be unique! | |
264 } | |
265 } else if (use->opcode() == IrOpcode::kReturn) { | |
266 found = use; | |
267 rets.push_back(found); | |
268 } | |
269 } | |
270 // There should be a merge or a return for each exit. | |
271 CHECK(found); | |
272 } | |
273 // Return nodes, the end merge, and the phis associated with the end merge | |
274 // must be duplicated as well. | |
275 for (Node* node : rets) exits.push_back(node); | |
276 if (end != NULL) { | |
277 exits.push_back(end); | |
278 for (Node* use : end->uses()) { | |
279 if (NodeProperties::IsPhi(use)) exits.push_back(use); | |
280 } | |
281 } | |
282 } | |
283 | |
284 //============================================================================ | |
285 // Duplicate the loop exit region and add a merge. | 270 // Duplicate the loop exit region and add a merge. |
286 //============================================================================ | 271 //============================================================================ |
| 272 |
| 273 // Currently we are limited to peeling loops with a single exit. The exit is |
| 274 // the postdominator of the loop (ignoring returns). |
| 275 Node* postdom = exits[0]; |
| 276 for (Node* node : rets) exits.push_back(node); |
| 277 for (Node* use : postdom->uses()) { |
| 278 if (NodeProperties::IsPhi(use)) exits.push_back(use); |
| 279 } |
| 280 |
287 NodeRange exit_range(&exits[0], &exits[0] + exits.size()); | 281 NodeRange exit_range(&exits[0], &exits[0] + exits.size()); |
288 peeling.CopyNodes(graph, tmp_zone, dead, exit_range); | 282 peeling.CopyNodes(graph, tmp_zone, dead, exit_range); |
289 | 283 |
290 Node* merge = graph->NewNode(common->Merge(2), end, peeling.map(end)); | 284 Node* merge = graph->NewNode(common->Merge(2), postdom, peeling.map(postdom)); |
291 end->ReplaceUses(merge); | 285 postdom->ReplaceUses(merge); |
292 merge->ReplaceInput(0, end); // HULK SMASH!! | 286 merge->ReplaceInput(0, postdom); // input 0 overwritten by above line. |
293 | 287 |
294 // Find and update all the edges into either the loop or exit region. | 288 // Find and update all the edges into either the loop or exit region. |
295 for (int i = 0; i < 2; i++) { | 289 for (int i = 0; i < 2; i++) { |
296 NodeRange range = i == 0 ? loop_tree->LoopNodes(loop) : exit_range; | 290 NodeRange range = i == 0 ? loop_tree->LoopNodes(loop) : exit_range; |
297 ZoneVector<Edge> value_edges(tmp_zone); | 291 ZoneVector<Edge> value_edges(tmp_zone); |
298 ZoneVector<Edge> effect_edges(tmp_zone); | 292 ZoneVector<Edge> effect_edges(tmp_zone); |
299 | 293 |
300 for (Node* node : range) { | 294 for (Node* node : range) { |
301 // Gather value and effect edges from outside the region. | 295 // Gather value and effect edges from outside the region. |
302 for (Edge edge : node->use_edges()) { | 296 for (Edge edge : node->use_edges()) { |
(...skipping 27 matching lines...) Expand all Loading... |
330 } | 324 } |
331 } | 325 } |
332 } | 326 } |
333 | 327 |
334 return iter; | 328 return iter; |
335 } | 329 } |
336 | 330 |
337 } // namespace compiler | 331 } // namespace compiler |
338 } // namespace internal | 332 } // namespace internal |
339 } // namespace v8 | 333 } // namespace v8 |
OLD | NEW |