Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: src/compiler/loop-analysis.cc

Issue 2143163002: [turbofan] Loop peeling with explicit loop exits. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix test Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/loop-analysis.h ('k') | src/compiler/loop-peeling.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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/loop-analysis.h" 5 #include "src/compiler/loop-analysis.h"
6 6
7 #include "src/compiler/graph.h" 7 #include "src/compiler/graph.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 11 matching lines...) Expand all
22 struct NodeInfo { 22 struct NodeInfo {
23 Node* node; 23 Node* node;
24 NodeInfo* next; // link in chaining loop members 24 NodeInfo* next; // link in chaining loop members
25 }; 25 };
26 26
27 27
28 // Temporary loop info needed during traversal and building the loop tree. 28 // Temporary loop info needed during traversal and building the loop tree.
29 struct LoopInfo { 29 struct LoopInfo {
30 Node* header; 30 Node* header;
31 NodeInfo* header_list; 31 NodeInfo* header_list;
32 NodeInfo* exit_list;
32 NodeInfo* body_list; 33 NodeInfo* body_list;
33 LoopTree::Loop* loop; 34 LoopTree::Loop* loop;
34 }; 35 };
35 36
36 37
37 // Encapsulation of the loop finding algorithm. 38 // Encapsulation of the loop finding algorithm.
38 // ----------------------------------------------------------------------------- 39 // -----------------------------------------------------------------------------
39 // Conceptually, the contents of a loop are those nodes that are "between" the 40 // Conceptually, the contents of a loop are those nodes that are "between" the
40 // loop header and the backedges of the loop. Graphs in the soup of nodes can 41 // loop header and the backedges of the loop. Graphs in the soup of nodes can
41 // form improper cycles, so standard loop finding algorithms that work on CFGs 42 // form improper cycles, so standard loop finding algorithms that work on CFGs
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 // Print out the results. 75 // Print out the results.
75 for (NodeInfo& ni : info_) { 76 for (NodeInfo& ni : info_) {
76 if (ni.node == nullptr) continue; 77 if (ni.node == nullptr) continue;
77 for (int i = 1; i <= loops_found_; i++) { 78 for (int i = 1; i <= loops_found_; i++) {
78 int index = ni.node->id() * width_ + INDEX(i); 79 int index = ni.node->id() * width_ + INDEX(i);
79 bool marked_forward = forward_[index] & BIT(i); 80 bool marked_forward = forward_[index] & BIT(i);
80 bool marked_backward = backward_[index] & BIT(i); 81 bool marked_backward = backward_[index] & BIT(i);
81 if (marked_forward && marked_backward) { 82 if (marked_forward && marked_backward) {
82 PrintF("X"); 83 PrintF("X");
83 } else if (marked_forward) { 84 } else if (marked_forward) {
84 PrintF("/"); 85 PrintF(">");
85 } else if (marked_backward) { 86 } else if (marked_backward) {
86 PrintF("\\"); 87 PrintF("<");
87 } else { 88 } else {
88 PrintF(" "); 89 PrintF(" ");
89 } 90 }
90 } 91 }
91 PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic()); 92 PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic());
92 } 93 }
93 94
94 int i = 0; 95 int i = 0;
95 for (LoopInfo& li : loops_) { 96 for (LoopInfo& li : loops_) {
96 PrintF("Loop %d headed at #%d\n", i, li.header->id()); 97 PrintF("Loop %d headed at #%d\n", i, li.header->id());
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 // Setup loop headers first. 192 // Setup loop headers first.
192 if (node->opcode() == IrOpcode::kLoop) { 193 if (node->opcode() == IrOpcode::kLoop) {
193 // found the loop node first. 194 // found the loop node first.
194 loop_num = CreateLoopInfo(node); 195 loop_num = CreateLoopInfo(node);
195 } else if (NodeProperties::IsPhi(node)) { 196 } else if (NodeProperties::IsPhi(node)) {
196 // found a phi first. 197 // found a phi first.
197 Node* merge = node->InputAt(node->InputCount() - 1); 198 Node* merge = node->InputAt(node->InputCount() - 1);
198 if (merge->opcode() == IrOpcode::kLoop) { 199 if (merge->opcode() == IrOpcode::kLoop) {
199 loop_num = CreateLoopInfo(merge); 200 loop_num = CreateLoopInfo(merge);
200 } 201 }
202 } else if (node->opcode() == IrOpcode::kLoopExit) {
203 // Intentionally ignore return value. Loop exit node marks
204 // are propagated normally.
205 CreateLoopInfo(node->InputAt(1));
206 } else if (node->opcode() == IrOpcode::kLoopExitValue ||
207 node->opcode() == IrOpcode::kLoopExitEffect) {
208 Node* loop_exit = NodeProperties::GetControlInput(node);
209 // Intentionally ignore return value. Loop exit node marks
210 // are propagated normally.
211 CreateLoopInfo(loop_exit->InputAt(1));
201 } 212 }
202 213
203 // Propagate marks backwards from this node. 214 // Propagate marks backwards from this node.
204 for (int i = 0; i < node->InputCount(); i++) { 215 for (int i = 0; i < node->InputCount(); i++) {
205 Node* input = node->InputAt(i); 216 Node* input = node->InputAt(i);
206 if (loop_num > 0 && i != kAssumedLoopEntryIndex) { 217 if (IsBackedge(node, i)) {
207 // Only propagate the loop mark on backedges. 218 // Only propagate the loop mark on backedges.
208 if (SetBackwardMark(input, loop_num)) Queue(input); 219 if (SetBackwardMark(input, loop_num)) Queue(input);
209 } else { 220 } else {
210 // Entry or normal edge. Propagate all marks except loop_num. 221 // Entry or normal edge. Propagate all marks except loop_num.
211 if (PropagateBackwardMarks(node, input, loop_num)) Queue(input); 222 if (PropagateBackwardMarks(node, input, loop_num)) Queue(input);
212 } 223 }
213 } 224 }
214 } 225 }
215 } 226 }
216 227
217 // Make a new loop if necessary for the given node. 228 // Make a new loop if necessary for the given node.
218 int CreateLoopInfo(Node* node) { 229 int CreateLoopInfo(Node* node) {
230 DCHECK_EQ(IrOpcode::kLoop, node->opcode());
219 int loop_num = LoopNum(node); 231 int loop_num = LoopNum(node);
220 if (loop_num > 0) return loop_num; 232 if (loop_num > 0) return loop_num;
221 233
222 loop_num = ++loops_found_; 234 loop_num = ++loops_found_;
223 if (INDEX(loop_num) >= width_) ResizeBackwardMarks(); 235 if (INDEX(loop_num) >= width_) ResizeBackwardMarks();
224 236
225 // Create a new loop. 237 // Create a new loop.
226 loops_.push_back({node, nullptr, nullptr, nullptr}); 238 loops_.push_back({node, nullptr, nullptr, nullptr, nullptr});
227 loop_tree_->NewLoop(); 239 loop_tree_->NewLoop();
228 SetBackwardMark(node, loop_num); 240 SetLoopMarkForLoopHeader(node, loop_num);
229 loop_tree_->node_to_loop_num_[node->id()] = loop_num;
230
231 // Setup loop mark for phis attached to loop header.
232 for (Node* use : node->uses()) {
233 if (NodeProperties::IsPhi(use)) {
234 info(use); // create the NodeInfo
235 SetBackwardMark(use, loop_num);
236 loop_tree_->node_to_loop_num_[use->id()] = loop_num;
237 }
238 }
239
240 return loop_num; 241 return loop_num;
241 } 242 }
242 243
244 void SetLoopMark(Node* node, int loop_num) {
245 info(node); // create the NodeInfo
246 SetBackwardMark(node, loop_num);
247 loop_tree_->node_to_loop_num_[node->id()] = loop_num;
248 }
249
250 void SetLoopMarkForLoopHeader(Node* node, int loop_num) {
251 DCHECK_EQ(IrOpcode::kLoop, node->opcode());
252 SetLoopMark(node, loop_num);
253 for (Node* use : node->uses()) {
254 if (NodeProperties::IsPhi(use)) {
255 SetLoopMark(use, loop_num);
256 }
257
258 // Do not keep the loop alive if it does not have any backedges.
259 if (node->InputCount() <= 1) continue;
260
261 if (use->opcode() == IrOpcode::kLoopExit) {
262 SetLoopMark(use, loop_num);
263 for (Node* exit_use : use->uses()) {
264 if (exit_use->opcode() == IrOpcode::kLoopExitValue ||
265 exit_use->opcode() == IrOpcode::kLoopExitEffect) {
266 SetLoopMark(exit_use, loop_num);
267 }
268 }
269 }
270 }
271 }
272
243 void ResizeBackwardMarks() { 273 void ResizeBackwardMarks() {
244 int new_width = width_ + 1; 274 int new_width = width_ + 1;
245 int max = num_nodes(); 275 int max = num_nodes();
246 uint32_t* new_backward = zone_->NewArray<uint32_t>(new_width * max); 276 uint32_t* new_backward = zone_->NewArray<uint32_t>(new_width * max);
247 memset(new_backward, 0, new_width * max * sizeof(uint32_t)); 277 memset(new_backward, 0, new_width * max * sizeof(uint32_t));
248 if (width_ > 0) { // copy old matrix data. 278 if (width_ > 0) { // copy old matrix data.
249 for (int i = 0; i < max; i++) { 279 for (int i = 0; i < max; i++) {
250 uint32_t* np = &new_backward[i * new_width]; 280 uint32_t* np = &new_backward[i * new_width];
251 uint32_t* op = &backward_[i * width_]; 281 uint32_t* op = &backward_[i * width_];
252 for (int j = 0; j < width_; j++) np[j] = op[j]; 282 for (int j = 0; j < width_; j++) np[j] = op[j];
(...skipping 16 matching lines...) Expand all
269 SetForwardMark(li.header, LoopNum(li.header)); 299 SetForwardMark(li.header, LoopNum(li.header));
270 Queue(li.header); 300 Queue(li.header);
271 } 301 }
272 // Propagate forward on paths that were backward reachable from backedges. 302 // Propagate forward on paths that were backward reachable from backedges.
273 while (!queue_.empty()) { 303 while (!queue_.empty()) {
274 Node* node = queue_.front(); 304 Node* node = queue_.front();
275 queue_.pop_front(); 305 queue_.pop_front();
276 queued_.Set(node, false); 306 queued_.Set(node, false);
277 for (Edge edge : node->use_edges()) { 307 for (Edge edge : node->use_edges()) {
278 Node* use = edge.from(); 308 Node* use = edge.from();
279 if (!IsBackedge(use, edge)) { 309 if (!IsBackedge(use, edge.index())) {
280 if (PropagateForwardMarks(node, use)) Queue(use); 310 if (PropagateForwardMarks(node, use)) Queue(use);
281 } 311 }
282 } 312 }
283 } 313 }
284 } 314 }
285 315
286 bool IsBackedge(Node* use, Edge& edge) { 316 bool IsLoopHeaderNode(Node* node) {
317 return node->opcode() == IrOpcode::kLoop || NodeProperties::IsPhi(node);
318 }
319
320 bool IsLoopExitNode(Node* node) {
321 return node->opcode() == IrOpcode::kLoopExit ||
322 node->opcode() == IrOpcode::kLoopExitValue ||
323 node->opcode() == IrOpcode::kLoopExitEffect;
324 }
325
326 bool IsBackedge(Node* use, int index) {
287 if (LoopNum(use) <= 0) return false; 327 if (LoopNum(use) <= 0) return false;
288 if (edge.index() == kAssumedLoopEntryIndex) return false;
289 if (NodeProperties::IsPhi(use)) { 328 if (NodeProperties::IsPhi(use)) {
290 return !NodeProperties::IsControlEdge(edge); 329 return index != NodeProperties::FirstControlIndex(use) &&
330 index != kAssumedLoopEntryIndex;
331 } else if (use->opcode() == IrOpcode::kLoop) {
332 return index != kAssumedLoopEntryIndex;
291 } 333 }
292 return true; 334 DCHECK(IsLoopExitNode(use));
335 return false;
293 } 336 }
294 337
295 int LoopNum(Node* node) { return loop_tree_->node_to_loop_num_[node->id()]; } 338 int LoopNum(Node* node) { return loop_tree_->node_to_loop_num_[node->id()]; }
296 339
297 NodeInfo& info(Node* node) { 340 NodeInfo& info(Node* node) {
298 NodeInfo& i = info_[node->id()]; 341 NodeInfo& i = info_[node->id()];
299 if (i.node == nullptr) i.node = node; 342 if (i.node == nullptr) i.node = node;
300 return i; 343 return i;
301 } 344 }
302 345
303 void Queue(Node* node) { 346 void Queue(Node* node) {
304 if (!queued_.Get(node)) { 347 if (!queued_.Get(node)) {
305 queue_.push_back(node); 348 queue_.push_back(node);
306 queued_.Set(node, true); 349 queued_.Set(node, true);
307 } 350 }
308 } 351 }
309 352
353 void AddNodeToLoop(NodeInfo* node_info, LoopInfo* loop, int loop_num) {
354 if (LoopNum(node_info->node) == loop_num) {
355 if (IsLoopHeaderNode(node_info->node)) {
356 node_info->next = loop->header_list;
357 loop->header_list = node_info;
358 } else {
359 DCHECK(IsLoopExitNode(node_info->node));
360 node_info->next = loop->exit_list;
361 loop->exit_list = node_info;
362 }
363 } else {
364 node_info->next = loop->body_list;
365 loop->body_list = node_info;
366 }
367 }
368
310 void FinishLoopTree() { 369 void FinishLoopTree() {
311 DCHECK(loops_found_ == static_cast<int>(loops_.size())); 370 DCHECK(loops_found_ == static_cast<int>(loops_.size()));
312 DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size())); 371 DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size()));
313 372
314 // Degenerate cases. 373 // Degenerate cases.
315 if (loops_found_ == 0) return; 374 if (loops_found_ == 0) return;
316 if (loops_found_ == 1) return FinishSingleLoop(); 375 if (loops_found_ == 1) return FinishSingleLoop();
317 376
318 for (int i = 1; i <= loops_found_; i++) ConnectLoopTree(i); 377 for (int i = 1; i <= loops_found_; i++) ConnectLoopTree(i);
319 378
(...skipping 15 matching lines...) Expand all
335 LoopInfo* loop = &loops_[loop_num - 1]; 394 LoopInfo* loop = &loops_[loop_num - 1];
336 if (innermost == nullptr || 395 if (innermost == nullptr ||
337 loop->loop->depth_ > innermost->loop->depth_) { 396 loop->loop->depth_ > innermost->loop->depth_) {
338 innermost = loop; 397 innermost = loop;
339 innermost_index = loop_num; 398 innermost_index = loop_num;
340 } 399 }
341 } 400 }
342 } 401 }
343 } 402 }
344 if (innermost == nullptr) continue; 403 if (innermost == nullptr) continue;
345 if (LoopNum(ni.node) == innermost_index) { 404 AddNodeToLoop(&ni, innermost, innermost_index);
346 ni.next = innermost->header_list;
347 innermost->header_list = &ni;
348 } else {
349 ni.next = innermost->body_list;
350 innermost->body_list = &ni;
351 }
352 count++; 405 count++;
353 } 406 }
354 407
355 // Serialize the node lists for loops into the loop tree. 408 // Serialize the node lists for loops into the loop tree.
356 loop_tree_->loop_nodes_.reserve(count); 409 loop_tree_->loop_nodes_.reserve(count);
357 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { 410 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) {
358 SerializeLoop(loop); 411 SerializeLoop(loop);
359 } 412 }
360 } 413 }
361 414
362 // Handle the simpler case of a single loop (no checks for nesting necessary). 415 // Handle the simpler case of a single loop (no checks for nesting necessary).
363 void FinishSingleLoop() { 416 void FinishSingleLoop() {
364 // Place nodes into the loop header and body. 417 // Place nodes into the loop header and body.
365 LoopInfo* li = &loops_[0]; 418 LoopInfo* li = &loops_[0];
366 li->loop = &loop_tree_->all_loops_[0]; 419 li->loop = &loop_tree_->all_loops_[0];
367 loop_tree_->SetParent(nullptr, li->loop); 420 loop_tree_->SetParent(nullptr, li->loop);
368 size_t count = 0; 421 size_t count = 0;
369 for (NodeInfo& ni : info_) { 422 for (NodeInfo& ni : info_) {
370 if (ni.node == nullptr || !IsInLoop(ni.node, 1)) continue; 423 if (ni.node == nullptr || !IsInLoop(ni.node, 1)) continue;
371 if (LoopNum(ni.node) == 1) { 424 AddNodeToLoop(&ni, li, 1);
372 ni.next = li->header_list;
373 li->header_list = &ni;
374 } else {
375 ni.next = li->body_list;
376 li->body_list = &ni;
377 }
378 count++; 425 count++;
379 } 426 }
380 427
381 // Serialize the node lists for the loop into the loop tree. 428 // Serialize the node lists for the loop into the loop tree.
382 loop_tree_->loop_nodes_.reserve(count); 429 loop_tree_->loop_nodes_.reserve(count);
383 SerializeLoop(li->loop); 430 SerializeLoop(li->loop);
384 } 431 }
385 432
386 // Recursively serialize the list of header nodes and body nodes 433 // Recursively serialize the list of header nodes and body nodes
387 // so that nested loops occupy nested intervals. 434 // so that nested loops occupy nested intervals.
(...skipping 11 matching lines...) Expand all
399 // Serialize the body. 446 // Serialize the body.
400 loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 447 loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size());
401 for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) { 448 for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) {
402 loop_tree_->loop_nodes_.push_back(ni->node); 449 loop_tree_->loop_nodes_.push_back(ni->node);
403 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; 450 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num;
404 } 451 }
405 452
406 // Serialize nested loops. 453 // Serialize nested loops.
407 for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); 454 for (LoopTree::Loop* child : loop->children_) SerializeLoop(child);
408 455
409 loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 456 // Serialize the exits.
457 loop->exits_start_ = static_cast<int>(loop_tree_->loop_nodes_.size());
458 for (NodeInfo* ni = li.exit_list; ni != nullptr; ni = ni->next) {
459 loop_tree_->loop_nodes_.push_back(ni->node);
460 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num;
461 }
462
463 loop->exits_end_ = static_cast<int>(loop_tree_->loop_nodes_.size());
410 } 464 }
411 465
412 // Connect the LoopTree loops to their parents recursively. 466 // Connect the LoopTree loops to their parents recursively.
413 LoopTree::Loop* ConnectLoopTree(int loop_num) { 467 LoopTree::Loop* ConnectLoopTree(int loop_num) {
414 LoopInfo& li = loops_[loop_num - 1]; 468 LoopInfo& li = loops_[loop_num - 1];
415 if (li.loop != nullptr) return li.loop; 469 if (li.loop != nullptr) return li.loop;
416 470
417 NodeInfo& ni = info(li.header); 471 NodeInfo& ni = info(li.header);
418 LoopTree::Loop* parent = nullptr; 472 LoopTree::Loop* parent = nullptr;
419 for (int i = 1; i <= loops_found_; i++) { 473 for (int i = 1; i <= loops_found_; i++) {
(...skipping 11 matching lines...) Expand all
431 return li.loop; 485 return li.loop;
432 } 486 }
433 487
434 void PrintLoop(LoopTree::Loop* loop) { 488 void PrintLoop(LoopTree::Loop* loop) {
435 for (int i = 0; i < loop->depth_; i++) PrintF(" "); 489 for (int i = 0; i < loop->depth_; i++) PrintF(" ");
436 PrintF("Loop depth = %d ", loop->depth_); 490 PrintF("Loop depth = %d ", loop->depth_);
437 int i = loop->header_start_; 491 int i = loop->header_start_;
438 while (i < loop->body_start_) { 492 while (i < loop->body_start_) {
439 PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id()); 493 PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id());
440 } 494 }
441 while (i < loop->body_end_) { 495 while (i < loop->exits_start_) {
442 PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id()); 496 PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id());
443 } 497 }
498 while (i < loop->exits_end_) {
499 PrintF(" E#%d", loop_tree_->loop_nodes_[i++]->id());
500 }
444 PrintF("\n"); 501 PrintF("\n");
445 for (LoopTree::Loop* child : loop->children_) PrintLoop(child); 502 for (LoopTree::Loop* child : loop->children_) PrintLoop(child);
446 } 503 }
447 }; 504 };
448 505
449 506
450 LoopTree* LoopFinder::BuildLoopTree(Graph* graph, Zone* zone) { 507 LoopTree* LoopFinder::BuildLoopTree(Graph* graph, Zone* zone) {
451 LoopTree* loop_tree = 508 LoopTree* loop_tree =
452 new (graph->zone()) LoopTree(graph->NodeCount(), graph->zone()); 509 new (graph->zone()) LoopTree(graph->NodeCount(), graph->zone());
453 LoopFinderImpl finder(graph, loop_tree, zone); 510 LoopFinderImpl finder(graph, loop_tree, zone);
(...skipping 10 matching lines...) Expand all
464 if (first->opcode() == IrOpcode::kLoop) return first; 521 if (first->opcode() == IrOpcode::kLoop) return first;
465 DCHECK(IrOpcode::IsPhiOpcode(first->opcode())); 522 DCHECK(IrOpcode::IsPhiOpcode(first->opcode()));
466 Node* header = NodeProperties::GetControlInput(first); 523 Node* header = NodeProperties::GetControlInput(first);
467 DCHECK_EQ(IrOpcode::kLoop, header->opcode()); 524 DCHECK_EQ(IrOpcode::kLoop, header->opcode());
468 return header; 525 return header;
469 } 526 }
470 527
471 } // namespace compiler 528 } // namespace compiler
472 } // namespace internal 529 } // namespace internal
473 } // namespace v8 530 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/loop-analysis.h ('k') | src/compiler/loop-peeling.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698