LCOV - code coverage report
Current view: top level - src/compiler - loop-peeling.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 123 128 96.1 %
Date: 2019-04-17 Functions: 11 11 100.0 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/loop-peeling.h"
       6             : #include "src/compiler/common-operator.h"
       7             : #include "src/compiler/compiler-source-position-table.h"
       8             : #include "src/compiler/graph.h"
       9             : #include "src/compiler/node-marker.h"
      10             : #include "src/compiler/node-origin-table.h"
      11             : #include "src/compiler/node-properties.h"
      12             : #include "src/compiler/node.h"
      13             : #include "src/zone/zone.h"
      14             : 
      15             : // Loop peeling is an optimization that copies the body of a loop, creating
      16             : // a new copy of the body called the "peeled iteration" that represents the
      17             : // first iteration. Beginning with a loop as follows:
      18             : 
      19             : //             E
      20             : //             |                 A
      21             : //             |                 |                     (backedges)
      22             : //             | +---------------|---------------------------------+
      23             : //             | | +-------------|-------------------------------+ |
      24             : //             | | |             | +--------+                    | |
      25             : //             | | |             | | +----+ |                    | |
      26             : //             | | |             | | |    | |                    | |
      27             : //           ( Loop )<-------- ( phiA )   | |                    | |
      28             : //              |                 |       | |                    | |
      29             : //      ((======P=================U=======|=|=====))             | |
      30             : //      ((                                | |     ))             | |
      31             : //      ((        X <---------------------+ |     ))             | |
      32             : //      ((                                  |     ))             | |
      33             : //      ((     body                         |     ))             | |
      34             : //      ((                                  |     ))             | |
      35             : //      ((        Y <-----------------------+     ))             | |
      36             : //      ((                                        ))             | |
      37             : //      ((===K====L====M==========================))             | |
      38             : //           |    |    |                                         | |
      39             : //           |    |    +-----------------------------------------+ |
      40             : //           |    +------------------------------------------------+
      41             : //           |
      42             : //          exit
      43             : 
      44             : // The body of the loop is duplicated so that all nodes considered "inside"
      45             : // the loop (e.g. {P, U, X, Y, K, L, M}) have a corresponding copies in the
      46             : // peeled iteration (e.g. {P', U', X', Y', K', L', M'}). What were considered
      47             : // backedges of the loop correspond to edges from the peeled iteration to
      48             : // the main loop body, with multiple backedges requiring a merge.
      49             : 
      50             : // Similarly, any exits from the loop body need to be merged with "exits"
      51             : // from the peeled iteration, resulting in the graph as follows:
      52             : 
      53             : //             E
      54             : //             |                 A
      55             : //             |                 |
      56             : //      ((=====P'================U'===============))
      57             : //      ((                                        ))
      58             : //      ((        X'<-------------+               ))
      59             : //      ((                        |               ))
      60             : //      ((   peeled iteration     |               ))
      61             : //      ((                        |               ))
      62             : //      ((        Y'<-----------+ |               ))
      63             : //      ((                      | |               ))
      64             : //      ((===K'===L'====M'======|=|===============))
      65             : //           |    |     |       | |
      66             : //  +--------+    +-+ +-+       | |
      67             : //  |               | |         | |
      68             : //  |              Merge <------phi
      69             : //  |                |           |
      70             : //  |          +-----+           |
      71             : //  |          |                 |                     (backedges)
      72             : //  |          | +---------------|---------------------------------+
      73             : //  |          | | +-------------|-------------------------------+ |
      74             : //  |          | | |             | +--------+                    | |
      75             : //  |          | | |             | | +----+ |                    | |
      76             : //  |          | | |             | | |    | |                    | |
      77             : //  |        ( Loop )<-------- ( phiA )   | |                    | |
      78             : //  |           |                 |       | |                    | |
      79             : //  |   ((======P=================U=======|=|=====))             | |
      80             : //  |   ((                                | |     ))             | |
      81             : //  |   ((        X <---------------------+ |     ))             | |
      82             : //  |   ((                                  |     ))             | |
      83             : //  |   ((     body                         |     ))             | |
      84             : //  |   ((                                  |     ))             | |
      85             : //  |   ((        Y <-----------------------+     ))             | |
      86             : //  |   ((                                        ))             | |
      87             : //  |   ((===K====L====M==========================))             | |
      88             : //  |        |    |    |                                         | |
      89             : //  |        |    |    +-----------------------------------------+ |
      90             : //  |        |    +------------------------------------------------+
      91             : //  |        |
      92             : //  |        |
      93             : //  +----+ +-+
      94             : //       | |
      95             : //      Merge
      96             : //        |
      97             : //      exit
      98             : 
      99             : // Note that the boxes ((===)) above are not explicitly represented in the
     100             : // graph, but are instead computed by the {LoopFinder}.
     101             : 
     102             : namespace v8 {
     103             : namespace internal {
     104             : namespace compiler {
     105             : 
     106             : struct Peeling {
     107             :   // Maps a node to its index in the {pairs} vector.
     108             :   NodeMarker<size_t> node_map;
     109             :   // The vector which contains the mapped nodes.
     110             :   NodeVector* pairs;
     111             : 
     112             :   Peeling(Graph* graph, size_t max, NodeVector* p)
     113       53428 :       : node_map(graph, static_cast<uint32_t>(max)), pairs(p) {}
     114             : 
     115    10440485 :   Node* map(Node* node) {
     116    10440485 :     if (node_map.Get(node) == 0) return node;
     117     8613552 :     return pairs->at(node_map.Get(node));
     118             :   }
     119             : 
     120     1473917 :   void Insert(Node* original, Node* copy) {
     121     2947834 :     node_map.Set(original, 1 + pairs->size());
     122     1473917 :     pairs->push_back(original);
     123     1473871 :     pairs->push_back(copy);
     124     1473829 :   }
     125             : 
     126       26756 :   void CopyNodes(Graph* graph, Zone* tmp_zone_, Node* dead, NodeRange nodes,
     127             :                  SourcePositionTable* source_positions,
     128             :                  NodeOriginTable* node_origins) {
     129             :     NodeVector inputs(tmp_zone_);
     130             :     // Copy all the nodes first.
     131     2765122 :     for (Node* node : nodes) {
     132             :       SourcePositionTable::Scope position(
     133     1369181 :           source_positions, source_positions->GetSourcePosition(node));
     134             :       NodeOriginTable::Scope origin_scope(node_origins, "copy nodes", node);
     135             :       inputs.clear();
     136     6478980 :       for (Node* input : node->inputs()) {
     137    10219599 :         inputs.push_back(map(input));
     138             :       }
     139     1369211 :       Node* copy = graph->NewNode(node->op(), node->InputCount(), &inputs[0]);
     140     1369267 :       if (NodeProperties::IsTyped(node)) {
     141             :         NodeProperties::SetType(copy, NodeProperties::GetType(node));
     142             :       }
     143     1369267 :       Insert(node, copy);
     144             :     }
     145             : 
     146             :     // Fix remaining inputs of the copies.
     147     2765394 :     for (Node* original : nodes) {
     148     2738724 :       Node* copy = pairs->at(node_map.Get(original));
     149    11589542 :       for (int i = 0; i < copy->InputCount(); i++) {
     150     5110134 :         copy->ReplaceInput(i, map(original->InputAt(i)));
     151             :       }
     152             :     }
     153       26714 :   }
     154             : 
     155             :   bool Marked(Node* node) { return node_map.Get(node) > 0; }
     156             : };
     157             : 
     158             : 
     159             : class PeeledIterationImpl : public PeeledIteration {
     160             :  public:
     161             :   NodeVector node_pairs_;
     162             :   explicit PeeledIterationImpl(Zone* zone) : node_pairs_(zone) {}
     163             : };
     164             : 
     165             : 
     166          63 : Node* PeeledIteration::map(Node* node) {
     167             :   // TODO(turbofan): we use a simple linear search, since the peeled iteration
     168             :   // is really only used in testing.
     169             :   PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this);
     170         615 :   for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) {
     171         380 :     if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1];
     172             :   }
     173             :   return node;
     174             : }
     175             : 
     176       36781 : bool LoopPeeler::CanPeel(LoopTree::Loop* loop) {
     177             :   // Look for returns and if projections that are outside the loop but whose
     178             :   // control input is inside the loop.
     179       36781 :   Node* loop_node = loop_tree_->GetLoopControl(loop);
     180     3767846 :   for (Node* node : loop_tree_->LoopNodes(loop)) {
     181     6376685 :     for (Node* use : node->uses()) {
     182     4511153 :       if (!loop_tree_->Contains(loop, use)) {
     183             :         bool unmarked_exit;
     184      197561 :         switch (node->opcode()) {
     185             :           case IrOpcode::kLoopExit:
     186       56539 :             unmarked_exit = (node->InputAt(1) != loop_node);
     187       56539 :             break;
     188             :           case IrOpcode::kLoopExitValue:
     189             :           case IrOpcode::kLoopExitEffect:
     190       62390 :             unmarked_exit = (node->InputAt(1)->InputAt(1) != loop_node);
     191       62390 :             break;
     192             :           default:
     193       78632 :             unmarked_exit = (use->opcode() != IrOpcode::kTerminate);
     194             :         }
     195      197561 :         if (unmarked_exit) {
     196       10052 :           if (FLAG_trace_turbo_loop) {
     197             :             Node* loop_node = loop_tree_->GetLoopControl(loop);
     198             :             PrintF(
     199             :                 "Cannot peel loop %i. Loop exit without explicit mark: Node %i "
     200             :                 "(%s) is inside "
     201             :                 "loop, but its use %i (%s) is outside.\n",
     202             :                 loop_node->id(), node->id(), node->op()->mnemonic(), use->id(),
     203           0 :                 use->op()->mnemonic());
     204             :           }
     205             :           return false;
     206             :         }
     207             :       }
     208             :     }
     209             :   }
     210             :   return true;
     211             : }
     212             : 
     213       36764 : PeeledIteration* LoopPeeler::Peel(LoopTree::Loop* loop) {
     214       36764 :   if (!CanPeel(loop)) return nullptr;
     215             : 
     216             :   //============================================================================
     217             :   // Construct the peeled iteration.
     218             :   //============================================================================
     219       53428 :   PeeledIterationImpl* iter = new (tmp_zone_) PeeledIterationImpl(tmp_zone_);
     220       26714 :   size_t estimated_peeled_size = 5 + (loop->TotalSize()) * 2;
     221       26714 :   Peeling peeling(graph_, estimated_peeled_size, &iter->node_pairs_);
     222             : 
     223       26714 :   Node* dead = graph_->NewNode(common_->Dead());
     224             : 
     225             :   // Map the loop header nodes to their entry values.
     226      262752 :   for (Node* node : loop_tree_->HeaderNodes(loop)) {
     227      104662 :     peeling.Insert(node, node->InputAt(kAssumedLoopEntryIndex));
     228             :   }
     229             : 
     230             :   // Copy all the nodes of loop body for the peeled iteration.
     231       53428 :   peeling.CopyNodes(graph_, tmp_zone_, dead, loop_tree_->BodyNodes(loop),
     232       53428 :                     source_positions_, node_origins_);
     233             : 
     234             :   //============================================================================
     235             :   // Replace the entry to the loop with the output of the peeled iteration.
     236             :   //============================================================================
     237       26714 :   Node* loop_node = loop_tree_->GetLoopControl(loop);
     238             :   Node* new_entry;
     239       26714 :   int backedges = loop_node->InputCount() - 1;
     240       26714 :   if (backedges > 1) {
     241             :     // Multiple backedges from original loop, therefore multiple output edges
     242             :     // from the peeled iteration.
     243           3 :     NodeVector inputs(tmp_zone_);
     244          15 :     for (int i = 1; i < loop_node->InputCount(); i++) {
     245          12 :       inputs.push_back(peeling.map(loop_node->InputAt(i)));
     246             :     }
     247             :     Node* merge =
     248           3 :         graph_->NewNode(common_->Merge(backedges), backedges, &inputs[0]);
     249             : 
     250             :     // Merge values from the multiple output edges of the peeled iteration.
     251          16 :     for (Node* node : loop_tree_->HeaderNodes(loop)) {
     252           5 :       if (node->opcode() == IrOpcode::kLoop) continue;  // already done.
     253             :       inputs.clear();
     254          10 :       for (int i = 0; i < backedges; i++) {
     255          12 :         inputs.push_back(peeling.map(node->InputAt(1 + i)));
     256             :       }
     257           4 :       for (Node* input : inputs) {
     258           4 :         if (input != inputs[0]) {  // Non-redundant phi.
     259           2 :           inputs.push_back(merge);
     260           2 :           const Operator* op = common_->ResizeMergeOrPhi(node->op(), backedges);
     261           2 :           Node* phi = graph_->NewNode(op, backedges + 1, &inputs[0]);
     262           2 :           node->ReplaceInput(0, phi);
     263           2 :           break;
     264             :         }
     265             :       }
     266             :     }
     267           3 :     new_entry = merge;
     268             :   } else {
     269             :     // Only one backedge, simply replace the input to loop with output of
     270             :     // peeling.
     271      236025 :     for (Node* node : loop_tree_->HeaderNodes(loop)) {
     272      104657 :       node->ReplaceInput(0, peeling.map(node->InputAt(1)));
     273             :     }
     274       26711 :     new_entry = peeling.map(loop_node->InputAt(1));
     275             :   }
     276       26714 :   loop_node->ReplaceInput(0, new_entry);
     277             : 
     278             :   //============================================================================
     279             :   // Change the exit and exit markers to merge/phi/effect-phi.
     280             :   //============================================================================
     281      234540 :   for (Node* exit : loop_tree_->ExitNodes(loop)) {
     282       90556 :     switch (exit->opcode()) {
     283             :       case IrOpcode::kLoopExit:
     284             :         // Change the loop exit node to a merge node.
     285       35875 :         exit->ReplaceInput(1, peeling.map(exit->InputAt(0)));
     286       35875 :         NodeProperties::ChangeOp(exit, common_->Merge(2));
     287       35875 :         break;
     288             :       case IrOpcode::kLoopExitValue:
     289             :         // Change exit marker to phi.
     290       18816 :         exit->InsertInput(graph_->zone(), 1, peeling.map(exit->InputAt(0)));
     291       18816 :         NodeProperties::ChangeOp(
     292       37632 :             exit, common_->Phi(MachineRepresentation::kTagged, 2));
     293       18816 :         break;
     294             :       case IrOpcode::kLoopExitEffect:
     295             :         // Change effect exit marker to effect phi.
     296       35865 :         exit->InsertInput(graph_->zone(), 1, peeling.map(exit->InputAt(0)));
     297       35865 :         NodeProperties::ChangeOp(exit, common_->EffectPhi(2));
     298       35865 :         break;
     299             :       default:
     300             :         break;
     301             :     }
     302             :   }
     303             :   return iter;
     304             : }
     305             : 
     306       41329 : void LoopPeeler::PeelInnerLoops(LoopTree::Loop* loop) {
     307             :   // If the loop has nested loops, peel inside those.
     308       41329 :   if (!loop->children().empty()) {
     309       10089 :     for (LoopTree::Loop* inner_loop : loop->children()) {
     310        5579 :       PeelInnerLoops(inner_loop);
     311             :     }
     312             :     return;
     313             :   }
     314             :   // Only peel small-enough loops.
     315       36819 :   if (loop->TotalSize() > LoopPeeler::kMaxPeeledNodes) return;
     316       36755 :   if (FLAG_trace_turbo_loop) {
     317           0 :     PrintF("Peeling loop with header: ");
     318           0 :     for (Node* node : loop_tree_->HeaderNodes(loop)) {
     319           0 :       PrintF("%i ", node->id());
     320             :     }
     321           0 :     PrintF("\n");
     322             :   }
     323             : 
     324       36755 :   Peel(loop);
     325             : }
     326             : 
     327             : namespace {
     328             : 
     329      130508 : void EliminateLoopExit(Node* node) {
     330             :   DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
     331             :   // The exit markers take the loop exit as input. We iterate over uses
     332             :   // and remove all the markers from the graph.
     333     1014422 :   for (Edge edge : node->use_edges()) {
     334      441957 :     if (NodeProperties::IsControlEdge(edge)) {
     335             :       Node* marker = edge.from();
     336      441957 :       if (marker->opcode() == IrOpcode::kLoopExitValue) {
     337      177623 :         NodeProperties::ReplaceUses(marker, marker->InputAt(0));
     338      177623 :         marker->Kill();
     339      264334 :       } else if (marker->opcode() == IrOpcode::kLoopExitEffect) {
     340      130508 :         NodeProperties::ReplaceUses(marker, nullptr,
     341      130508 :                                     NodeProperties::GetEffectInput(marker));
     342      130508 :         marker->Kill();
     343             :       }
     344             :     }
     345             :   }
     346      130508 :   NodeProperties::ReplaceUses(node, nullptr, nullptr,
     347      130508 :                               NodeProperties::GetControlInput(node, 0));
     348      130508 :   node->Kill();
     349      130508 : }
     350             : 
     351             : }  // namespace
     352             : 
     353      460759 : void LoopPeeler::PeelInnerLoopsOfTree() {
     354      460759 :   for (LoopTree::Loop* loop : loop_tree_->outer_loops()) {
     355       35750 :     PeelInnerLoops(loop);
     356             :   }
     357             : 
     358      460760 :   EliminateLoopExits(graph_, tmp_zone_);
     359      460764 : }
     360             : 
     361             : // static
     362      464164 : void LoopPeeler::EliminateLoopExits(Graph* graph, Zone* tmp_zone) {
     363      464164 :   ZoneQueue<Node*> queue(tmp_zone);
     364             :   ZoneVector<bool> visited(graph->NodeCount(), false, tmp_zone);
     365      928320 :   queue.push(graph->end());
     366     7899847 :   while (!queue.empty()) {
     367     7435679 :     Node* node = queue.front();
     368             :     queue.pop();
     369             : 
     370     7435689 :     if (node->opcode() == IrOpcode::kLoopExit) {
     371      130508 :       Node* control = NodeProperties::GetControlInput(node);
     372      130508 :       EliminateLoopExit(node);
     373      391524 :       if (!visited[control->id()]) {
     374             :         visited[control->id()] = true;
     375             :         queue.push(control);
     376             :       }
     377             :     } else {
     378    22703409 :       for (int i = 0; i < node->op()->ControlInputCount(); i++) {
     379     7699111 :         Node* control = NodeProperties::GetControlInput(node, i);
     380    15398214 :         if (!visited[control->id()]) {
     381             :           visited[control->id()] = true;
     382             :           queue.push(control);
     383             :         }
     384             :       }
     385             :     }
     386             :   }
     387      464168 : }
     388             : 
     389             : }  // namespace compiler
     390             : }  // namespace internal
     391      122004 : }  // namespace v8

Generated by: LCOV version 1.10