LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-loop-analysis.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 577 578 99.8 %
Date: 2019-04-18 Functions: 63 63 100.0 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/access-builder.h"
       6             : #include "src/compiler/common-operator.h"
       7             : #include "src/compiler/graph.h"
       8             : #include "src/compiler/graph-visualizer.h"
       9             : #include "src/compiler/js-graph.h"
      10             : #include "src/compiler/js-operator.h"
      11             : #include "src/compiler/loop-analysis.h"
      12             : #include "src/compiler/node.h"
      13             : #include "src/compiler/opcodes.h"
      14             : #include "src/compiler/operator.h"
      15             : #include "src/compiler/schedule.h"
      16             : #include "src/compiler/scheduler.h"
      17             : #include "src/compiler/simplified-operator.h"
      18             : #include "src/compiler/verifier.h"
      19             : #include "test/cctest/cctest.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : namespace compiler {
      24             : 
      25       53312 : static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
      26       26656 :                         0, 1, 0, 0);
      27       53312 : static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure,
      28       26656 :                        "Int32LessThan", 2, 0, 0, 1, 0, 0);
      29       53312 : static Operator kStore(IrOpcode::kStore, Operator::kNoProperties, "Store", 1, 1,
      30       26656 :                        1, 0, 1, 0);
      31             : 
      32             : static const int kNumLeafs = 4;
      33             : 
      34             : // A helper for all tests dealing with LoopFinder.
      35      163040 : class LoopFinderTester : HandleAndZoneScope {
      36             :  public:
      37      163040 :   LoopFinderTester()
      38             :       : isolate(main_isolate()),
      39             :         common(main_zone()),
      40             :         graph(main_zone()),
      41             :         jsgraph(main_isolate(), &graph, &common, nullptr, nullptr, nullptr),
      42      163040 :         start(graph.NewNode(common.Start(1))),
      43      163040 :         end(graph.NewNode(common.End(1), start)),
      44      163040 :         p0(graph.NewNode(common.Parameter(0), start)),
      45      163040 :         zero(jsgraph.Int32Constant(0)),
      46      163040 :         one(jsgraph.OneConstant()),
      47      163040 :         half(jsgraph.Constant(0.5)),
      48      163040 :         self(graph.NewNode(common.Int32Constant(0xAABBCCDD))),
      49      163040 :         dead(graph.NewNode(common.Dead())),
      50     1793440 :         loop_tree(nullptr) {
      51      163040 :     graph.SetEnd(end);
      52      163040 :     graph.SetStart(start);
      53      163040 :     leaf[0] = zero;
      54      163040 :     leaf[1] = one;
      55      163040 :     leaf[2] = half;
      56      163040 :     leaf[3] = p0;
      57      163040 :   }
      58             : 
      59             :   Isolate* isolate;
      60             :   CommonOperatorBuilder common;
      61             :   Graph graph;
      62             :   JSGraph jsgraph;
      63             :   Node* start;
      64             :   Node* end;
      65             :   Node* p0;
      66             :   Node* zero;
      67             :   Node* one;
      68             :   Node* half;
      69             :   Node* self;
      70             :   Node* dead;
      71             :   Node* leaf[kNumLeafs];
      72             :   LoopTree* loop_tree;
      73             : 
      74             :   Node* Phi(Node* a) {
      75             :     return SetSelfReferences(graph.NewNode(op(1, false), a, start));
      76             :   }
      77             : 
      78             :   Node* Phi(Node* a, Node* b) {
      79             :     return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
      80             :   }
      81             : 
      82             :   Node* Phi(Node* a, Node* b, Node* c) {
      83             :     return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
      84             :   }
      85             : 
      86             :   Node* Phi(Node* a, Node* b, Node* c, Node* d) {
      87             :     return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
      88             :   }
      89             : 
      90             :   Node* EffectPhi(Node* a) {
      91             :     return SetSelfReferences(graph.NewNode(op(1, true), a, start));
      92             :   }
      93             : 
      94             :   Node* EffectPhi(Node* a, Node* b) {
      95             :     return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
      96             :   }
      97             : 
      98             :   Node* EffectPhi(Node* a, Node* b, Node* c) {
      99             :     return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
     100             :   }
     101             : 
     102             :   Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
     103             :     return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
     104             :   }
     105             : 
     106             :   Node* SetSelfReferences(Node* node) {
     107             :     for (Edge edge : node->input_edges()) {
     108             :       if (edge.to() == self) node->ReplaceInput(edge.index(), node);
     109             :     }
     110             :     return node;
     111             :   }
     112             : 
     113             :   const Operator* op(int count, bool effect) {
     114           5 :     return effect ? common.EffectPhi(count)
     115         135 :                   : common.Phi(MachineRepresentation::kTagged, count);
     116             :   }
     117             : 
     118         105 :   Node* Return(Node* val, Node* effect, Node* control) {
     119         105 :     Node* zero = graph.NewNode(common.Int32Constant(0));
     120         105 :     Node* ret = graph.NewNode(common.Return(), zero, val, effect, control);
     121         105 :     end->ReplaceInput(0, ret);
     122         105 :     return ret;
     123             :   }
     124             : 
     125      653950 :   LoopTree* GetLoopTree() {
     126      653950 :     if (loop_tree == nullptr) {
     127      163035 :       if (FLAG_trace_turbo_graph) {
     128           0 :         StdoutStream{} << AsRPO(graph);
     129             :       }
     130      326070 :       Zone zone(main_isolate()->allocator(), ZONE_NAME);
     131      163035 :       loop_tree = LoopFinder::BuildLoopTree(&graph, &zone);
     132             :     }
     133      653950 :     return loop_tree;
     134             :   }
     135             : 
     136      491165 :   void CheckLoop(Node** header, int header_count, Node** body, int body_count) {
     137      491165 :     LoopTree* tree = GetLoopTree();
     138      491165 :     LoopTree::Loop* loop = tree->ContainingLoop(header[0]);
     139      491165 :     CHECK(loop);
     140             : 
     141      491165 :     CHECK(header_count == static_cast<int>(loop->HeaderSize()));
     142     2455565 :     for (int i = 0; i < header_count; i++) {
     143             :       // Each header node should be in the loop.
     144     1964400 :       CHECK_EQ(loop, tree->ContainingLoop(header[i]));
     145      982200 :       CheckRangeContains(tree->HeaderNodes(loop), header[i]);
     146             :     }
     147             : 
     148      491165 :     CHECK_EQ(body_count, static_cast<int>(loop->BodySize()));
     149             :     // TODO(turbofan): O(n^2) set equivalence in this test.
     150     9689955 :     for (int i = 0; i < body_count; i++) {
     151             :       // Each body node should be contained in the loop.
     152     4599395 :       CHECK(tree->Contains(loop, body[i]));
     153     4599395 :       CheckRangeContains(tree->BodyNodes(loop), body[i]);
     154             :     }
     155      491165 :   }
     156             : 
     157     5581595 :   void CheckRangeContains(NodeRange range, Node* node) {
     158     5581595 :     CHECK_NE(range.end(), std::find(range.begin(), range.end(), node));
     159     5581595 :   }
     160             : 
     161      162785 :   void CheckNestedLoops(Node** chain, int chain_count) {
     162      162785 :     LoopTree* tree = GetLoopTree();
     163     1137695 :     for (int i = 0; i < chain_count; i++) {
     164      487455 :       Node* header = chain[i];
     165             :       // Each header should be in a loop.
     166             :       LoopTree::Loop* loop = tree->ContainingLoop(header);
     167      487455 :       CHECK(loop);
     168             :       // Check parentage.
     169             :       LoopTree::Loop* parent =
     170      487455 :           i == 0 ? nullptr : tree->ContainingLoop(chain[i - 1]);
     171      487455 :       CHECK_EQ(parent, loop->parent());
     172      974135 :       for (int j = i - 1; j >= 0; j--) {
     173             :         // This loop should be nested inside all the outer loops.
     174      486680 :         Node* outer_header = chain[j];
     175             :         LoopTree::Loop* outer = tree->ContainingLoop(outer_header);
     176      486680 :         CHECK(tree->Contains(outer, header));
     177      486680 :         CHECK(!tree->Contains(loop, outer_header));
     178             :       }
     179             :     }
     180      162785 :   }
     181             : 
     182             :   Zone* zone() { return main_zone(); }
     183             : };
     184             : 
     185             : 
     186             : struct While {
     187             :   LoopFinderTester& t;
     188             :   Node* branch;
     189             :   Node* if_true;
     190             :   Node* exit;
     191             :   Node* loop;
     192             : 
     193         200 :   While(LoopFinderTester& R, Node* cond) : t(R) {
     194         400 :     loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
     195         400 :     branch = t.graph.NewNode(t.common.Branch(), cond, loop);
     196         400 :     if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     197         400 :     exit = t.graph.NewNode(t.common.IfFalse(), branch);
     198         200 :     loop->ReplaceInput(1, if_true);
     199         200 :   }
     200             : 
     201          55 :   void chain(Node* control) { loop->ReplaceInput(0, control); }
     202             :   void nest(While& that) {
     203          25 :     that.loop->ReplaceInput(1, exit);
     204          25 :     this->loop->ReplaceInput(0, that.if_true);
     205             :   }
     206             : };
     207             : 
     208             : 
     209             : struct Counter {
     210             :   Node* base;
     211             :   Node* inc;
     212             :   Node* phi;
     213             :   Node* add;
     214             : 
     215          90 :   Counter(While& w, int32_t b, int32_t k)
     216          90 :       : base(w.t.jsgraph.Int32Constant(b)), inc(w.t.jsgraph.Int32Constant(k)) {
     217          90 :     Build(w);
     218          90 :   }
     219             : 
     220          40 :   Counter(While& w, Node* b, Node* k) : base(b), inc(k) { Build(w); }
     221             : 
     222         130 :   void Build(While& w) {
     223         390 :     phi = w.t.graph.NewNode(w.t.op(2, false), base, base, w.loop);
     224         260 :     add = w.t.graph.NewNode(&kIntAdd, phi, inc);
     225         130 :     phi->ReplaceInput(1, add);
     226         130 :   }
     227             : };
     228             : 
     229             : 
     230             : struct StoreLoop {
     231             :   Node* base;
     232             :   Node* val;
     233             :   Node* phi;
     234             :   Node* store;
     235             : 
     236           5 :   explicit StoreLoop(While& w)
     237           5 :       : base(w.t.graph.start()), val(w.t.jsgraph.Int32Constant(13)) {
     238           5 :     Build(w);
     239           5 :   }
     240             : 
     241             :   StoreLoop(While& w, Node* b, Node* v) : base(b), val(v) { Build(w); }
     242             : 
     243           5 :   void Build(While& w) {
     244          15 :     phi = w.t.graph.NewNode(w.t.op(2, true), base, base, w.loop);
     245          10 :     store = w.t.graph.NewNode(&kStore, val, phi, w.loop);
     246           5 :     phi->ReplaceInput(1, store);
     247           5 :   }
     248             : };
     249             : 
     250             : 
     251       26661 : TEST(LaLoop1) {
     252             :   // One loop.
     253           5 :   LoopFinderTester t;
     254           5 :   While w(t, t.p0);
     255           5 :   t.Return(t.p0, t.start, w.exit);
     256             : 
     257           5 :   Node* chain[] = {w.loop};
     258           5 :   t.CheckNestedLoops(chain, 1);
     259             : 
     260           5 :   Node* header[] = {w.loop};
     261           5 :   Node* body[] = {w.branch, w.if_true};
     262           5 :   t.CheckLoop(header, 1, body, 2);
     263           5 : }
     264             : 
     265             : 
     266       26661 : TEST(LaLoop1phi) {
     267             :   // One loop with a simple phi.
     268           5 :   LoopFinderTester t;
     269           5 :   While w(t, t.p0);
     270           5 :   Node* phi = t.graph.NewNode(t.common.Phi(MachineRepresentation::kTagged, 2),
     271             :                               t.zero, t.one, w.loop);
     272           5 :   t.Return(phi, t.start, w.exit);
     273             : 
     274           5 :   Node* chain[] = {w.loop};
     275           5 :   t.CheckNestedLoops(chain, 1);
     276             : 
     277           5 :   Node* header[] = {w.loop, phi};
     278           5 :   Node* body[] = {w.branch, w.if_true};
     279           5 :   t.CheckLoop(header, 2, body, 2);
     280           5 : }
     281             : 
     282             : 
     283       26661 : TEST(LaLoop1c) {
     284             :   // One loop with a counter.
     285           5 :   LoopFinderTester t;
     286           5 :   While w(t, t.p0);
     287           5 :   Counter c(w, 0, 1);
     288           5 :   t.Return(c.phi, t.start, w.exit);
     289             : 
     290           5 :   Node* chain[] = {w.loop};
     291           5 :   t.CheckNestedLoops(chain, 1);
     292             : 
     293           5 :   Node* header[] = {w.loop, c.phi};
     294           5 :   Node* body[] = {w.branch, w.if_true, c.add};
     295           5 :   t.CheckLoop(header, 2, body, 3);
     296           5 : }
     297             : 
     298             : 
     299       26661 : TEST(LaLoop1e) {
     300             :   // One loop with an effect phi.
     301           5 :   LoopFinderTester t;
     302           5 :   While w(t, t.p0);
     303           5 :   StoreLoop c(w);
     304           5 :   t.Return(t.p0, c.phi, w.exit);
     305             : 
     306           5 :   Node* chain[] = {w.loop};
     307           5 :   t.CheckNestedLoops(chain, 1);
     308             : 
     309           5 :   Node* header[] = {w.loop, c.phi};
     310           5 :   Node* body[] = {w.branch, w.if_true, c.store};
     311           5 :   t.CheckLoop(header, 2, body, 3);
     312           5 : }
     313             : 
     314             : 
     315       26661 : TEST(LaLoop1d) {
     316             :   // One loop with two counters.
     317           5 :   LoopFinderTester t;
     318           5 :   While w(t, t.p0);
     319           5 :   Counter c1(w, 0, 1);
     320           5 :   Counter c2(w, 1, 1);
     321          10 :   t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w.exit);
     322             : 
     323           5 :   Node* chain[] = {w.loop};
     324           5 :   t.CheckNestedLoops(chain, 1);
     325             : 
     326           5 :   Node* header[] = {w.loop, c1.phi, c2.phi};
     327           5 :   Node* body[] = {w.branch, w.if_true, c1.add, c2.add};
     328           5 :   t.CheckLoop(header, 3, body, 4);
     329           5 : }
     330             : 
     331             : 
     332       26661 : TEST(LaLoop2) {
     333             :   // One loop following another.
     334           5 :   LoopFinderTester t;
     335           5 :   While w1(t, t.p0);
     336           5 :   While w2(t, t.p0);
     337           5 :   w2.chain(w1.exit);
     338           5 :   t.Return(t.p0, t.start, w2.exit);
     339             : 
     340             :   {
     341           5 :     Node* chain[] = {w1.loop};
     342           5 :     t.CheckNestedLoops(chain, 1);
     343             : 
     344           5 :     Node* header[] = {w1.loop};
     345           5 :     Node* body[] = {w1.branch, w1.if_true};
     346           5 :     t.CheckLoop(header, 1, body, 2);
     347             :   }
     348             : 
     349             :   {
     350           5 :     Node* chain[] = {w2.loop};
     351           5 :     t.CheckNestedLoops(chain, 1);
     352             : 
     353           5 :     Node* header[] = {w2.loop};
     354           5 :     Node* body[] = {w2.branch, w2.if_true};
     355           5 :     t.CheckLoop(header, 1, body, 2);
     356             :   }
     357           5 : }
     358             : 
     359             : 
     360       26661 : TEST(LaLoop2c) {
     361             :   // One loop following another, each with counters.
     362           5 :   LoopFinderTester t;
     363           5 :   While w1(t, t.p0);
     364           5 :   While w2(t, t.p0);
     365           5 :   Counter c1(w1, 0, 1);
     366           5 :   Counter c2(w2, 0, 1);
     367           5 :   w2.chain(w1.exit);
     368          10 :   t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
     369             : 
     370             :   {
     371           5 :     Node* chain[] = {w1.loop};
     372           5 :     t.CheckNestedLoops(chain, 1);
     373             : 
     374           5 :     Node* header[] = {w1.loop, c1.phi};
     375           5 :     Node* body[] = {w1.branch, w1.if_true, c1.add};
     376           5 :     t.CheckLoop(header, 2, body, 3);
     377             :   }
     378             : 
     379             :   {
     380           5 :     Node* chain[] = {w2.loop};
     381           5 :     t.CheckNestedLoops(chain, 1);
     382             : 
     383           5 :     Node* header[] = {w2.loop, c2.phi};
     384           5 :     Node* body[] = {w2.branch, w2.if_true, c2.add};
     385           5 :     t.CheckLoop(header, 2, body, 3);
     386             :   }
     387           5 : }
     388             : 
     389             : 
     390       26661 : TEST(LaLoop2cc) {
     391             :   // One loop following another; second loop uses phi from first.
     392          85 :   for (int i = 0; i < 8; i++) {
     393          40 :     LoopFinderTester t;
     394          40 :     While w1(t, t.p0);
     395          40 :     While w2(t, t.p0);
     396          40 :     Counter c1(w1, 0, 1);
     397             : 
     398             :     // various usage scenarios for the second loop.
     399          40 :     Counter c2(w2, i & 1 ? t.p0 : c1.phi, i & 2 ? t.p0 : c1.phi);
     400          40 :     if (i & 3) w2.branch->ReplaceInput(0, c1.phi);
     401             : 
     402          40 :     w2.chain(w1.exit);
     403          80 :     t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
     404             : 
     405             :     {
     406          40 :       Node* chain[] = {w1.loop};
     407          40 :       t.CheckNestedLoops(chain, 1);
     408             : 
     409          40 :       Node* header[] = {w1.loop, c1.phi};
     410          40 :       Node* body[] = {w1.branch, w1.if_true, c1.add};
     411          40 :       t.CheckLoop(header, 2, body, 3);
     412             :     }
     413             : 
     414             :     {
     415          40 :       Node* chain[] = {w2.loop};
     416          40 :       t.CheckNestedLoops(chain, 1);
     417             : 
     418          40 :       Node* header[] = {w2.loop, c2.phi};
     419          40 :       Node* body[] = {w2.branch, w2.if_true, c2.add};
     420          40 :       t.CheckLoop(header, 2, body, 3);
     421             :     }
     422             :   }
     423           5 : }
     424             : 
     425             : 
     426       26661 : TEST(LaNestedLoop1) {
     427             :   // One loop nested in another.
     428           5 :   LoopFinderTester t;
     429           5 :   While w1(t, t.p0);
     430           5 :   While w2(t, t.p0);
     431             :   w2.nest(w1);
     432           5 :   t.Return(t.p0, t.start, w1.exit);
     433             : 
     434           5 :   Node* chain[] = {w1.loop, w2.loop};
     435           5 :   t.CheckNestedLoops(chain, 2);
     436             : 
     437           5 :   Node* h1[] = {w1.loop};
     438           5 :   Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true, w2.exit};
     439           5 :   t.CheckLoop(h1, 1, b1, 6);
     440             : 
     441           5 :   Node* h2[] = {w2.loop};
     442           5 :   Node* b2[] = {w2.branch, w2.if_true};
     443           5 :   t.CheckLoop(h2, 1, b2, 2);
     444           5 : }
     445             : 
     446             : 
     447       26661 : TEST(LaNestedLoop1c) {
     448             :   // One loop nested in another, each with a counter.
     449           5 :   LoopFinderTester t;
     450           5 :   While w1(t, t.p0);
     451           5 :   While w2(t, t.p0);
     452           5 :   Counter c1(w1, 0, 1);
     453           5 :   Counter c2(w2, 0, 1);
     454           5 :   w2.branch->ReplaceInput(0, c2.phi);
     455             :   w2.nest(w1);
     456           5 :   t.Return(c1.phi, t.start, w1.exit);
     457             : 
     458           5 :   Node* chain[] = {w1.loop, w2.loop};
     459           5 :   t.CheckNestedLoops(chain, 2);
     460             : 
     461           5 :   Node* h1[] = {w1.loop, c1.phi};
     462          25 :   Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true,
     463          25 :                 w2.exit,   c2.phi,     c1.add,  c2.add};
     464           5 :   t.CheckLoop(h1, 2, b1, 9);
     465             : 
     466           5 :   Node* h2[] = {w2.loop, c2.phi};
     467           5 :   Node* b2[] = {w2.branch, w2.if_true, c2.add};
     468           5 :   t.CheckLoop(h2, 2, b2, 3);
     469           5 : }
     470             : 
     471             : 
     472       26661 : TEST(LaNestedLoop1x) {
     473             :   // One loop nested in another.
     474           5 :   LoopFinderTester t;
     475           5 :   While w1(t, t.p0);
     476           5 :   While w2(t, t.p0);
     477             :   w2.nest(w1);
     478             : 
     479           5 :   const Operator* op = t.common.Phi(MachineRepresentation::kWord32, 2);
     480           5 :   Node* p1a = t.graph.NewNode(op, t.p0, t.p0, w1.loop);
     481           5 :   Node* p1b = t.graph.NewNode(op, t.p0, t.p0, w1.loop);
     482           5 :   Node* p2a = t.graph.NewNode(op, p1a, t.p0, w2.loop);
     483           5 :   Node* p2b = t.graph.NewNode(op, p1b, t.p0, w2.loop);
     484             : 
     485           5 :   p1a->ReplaceInput(1, p2b);
     486           5 :   p1b->ReplaceInput(1, p2a);
     487             : 
     488           5 :   p2a->ReplaceInput(1, p2b);
     489           5 :   p2b->ReplaceInput(1, p2a);
     490             : 
     491           5 :   t.Return(t.p0, t.start, w1.exit);
     492             : 
     493           5 :   Node* chain[] = {w1.loop, w2.loop};
     494           5 :   t.CheckNestedLoops(chain, 2);
     495             : 
     496           5 :   Node* h1[] = {w1.loop, p1a, p1b};
     497          15 :   Node* b1[] = {w1.branch, w1.if_true, w2.loop,    p2a,
     498          15 :                 p2b,       w2.branch,  w2.if_true, w2.exit};
     499           5 :   t.CheckLoop(h1, 3, b1, 8);
     500             : 
     501           5 :   Node* h2[] = {w2.loop, p2a, p2b};
     502           5 :   Node* b2[] = {w2.branch, w2.if_true};
     503           5 :   t.CheckLoop(h2, 3, b2, 2);
     504           5 : }
     505             : 
     506             : 
     507       26661 : TEST(LaNestedLoop2) {
     508             :   // Two loops nested in an outer loop.
     509           5 :   LoopFinderTester t;
     510           5 :   While w1(t, t.p0);
     511           5 :   While w2(t, t.p0);
     512           5 :   While w3(t, t.p0);
     513             :   w2.nest(w1);
     514             :   w3.nest(w1);
     515           5 :   w3.chain(w2.exit);
     516           5 :   t.Return(t.p0, t.start, w1.exit);
     517             : 
     518           5 :   Node* chain1[] = {w1.loop, w2.loop};
     519           5 :   t.CheckNestedLoops(chain1, 2);
     520             : 
     521           5 :   Node* chain2[] = {w1.loop, w3.loop};
     522           5 :   t.CheckNestedLoops(chain2, 2);
     523             : 
     524           5 :   Node* h1[] = {w1.loop};
     525          25 :   Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
     526          25 :                 w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
     527           5 :   t.CheckLoop(h1, 1, b1, 10);
     528             : 
     529           5 :   Node* h2[] = {w2.loop};
     530           5 :   Node* b2[] = {w2.branch, w2.if_true};
     531           5 :   t.CheckLoop(h2, 1, b2, 2);
     532             : 
     533           5 :   Node* h3[] = {w3.loop};
     534           5 :   Node* b3[] = {w3.branch, w3.if_true};
     535           5 :   t.CheckLoop(h3, 1, b3, 2);
     536           5 : }
     537             : 
     538             : 
     539       26661 : TEST(LaNestedLoop3) {
     540             :   // Three nested loops.
     541           5 :   LoopFinderTester t;
     542           5 :   While w1(t, t.p0);
     543           5 :   While w2(t, t.p0);
     544           5 :   While w3(t, t.p0);
     545           5 :   w2.loop->ReplaceInput(0, w1.if_true);
     546           5 :   w3.loop->ReplaceInput(0, w2.if_true);
     547           5 :   w2.loop->ReplaceInput(1, w3.exit);
     548           5 :   w1.loop->ReplaceInput(1, w2.exit);
     549           5 :   t.Return(t.p0, t.start, w1.exit);
     550             : 
     551           5 :   Node* chain[] = {w1.loop, w2.loop, w3.loop};
     552           5 :   t.CheckNestedLoops(chain, 3);
     553             : 
     554           5 :   Node* h1[] = {w1.loop};
     555          25 :   Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
     556          25 :                 w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
     557           5 :   t.CheckLoop(h1, 1, b1, 10);
     558             : 
     559           5 :   Node* h2[] = {w2.loop};
     560           5 :   Node* b2[] = {w2.branch, w2.if_true, w3.loop, w3.branch, w3.if_true, w3.exit};
     561           5 :   t.CheckLoop(h2, 1, b2, 6);
     562             : 
     563           5 :   Node* h3[] = {w3.loop};
     564           5 :   Node* b3[] = {w3.branch, w3.if_true};
     565           5 :   t.CheckLoop(h3, 1, b3, 2);
     566           5 : }
     567             : 
     568             : 
     569       26661 : TEST(LaNestedLoop3c) {
     570             :   // Three nested loops with counters.
     571           5 :   LoopFinderTester t;
     572           5 :   While w1(t, t.p0);
     573           5 :   Counter c1(w1, 0, 1);
     574           5 :   While w2(t, t.p0);
     575           5 :   Counter c2(w2, 0, 1);
     576           5 :   While w3(t, t.p0);
     577           5 :   Counter c3(w3, 0, 1);
     578           5 :   w2.loop->ReplaceInput(0, w1.if_true);
     579           5 :   w3.loop->ReplaceInput(0, w2.if_true);
     580           5 :   w2.loop->ReplaceInput(1, w3.exit);
     581           5 :   w1.loop->ReplaceInput(1, w2.exit);
     582           5 :   w1.branch->ReplaceInput(0, c1.phi);
     583           5 :   w2.branch->ReplaceInput(0, c2.phi);
     584           5 :   w3.branch->ReplaceInput(0, c3.phi);
     585           5 :   t.Return(c1.phi, t.start, w1.exit);
     586             : 
     587           5 :   Node* chain[] = {w1.loop, w2.loop, w3.loop};
     588           5 :   t.CheckNestedLoops(chain, 3);
     589             : 
     590           5 :   Node* h1[] = {w1.loop, c1.phi};
     591          20 :   Node* b1[] = {w1.branch, w1.if_true, c1.add,    c2.add,     c2.add,
     592          25 :                 c2.phi,    c3.phi,     w2.loop,   w2.branch,  w2.if_true,
     593          45 :                 w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
     594           5 :   t.CheckLoop(h1, 2, b1, 15);
     595             : 
     596           5 :   Node* h2[] = {w2.loop, c2.phi};
     597          25 :   Node* b2[] = {w2.branch, w2.if_true, c2.add,     c3.add, c3.phi,
     598          25 :                 w3.loop,   w3.branch,  w3.if_true, w3.exit};
     599           5 :   t.CheckLoop(h2, 2, b2, 9);
     600             : 
     601           5 :   Node* h3[] = {w3.loop, c3.phi};
     602           5 :   Node* b3[] = {w3.branch, w3.if_true, c3.add};
     603           5 :   t.CheckLoop(h3, 2, b3, 3);
     604           5 : }
     605             : 
     606             : 
     607       26661 : TEST(LaMultipleExit1) {
     608             :   const int kMaxExits = 10;
     609             :   Node* merge[1 + kMaxExits];
     610             :   Node* body[2 * kMaxExits];
     611             : 
     612             :   // A single loop with {i} exits.
     613          95 :   for (int i = 1; i < kMaxExits; i++) {
     614          45 :     LoopFinderTester t;
     615          45 :     Node* cond = t.p0;
     616             : 
     617             :     int merge_count = 0;
     618             :     int body_count = 0;
     619          45 :     Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
     620             :     Node* last = loop;
     621             : 
     622         495 :     for (int e = 0; e < i; e++) {
     623         225 :       Node* branch = t.graph.NewNode(t.common.Branch(), cond, last);
     624         225 :       Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     625         225 :       Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
     626             :       last = if_true;
     627             : 
     628         225 :       body[body_count++] = branch;
     629         225 :       body[body_count++] = if_true;
     630         225 :       merge[merge_count++] = exit;
     631             :     }
     632             : 
     633          45 :     loop->ReplaceInput(1, last);  // form loop backedge.
     634          45 :     Node* end = t.graph.NewNode(t.common.Merge(i), i, merge);  // form exit.
     635             :     t.graph.SetEnd(end);
     636             : 
     637          45 :     Node* h[] = {loop};
     638          45 :     t.CheckLoop(h, 1, body, body_count);
     639             :   }
     640           5 : }
     641             : 
     642             : 
     643       26661 : TEST(LaMultipleBackedge1) {
     644             :   const int kMaxBackedges = 10;
     645             :   Node* loop_inputs[1 + kMaxBackedges];
     646             :   Node* body[3 * kMaxBackedges];
     647             : 
     648             :   // A single loop with {i} backedges.
     649          95 :   for (int i = 1; i < kMaxBackedges; i++) {
     650          45 :     LoopFinderTester t;
     651             : 
     652         315 :     for (int j = 0; j <= i; j++) loop_inputs[j] = t.start;
     653          45 :     Node* loop = t.graph.NewNode(t.common.Loop(1 + i), 1 + i, loop_inputs);
     654             : 
     655          45 :     Node* cond = t.p0;
     656             :     int body_count = 0;
     657             :     Node* exit = loop;
     658             : 
     659         495 :     for (int b = 0; b < i; b++) {
     660         225 :       Node* branch = t.graph.NewNode(t.common.Branch(), cond, exit);
     661         225 :       Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     662         225 :       Node* if_false = t.graph.NewNode(t.common.IfFalse(), branch);
     663             :       exit = if_false;
     664             : 
     665         225 :       body[body_count++] = branch;
     666         225 :       body[body_count++] = if_true;
     667         225 :       if (b != (i - 1)) body[body_count++] = if_false;
     668             : 
     669         225 :       loop->ReplaceInput(1 + b, if_true);
     670             :     }
     671             : 
     672             :     t.graph.SetEnd(exit);
     673             : 
     674          45 :     Node* h[] = {loop};
     675          45 :     t.CheckLoop(h, 1, body, body_count);
     676             :   }
     677           5 : }
     678             : 
     679             : 
     680       26661 : TEST(LaEdgeMatrix1) {
     681             :   // Test various kinds of extra edges added to a simple loop.
     682          35 :   for (int i = 0; i < 3; i++) {
     683         105 :     for (int j = 0; j < 3; j++) {
     684         315 :       for (int k = 0; k < 3; k++) {
     685         135 :         LoopFinderTester t;
     686             : 
     687         135 :         Node* p1 = t.jsgraph.Int32Constant(11);
     688         135 :         Node* p2 = t.jsgraph.Int32Constant(22);
     689         135 :         Node* p3 = t.jsgraph.Int32Constant(33);
     690             : 
     691         135 :         Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
     692         135 :         Node* phi = t.graph.NewNode(
     693             :             t.common.Phi(MachineRepresentation::kWord32, 2), t.one, p1, loop);
     694             :         Node* cond = t.graph.NewNode(&kIntAdd, phi, p2);
     695         135 :         Node* branch = t.graph.NewNode(t.common.Branch(), cond, loop);
     696         135 :         Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     697         135 :         Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
     698         135 :         loop->ReplaceInput(1, if_true);
     699         135 :         Node* zero = t.graph.NewNode(t.common.Int32Constant(0));
     700         135 :         Node* ret = t.graph.NewNode(t.common.Return(), zero, p3, t.start, exit);
     701             :         t.graph.SetEnd(ret);
     702             : 
     703         135 :         Node* choices[] = {p1, phi, cond};
     704         135 :         p1->ReplaceUses(choices[i]);
     705         135 :         p2->ReplaceUses(choices[j]);
     706         135 :         p3->ReplaceUses(choices[k]);
     707             : 
     708         135 :         Node* header[] = {loop, phi};
     709         135 :         Node* body[] = {cond, branch, if_true};
     710         135 :         t.CheckLoop(header, 2, body, 3);
     711             :       }
     712             :     }
     713             :   }
     714           5 : }
     715             : 
     716             : 
     717          25 : void RunEdgeMatrix2(int i) {
     718          25 :   CHECK(i >= 0 && i < 5);
     719         275 :   for (int j = 0; j < 5; j++) {
     720        1375 :     for (int k = 0; k < 5; k++) {
     721         625 :       LoopFinderTester t;
     722             : 
     723         625 :       Node* p1 = t.jsgraph.Int32Constant(11);
     724         625 :       Node* p2 = t.jsgraph.Int32Constant(22);
     725         625 :       Node* p3 = t.jsgraph.Int32Constant(33);
     726             : 
     727             :       // outer loop.
     728         625 :       Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
     729         625 :       Node* phi1 = t.graph.NewNode(
     730             :           t.common.Phi(MachineRepresentation::kWord32, 2), t.one, p1, loop1);
     731         625 :       Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, t.one);
     732         625 :       Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
     733         625 :       Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
     734         625 :       Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
     735             : 
     736             :       // inner loop.
     737         625 :       Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
     738         625 :       Node* phi2 = t.graph.NewNode(
     739             :           t.common.Phi(MachineRepresentation::kWord32, 2), t.one, p2, loop2);
     740             :       Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p3);
     741         625 :       Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
     742         625 :       Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
     743         625 :       Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
     744         625 :       loop2->ReplaceInput(1, if_true2);
     745         625 :       loop1->ReplaceInput(1, exit2);
     746             : 
     747         625 :       Node* zero = t.graph.NewNode(t.common.Int32Constant(0));
     748             :       Node* ret =
     749         625 :           t.graph.NewNode(t.common.Return(), zero, phi1, t.start, exit1);
     750             :       t.graph.SetEnd(ret);
     751             : 
     752         625 :       Node* choices[] = {p1, phi1, cond1, phi2, cond2};
     753         625 :       p1->ReplaceUses(choices[i]);
     754         625 :       p2->ReplaceUses(choices[j]);
     755         625 :       p3->ReplaceUses(choices[k]);
     756             : 
     757         625 :       Node* header1[] = {loop1, phi1};
     758             :       Node* body1[] = {cond1, branch1, if_true1, exit2,   loop2,
     759         625 :                        phi2,  cond2,   branch2,  if_true2};
     760         625 :       t.CheckLoop(header1, 2, body1, 9);
     761             : 
     762         625 :       Node* header2[] = {loop2, phi2};
     763         625 :       Node* body2[] = {cond2, branch2, if_true2};
     764         625 :       t.CheckLoop(header2, 2, body2, 3);
     765             : 
     766         625 :       Node* chain[] = {loop1, loop2};
     767         625 :       t.CheckNestedLoops(chain, 2);
     768             :     }
     769             :   }
     770          25 : }
     771             : 
     772             : 
     773       26661 : TEST(LaEdgeMatrix2_0) { RunEdgeMatrix2(0); }
     774             : 
     775             : 
     776       26661 : TEST(LaEdgeMatrix2_1) { RunEdgeMatrix2(1); }
     777             : 
     778             : 
     779       26661 : TEST(LaEdgeMatrix2_2) { RunEdgeMatrix2(2); }
     780             : 
     781             : 
     782       26661 : TEST(LaEdgeMatrix2_3) { RunEdgeMatrix2(3); }
     783             : 
     784             : 
     785       26661 : TEST(LaEdgeMatrix2_4) { RunEdgeMatrix2(4); }
     786             : 
     787             : 
     788             : // Generates a triply-nested loop with extra edges between the phis and
     789             : // conditions according to the edge choice parameters.
     790      162000 : void RunEdgeMatrix3(int c1a, int c1b, int c1c,    // line break
     791             :                     int c2a, int c2b, int c2c,    // line break
     792             :                     int c3a, int c3b, int c3c) {  // line break
     793      162000 :   LoopFinderTester t;
     794             : 
     795      162000 :   Node* p1a = t.jsgraph.Int32Constant(11);
     796      162000 :   Node* p1b = t.jsgraph.Int32Constant(22);
     797      162000 :   Node* p1c = t.jsgraph.Int32Constant(33);
     798      162000 :   Node* p2a = t.jsgraph.Int32Constant(44);
     799      162000 :   Node* p2b = t.jsgraph.Int32Constant(55);
     800      162000 :   Node* p2c = t.jsgraph.Int32Constant(66);
     801      162000 :   Node* p3a = t.jsgraph.Int32Constant(77);
     802      162000 :   Node* p3b = t.jsgraph.Int32Constant(88);
     803      162000 :   Node* p3c = t.jsgraph.Int32Constant(99);
     804             : 
     805             :   // L1 depth = 0
     806      162000 :   Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
     807      162000 :   Node* phi1 = t.graph.NewNode(t.common.Phi(MachineRepresentation::kWord32, 2),
     808             :                                p1a, p1c, loop1);
     809             :   Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, p1b);
     810      162000 :   Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
     811      162000 :   Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
     812      162000 :   Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
     813             : 
     814             :   // L2 depth = 1
     815      162000 :   Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
     816      162000 :   Node* phi2 = t.graph.NewNode(t.common.Phi(MachineRepresentation::kWord32, 2),
     817             :                                p2a, p2c, loop2);
     818             :   Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p2b);
     819      162000 :   Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
     820      162000 :   Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
     821      162000 :   Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
     822             : 
     823             :   // L3 depth = 2
     824      162000 :   Node* loop3 = t.graph.NewNode(t.common.Loop(2), if_true2, t.start);
     825      162000 :   Node* phi3 = t.graph.NewNode(t.common.Phi(MachineRepresentation::kWord32, 2),
     826             :                                p3a, p3c, loop3);
     827             :   Node* cond3 = t.graph.NewNode(&kIntAdd, phi3, p3b);
     828      162000 :   Node* branch3 = t.graph.NewNode(t.common.Branch(), cond3, loop3);
     829      162000 :   Node* if_true3 = t.graph.NewNode(t.common.IfTrue(), branch3);
     830      162000 :   Node* exit3 = t.graph.NewNode(t.common.IfFalse(), branch3);
     831             : 
     832      162000 :   loop3->ReplaceInput(1, if_true3);
     833      162000 :   loop2->ReplaceInput(1, exit3);
     834      162000 :   loop1->ReplaceInput(1, exit2);
     835             : 
     836      162000 :   Node* zero = t.graph.NewNode(t.common.Int32Constant(0));
     837      162000 :   Node* ret = t.graph.NewNode(t.common.Return(), zero, phi1, t.start, exit1);
     838             :   t.graph.SetEnd(ret);
     839             : 
     840             :   // Mutate the graph according to the edge choices.
     841             : 
     842      162000 :   Node* o1[] = {t.one};
     843      162000 :   Node* o2[] = {t.one, phi1, cond1};
     844      162000 :   Node* o3[] = {t.one, phi1, cond1, phi2, cond2};
     845             : 
     846      162000 :   p1a->ReplaceUses(o1[c1a]);
     847      162000 :   p1b->ReplaceUses(o1[c1b]);
     848             : 
     849      162000 :   p2a->ReplaceUses(o2[c2a]);
     850      162000 :   p2b->ReplaceUses(o2[c2b]);
     851             : 
     852      162000 :   p3a->ReplaceUses(o3[c3a]);
     853      162000 :   p3b->ReplaceUses(o3[c3b]);
     854             : 
     855      162000 :   Node* l2[] = {phi1, cond1, phi2, cond2};
     856      162000 :   Node* l3[] = {phi1, cond1, phi2, cond2, phi3, cond3};
     857             : 
     858      162000 :   p1c->ReplaceUses(l2[c1c]);
     859      162000 :   p2c->ReplaceUses(l3[c2c]);
     860      162000 :   p3c->ReplaceUses(l3[c3c]);
     861             : 
     862             :   // Run the tests and verify loop structure.
     863             : 
     864      162000 :   Node* chain[] = {loop1, loop2, loop3};
     865      162000 :   t.CheckNestedLoops(chain, 3);
     866             : 
     867      162000 :   Node* header1[] = {loop1, phi1};
     868             :   Node* body1[] = {cond1, branch1, if_true1, exit2,    loop2,
     869             :                    phi2,  cond2,   branch2,  if_true2, exit3,
     870      162000 :                    loop3, phi3,    cond3,    branch3,  if_true3};
     871      162000 :   t.CheckLoop(header1, 2, body1, 15);
     872             : 
     873      162000 :   Node* header2[] = {loop2, phi2};
     874             :   Node* body2[] = {cond2, branch2, if_true2, exit3,   loop3,
     875      162000 :                    phi3,  cond3,   branch3,  if_true3};
     876      162000 :   t.CheckLoop(header2, 2, body2, 9);
     877             : 
     878      162000 :   Node* header3[] = {loop3, phi3};
     879      162000 :   Node* body3[] = {cond3, branch3, if_true3};
     880      162000 :   t.CheckLoop(header3, 2, body3, 3);
     881      162000 : }
     882             : 
     883             : 
     884             : // Runs all combinations with a fixed {i}.
     885          30 : static void RunEdgeMatrix3_i(int i) {
     886          90 :   for (int a = 0; a < 1; a++) {
     887          90 :     for (int b = 0; b < 1; b++) {
     888         270 :       for (int c = 0; c < 4; c++) {
     889         840 :         for (int d = 0; d < 3; d++) {
     890        2520 :           for (int e = 0; e < 3; e++) {
     891       14040 :             for (int f = 0; f < 6; f++) {
     892       71280 :               for (int g = 0; g < 5; g++) {
     893      356400 :                 for (int h = 0; h < 5; h++) {
     894      162000 :                   RunEdgeMatrix3(a, b, c, d, e, f, g, h, i);
     895             :                 }
     896             :               }
     897             :             }
     898             :           }
     899             :         }
     900             :       }
     901             :     }
     902             :   }
     903          30 : }
     904             : 
     905             : 
     906             : // Test all possible legal triply-nested loops with conditions and phis.
     907       26661 : TEST(LaEdgeMatrix3_0) { RunEdgeMatrix3_i(0); }
     908             : 
     909             : 
     910       26661 : TEST(LaEdgeMatrix3_1) { RunEdgeMatrix3_i(1); }
     911             : 
     912             : 
     913       26661 : TEST(LaEdgeMatrix3_2) { RunEdgeMatrix3_i(2); }
     914             : 
     915             : 
     916       26661 : TEST(LaEdgeMatrix3_3) { RunEdgeMatrix3_i(3); }
     917             : 
     918             : 
     919       26661 : TEST(LaEdgeMatrix3_4) { RunEdgeMatrix3_i(4); }
     920             : 
     921             : 
     922       26661 : TEST(LaEdgeMatrix3_5) { RunEdgeMatrix3_i(5); }
     923             : 
     924             : 
     925          40 : static void RunManyChainedLoops_i(int count) {
     926          40 :   LoopFinderTester t;
     927          40 :   Node** nodes = t.zone()->NewArray<Node*>(count * 4);
     928          40 :   Node* k11 = t.jsgraph.Int32Constant(11);
     929          40 :   Node* k12 = t.jsgraph.Int32Constant(12);
     930          40 :   Node* last = t.start;
     931             : 
     932             :   // Build loops.
     933        3530 :   for (int i = 0; i < count; i++) {
     934        1745 :     Node* loop = t.graph.NewNode(t.common.Loop(2), last, t.start);
     935        1745 :     Node* phi = t.graph.NewNode(t.common.Phi(MachineRepresentation::kWord32, 2),
     936             :                                 k11, k12, loop);
     937        1745 :     Node* branch = t.graph.NewNode(t.common.Branch(), phi, loop);
     938        1745 :     Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     939        1745 :     Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
     940        1745 :     loop->ReplaceInput(1, if_true);
     941             : 
     942        1745 :     nodes[i * 4 + 0] = loop;
     943        1745 :     nodes[i * 4 + 1] = phi;
     944        1745 :     nodes[i * 4 + 2] = branch;
     945        1745 :     nodes[i * 4 + 3] = if_true;
     946             : 
     947             :     last = exit;
     948             :   }
     949             : 
     950          40 :   Node* zero = t.graph.NewNode(t.common.Int32Constant(0));
     951          40 :   Node* ret = t.graph.NewNode(t.common.Return(), zero, t.p0, t.start, last);
     952             :   t.graph.SetEnd(ret);
     953             : 
     954             :   // Verify loops.
     955        3530 :   for (int i = 0; i < count; i++) {
     956        1745 :     t.CheckLoop(nodes + i * 4, 2, nodes + i * 4 + 2, 2);
     957             :   }
     958          40 : }
     959             : 
     960             : 
     961          40 : static void RunManyNestedLoops_i(int count) {
     962          40 :   LoopFinderTester t;
     963          40 :   Node** nodes = t.zone()->NewArray<Node*>(count * 5);
     964          40 :   Node* k11 = t.jsgraph.Int32Constant(11);
     965          40 :   Node* k12 = t.jsgraph.Int32Constant(12);
     966             :   Node* outer = nullptr;
     967          40 :   Node* entry = t.start;
     968             : 
     969             :   // Build loops.
     970          40 :   Node* zero = t.graph.NewNode(t.common.Int32Constant(0));
     971        3530 :   for (int i = 0; i < count; i++) {
     972        1745 :     Node* loop = t.graph.NewNode(t.common.Loop(2), entry, t.start);
     973        1745 :     Node* phi = t.graph.NewNode(t.common.Phi(MachineRepresentation::kWord32, 2),
     974             :                                 k11, k12, loop);
     975        1745 :     Node* branch = t.graph.NewNode(t.common.Branch(), phi, loop);
     976        1745 :     Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
     977        1745 :     Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
     978             : 
     979        1745 :     nodes[i * 5 + 0] = exit;     // outside
     980        1745 :     nodes[i * 5 + 1] = loop;     // header
     981        1745 :     nodes[i * 5 + 2] = phi;      // header
     982        1745 :     nodes[i * 5 + 3] = branch;   // body
     983        1745 :     nodes[i * 5 + 4] = if_true;  // body
     984             : 
     985        1745 :     if (outer != nullptr) {
     986             :       // inner loop.
     987        1705 :       outer->ReplaceInput(1, exit);
     988             :     } else {
     989             :       // outer loop.
     990          40 :       Node* ret = t.graph.NewNode(t.common.Return(), zero, t.p0, t.start, exit);
     991             :       t.graph.SetEnd(ret);
     992             :     }
     993             :     outer = loop;
     994             :     entry = if_true;
     995             :   }
     996          40 :   outer->ReplaceInput(1, entry);  // innermost loop.
     997             : 
     998             :   // Verify loops.
     999        3530 :   for (int i = 0; i < count; i++) {
    1000        1745 :     int k = i * 5;
    1001        1745 :     t.CheckLoop(nodes + k + 1, 2, nodes + k + 3, count * 5 - k - 3);
    1002             :   }
    1003          40 : }
    1004             : 
    1005             : 
    1006       26661 : TEST(LaManyChained_30) { RunManyChainedLoops_i(30); }
    1007       26661 : TEST(LaManyChained_31) { RunManyChainedLoops_i(31); }
    1008       26661 : TEST(LaManyChained_32) { RunManyChainedLoops_i(32); }
    1009       26661 : TEST(LaManyChained_33) { RunManyChainedLoops_i(33); }
    1010       26661 : TEST(LaManyChained_34) { RunManyChainedLoops_i(34); }
    1011       26661 : TEST(LaManyChained_62) { RunManyChainedLoops_i(62); }
    1012       26661 : TEST(LaManyChained_63) { RunManyChainedLoops_i(63); }
    1013       26661 : TEST(LaManyChained_64) { RunManyChainedLoops_i(64); }
    1014             : 
    1015       26661 : TEST(LaManyNested_30) { RunManyNestedLoops_i(30); }
    1016       26661 : TEST(LaManyNested_31) { RunManyNestedLoops_i(31); }
    1017       26661 : TEST(LaManyNested_32) { RunManyNestedLoops_i(32); }
    1018       26661 : TEST(LaManyNested_33) { RunManyNestedLoops_i(33); }
    1019       26661 : TEST(LaManyNested_34) { RunManyNestedLoops_i(34); }
    1020       26661 : TEST(LaManyNested_62) { RunManyNestedLoops_i(62); }
    1021       26661 : TEST(LaManyNested_63) { RunManyNestedLoops_i(63); }
    1022       26661 : TEST(LaManyNested_64) { RunManyNestedLoops_i(64); }
    1023             : 
    1024             : 
    1025       26666 : TEST(LaPhiTangle) { LoopFinderTester t; }
    1026             : 
    1027             : }  // namespace compiler
    1028             : }  // namespace internal
    1029       79968 : }  // namespace v8

Generated by: LCOV version 1.10