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

Side by Side Diff: src/IceCfg.cpp

Issue 1318553003: Compute the loop nest depth of each CfgNode and weight Variables by it. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: calculate -> compute (consistency) Created 5 years, 3 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/IceCfg.h ('k') | src/IceCfgNode.h » ('j') | src/IceCfgNode.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===// 1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===//
2 // 2 //
3 // The Subzero Code Generator 3 // The Subzero Code Generator
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 /// 9 ///
10 /// \file 10 /// \file
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 55
56 Cfg::~Cfg() { assert(ICE_TLS_GET_FIELD(CurrentCfg) == nullptr); } 56 Cfg::~Cfg() { assert(ICE_TLS_GET_FIELD(CurrentCfg) == nullptr); }
57 57
58 void Cfg::setError(const IceString &Message) { 58 void Cfg::setError(const IceString &Message) {
59 HasError = true; 59 HasError = true;
60 ErrorMessage = Message; 60 ErrorMessage = Message;
61 } 61 }
62 62
63 CfgNode *Cfg::makeNode() { 63 CfgNode *Cfg::makeNode() {
64 SizeT LabelIndex = Nodes.size(); 64 SizeT LabelIndex = Nodes.size();
65 CfgNode *Node = CfgNode::create(this, LabelIndex); 65 CfgNode *Node = CfgNode::create(this, LabelIndex);
Jim Stichnoth 2015/09/01 22:17:37 May want to document here that LoopNestDepth may n
ascull 2015/09/03 19:52:37 Done.
66 Nodes.push_back(Node); 66 Nodes.push_back(Node);
67 return Node; 67 return Node;
68 } 68 }
69 69
70 void Cfg::swapNodes(NodeList &NewNodes) { 70 void Cfg::swapNodes(NodeList &NewNodes) {
71 Nodes.swap(NewNodes); 71 Nodes.swap(NewNodes);
72 for (SizeT I = 0, NumNodes = getNumNodes(); I < NumNodes; ++I) 72 for (SizeT I = 0, NumNodes = getNumNodes(); I < NumNodes; ++I)
73 Nodes[I]->resetIndex(I); 73 Nodes[I]->resetIndex(I);
74 } 74 }
75 75
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 455
456 // Compute the stack frame layout. 456 // Compute the stack frame layout.
457 void Cfg::genFrame() { 457 void Cfg::genFrame() {
458 TimerMarker T(TimerStack::TT_genFrame, this); 458 TimerMarker T(TimerStack::TT_genFrame, this);
459 getTarget()->addProlog(Entry); 459 getTarget()->addProlog(Entry);
460 for (CfgNode *Node : Nodes) 460 for (CfgNode *Node : Nodes)
461 if (Node->getHasReturn()) 461 if (Node->getHasReturn())
462 getTarget()->addEpilog(Node); 462 getTarget()->addEpilog(Node);
463 } 463 }
464 464
465 // This is a lightweight version of live-range-end calculation. Marks 465 // Use Tarjn's strongly connected components algorithm to identify outermost to
jvoung (off chromium) 2015/09/01 18:56:18 Tarjan's
ascull 2015/09/03 19:52:37 Done.
466 // the last use of only those variables whose definition and uses are 466 // innermost loops. By deleting the head of the loop from the graph, inner
467 // completely with a single block. It is a quick single pass and 467 // loops can be found. This assumes that the head node is not shared between
468 // doesn't need to iterate until convergence. 468 // loops but instead all paths to the head come from 'continue' constructs.
469 //
470 // This only computes the loop nest depth within the function and does not take
471 // into account whether the function was called from within a loop.
472 void Cfg::computeLoopNestDepth() {
Jim Stichnoth 2015/09/01 22:17:37 Add a TimerMarker here (and add a new marker type
ascull 2015/09/03 19:52:37 Done.
473 using index_t = uint32_t;
Jim Stichnoth 2015/09/01 22:17:37 Type names should be capitalized per LLVM coding s
ascull 2015/09/03 19:52:37 Done.
474 constexpr index_t UndefinedIndex = 0;
475
476 struct LoopNode {
Jim Stichnoth 2015/09/01 22:17:37 I think if you are defining methods, you should ca
ascull 2015/09/03 19:52:37 Done.
477 LoopNode() = delete;
478 LoopNode operator=(const LoopNode &) = delete;
479
480 explicit LoopNode(CfgNode *BB) : BB(BB) {}
481 LoopNode(const LoopNode &) = default;
482
483 void reset() {
484 Succ = BB->getOutEdges().begin();
485 Index = LowLink = UndefinedIndex;
486 OnStack = false;
487 }
488
489 void visit(index_t VisitIndex) { Index = LowLink = VisitIndex; }
490 bool isVisited() const { return Index != UndefinedIndex; }
491
492 void setDeleted() { deleted = true; }
493 bool isDeleted() const { return deleted; }
494
495 CfgNode *BB;
496 NodeList::const_iterator Succ;
Jim Stichnoth 2015/09/01 22:17:37 Initialize members in the ctor or in the same way
ascull 2015/09/03 19:52:37 Done.
497 index_t Index;
498 index_t LowLink;
499 bool OnStack;
500 bool deleted = false;
jvoung (off chromium) 2015/09/01 18:56:17 capitalize deleted to follow code style
ascull 2015/09/03 19:52:37 Done.
501 };
502
503 // Create a collection of decorated nodes in the same order as Nodes which
504 // means the node's index will be valid.
505 std::vector<LoopNode, CfgLocalAllocator<LoopNode>> AllNodes;
506 // This is used as a replacement for the call stack
507 std::vector<LoopNode *, CfgLocalAllocator<LoopNode *>> WorkStack;
508 // Track which loop a node belongs to
509 std::vector<LoopNode *, CfgLocalAllocator<LoopNode *>> LoopStack;
510
511 // Allocate memory ahead of time. This is why a vector is used instead of a
512 // stack which doesn not support reserving (or bulk erasure used below).
jvoung (off chromium) 2015/09/01 18:56:18 doesn -> doesn't
ascull 2015/09/03 19:52:37 Done.
513 AllNodes.reserve(Nodes.size());
514 WorkStack.reserve(Nodes.size());
515 LoopStack.reserve(Nodes.size());
516
517 // Load in initial data
518 for (CfgNode *Node : Nodes)
519 AllNodes.emplace_back(Node);
520
521 size_t NumDeletedNodes = 0;
Jim Stichnoth 2015/09/01 22:17:37 SizeT or, if you object to that, std::vector<Loop
ascull 2015/09/03 19:52:37 Done.
522
523 while (NumDeletedNodes < AllNodes.size()) {
524 // Prepare to run Tarjan's
525 index_t NextIndex = 1;
jvoung (off chromium) 2015/09/01 18:56:18 nit: How about UndefinedIndex + 1, to ensure the i
ascull 2015/09/03 19:52:37 Done.
526 for (LoopNode &Node : AllNodes)
527 Node.reset();
jvoung (off chromium) 2015/09/01 18:56:18 Wonder if you should add an Ice timer for this who
ascull 2015/09/03 19:52:37 Done.
528
529 assert(WorkStack.empty());
530 assert(LoopStack.empty());
531
532 for (LoopNode &Node : AllNodes) {
533 if (Node.isDeleted() || Node.isVisited())
534 continue;
535
536 WorkStack.push_back(&Node);
537
538 continue_work_loop:
539 while (!WorkStack.empty()) {
540 LoopNode &WorkNode = *WorkStack.back();
541 WorkStack.pop_back();
542
543 if (!WorkNode.isVisited()) {
544 WorkNode.visit(NextIndex++);
545 LoopStack.push_back(&WorkNode);
546 WorkNode.OnStack = true;
547 } else {
548 // Returning to a node after having recursed into Succ so continue
549 // iterating through successors after using the Succ.LowLink value
550 // that was computed in the recursion.
551 LoopNode &Succ = AllNodes[(*WorkNode.Succ)->getIndex()];
552 WorkNode.LowLink = std::min(WorkNode.LowLink, Succ.LowLink);
553 ++WorkNode.Succ;
554 }
555
556 // Visit the successors and recurse into unvisited nodes. The recursion
557 // could cause the iteration to be suspended but it will resume as the
558 // stack is unwound.
559 auto SuccEnd = WorkNode.BB->getOutEdges().end();
560 for (; WorkNode.Succ != SuccEnd; ++WorkNode.Succ) {
561 LoopNode &Succ = AllNodes[(*WorkNode.Succ)->getIndex()];
562
563 if (Succ.isDeleted())
564 continue;
565
566 if (!Succ.isVisited()) {
567 WorkStack.insert(WorkStack.end(), {&WorkNode, &Succ});
568 goto continue_work_loop; // continue outer loop
jvoung (off chromium) 2015/09/01 18:56:18 You might be able to get away without a goto, if y
ascull 2015/09/03 19:52:37 I refactored the loop stuff out into it's own clas
569 } else if (Succ.OnStack) {
570 WorkNode.LowLink = std::min(WorkNode.LowLink, Succ.Index);
571 }
572 }
573
574 // Check for a loop being closed
575 if (WorkNode.LowLink == WorkNode.Index) {
576 // Single node loops mean no loop in a pure CFG. After lowering there
577 // may be reentrancy but we ignore that here.
jvoung (off chromium) 2015/09/01 18:56:18 What do you mean by reentrancy here? Branches from
ascull 2015/09/03 19:52:37 That is what I meant, although it isn't a useful c
578 if (LoopStack.back() == &WorkNode) {
579 LoopStack.back()->OnStack = false;
580 LoopStack.back()->setDeleted();
581 ++NumDeletedNodes;
582 LoopStack.pop_back();
583 continue;
584 }
585
586 // Reaching here means a loop has been found! It consists of the
587 // nodes on the top of the stack, down until the current node being
588 // processed, WorkNode, is found.
589 for (auto It = LoopStack.rbegin(); It != LoopStack.rend(); ++It) {
590 (*It)->OnStack = false;
591 (*It)->BB->incrementLoopNestDepth();
592 // Remove the loop from the stack and delete the head node
593 if (*It == &WorkNode) {
594 (*It)->setDeleted();
595 ++NumDeletedNodes;
596 LoopStack.erase(It.base() - 1, LoopStack.end());
597 break;
598 }
599 }
600 }
601 }
602 }
603 }
604 }
605
606 // This is a lightweight version of live-range-end calculation. Marks the last
607 // use of only those variables whose definition and uses are completely with a
608 // single block. It is a quick single pass and doesn't need to iterate until
609 // convergence.
469 void Cfg::livenessLightweight() { 610 void Cfg::livenessLightweight() {
470 TimerMarker T(TimerStack::TT_livenessLightweight, this); 611 TimerMarker T(TimerStack::TT_livenessLightweight, this);
471 getVMetadata()->init(VMK_Uses); 612 getVMetadata()->init(VMK_Uses);
472 for (CfgNode *Node : Nodes) 613 for (CfgNode *Node : Nodes)
473 Node->livenessLightweight(); 614 Node->livenessLightweight();
474 } 615 }
475 616
476 void Cfg::liveness(LivenessMode Mode) { 617 void Cfg::liveness(LivenessMode Mode) {
477 TimerMarker T(TimerStack::TT_liveness, this); 618 TimerMarker T(TimerStack::TT_liveness, this);
478 Live.reset(new Liveness(this, Mode)); 619 Live.reset(new Liveness(this, Mode));
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 Str << " live range " << Var->getLiveRange() << "\n"; 740 Str << " live range " << Var->getLiveRange() << "\n";
600 } 741 }
601 } 742 }
602 } 743 }
603 } 744 }
604 } 745 }
605 return Valid; 746 return Valid;
606 } 747 }
607 748
608 void Cfg::contractEmptyNodes() { 749 void Cfg::contractEmptyNodes() {
609 // If we're decorating the asm output with register liveness info, 750 // If we're decorating the asm output with register liveness info, this
610 // this information may become corrupted or incorrect after 751 // information may become corrupted or incorrect after contracting nodes that
611 // contracting nodes that contain only redundant assignments. As 752 // contain only redundant assignments. As such, we disable this pass when
612 // such, we disable this pass when DecorateAsm is specified. This 753 // DecorateAsm is specified. This may make the resulting code look more
613 // may make the resulting code look more branchy, but it should have 754 // branchy, but it should have no effect on the register assignments.
614 // no effect on the register assignments.
615 if (Ctx->getFlags().getDecorateAsm()) 755 if (Ctx->getFlags().getDecorateAsm())
616 return; 756 return;
617 for (CfgNode *Node : Nodes) { 757 for (CfgNode *Node : Nodes) {
618 Node->contractIfEmpty(); 758 Node->contractIfEmpty();
619 } 759 }
620 } 760 }
621 761
622 void Cfg::doBranchOpt() { 762 void Cfg::doBranchOpt() {
623 TimerMarker T(TimerStack::TT_doBranchOpt, this); 763 TimerMarker T(TimerStack::TT_doBranchOpt, this);
624 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { 764 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) {
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 } 911 }
772 } 912 }
773 // Print each basic block 913 // Print each basic block
774 for (CfgNode *Node : Nodes) 914 for (CfgNode *Node : Nodes)
775 Node->dump(this); 915 Node->dump(this);
776 if (isVerbose(IceV_Instructions)) 916 if (isVerbose(IceV_Instructions))
777 Str << "}\n"; 917 Str << "}\n";
778 } 918 }
779 919
780 } // end of namespace Ice 920 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceCfg.h ('k') | src/IceCfgNode.h » ('j') | src/IceCfgNode.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698