LCOV - code coverage report
Current view: top level - test/unittests/compiler - loop-peeling-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 303 315 96.2 %
Date: 2019-04-18 Functions: 33 43 76.7 %

          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/access-builder.h"
       6             : #include "src/compiler/graph.h"
       7             : #include "src/compiler/graph-visualizer.h"
       8             : #include "src/compiler/js-graph.h"
       9             : #include "src/compiler/loop-peeling.h"
      10             : #include "src/compiler/machine-operator.h"
      11             : #include "src/compiler/node.h"
      12             : #include "src/compiler/node-properties.h"
      13             : #include "test/unittests/compiler/compiler-test-utils.h"
      14             : #include "test/unittests/compiler/graph-unittest.h"
      15             : #include "test/unittests/compiler/node-test-utils.h"
      16             : #include "testing/gmock-support.h"
      17             : 
      18             : using testing::AllOf;
      19             : using testing::BitEq;
      20             : using testing::Capture;
      21             : using testing::CaptureEq;
      22             : 
      23             : namespace v8 {
      24             : namespace internal {
      25             : namespace compiler {
      26             : 
      27             : struct While {
      28             :   Node* loop;
      29             :   Node* branch;
      30             :   Node* if_true;
      31             :   Node* if_false;
      32             :   Node* exit;
      33             : };
      34             : 
      35             : 
      36             : // A helper for building branches.
      37             : struct Branch {
      38             :   Node* branch;
      39             :   Node* if_true;
      40             :   Node* if_false;
      41             : };
      42             : 
      43             : 
      44             : // A helper for building counters attached to loops.
      45             : struct Counter {
      46             :   Node* base;
      47             :   Node* inc;
      48             :   Node* phi;
      49             :   Node* add;
      50             :   Node* exit_marker;
      51             : };
      52             : 
      53             : 
      54             : class LoopPeelingTest : public GraphTest {
      55             :  public:
      56          20 :   LoopPeelingTest() : GraphTest(1), machine_(zone()) {}
      57          10 :   ~LoopPeelingTest() override = default;
      58             : 
      59             :  protected:
      60             :   MachineOperatorBuilder machine_;
      61             : 
      62           5 :   MachineOperatorBuilder* machine() { return &machine_; }
      63             : 
      64          10 :   LoopTree* GetLoopTree() {
      65          10 :     if (FLAG_trace_turbo_graph) {
      66           0 :       StdoutStream{} << AsRPO(*graph());
      67             :     }
      68          20 :     Zone zone(isolate()->allocator(), ZONE_NAME);
      69          20 :     return LoopFinder::BuildLoopTree(graph(), &zone);
      70             :   }
      71             : 
      72             : 
      73           7 :   PeeledIteration* PeelOne() {
      74           7 :     LoopTree* loop_tree = GetLoopTree();
      75           7 :     LoopTree::Loop* loop = loop_tree->outer_loops()[0];
      76             :     LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
      77             :                       node_origins());
      78          14 :     EXPECT_TRUE(peeler.CanPeel(loop));
      79           7 :     return Peel(peeler, loop);
      80             :   }
      81             : 
      82           9 :   PeeledIteration* Peel(LoopPeeler peeler, LoopTree::Loop* loop) {
      83          18 :     EXPECT_TRUE(peeler.CanPeel(loop));
      84           9 :     PeeledIteration* peeled = peeler.Peel(loop);
      85           9 :     if (FLAG_trace_turbo_graph) {
      86           0 :       StdoutStream{} << AsRPO(*graph());
      87             :     }
      88           9 :     return peeled;
      89             :   }
      90             : 
      91          10 :   Node* InsertReturn(Node* val, Node* effect, Node* control) {
      92          10 :     Node* zero = graph()->NewNode(common()->Int32Constant(0));
      93          10 :     Node* r = graph()->NewNode(common()->Return(), zero, val, effect, control);
      94             :     graph()->SetEnd(r);
      95          10 :     return r;
      96             :   }
      97             : 
      98          49 :   Node* ExpectPeeled(Node* node, PeeledIteration* iter) {
      99          49 :     Node* p = iter->map(node);
     100          49 :     EXPECT_NE(node, p);
     101          49 :     return p;
     102             :   }
     103             : 
     104          11 :   void ExpectNotPeeled(Node* node, PeeledIteration* iter) {
     105          22 :     EXPECT_EQ(node, iter->map(node));
     106          11 :   }
     107             : 
     108           8 :   While NewWhile(Node* cond, Node* control = nullptr) {
     109           8 :     if (control == nullptr) control = start();
     110             :     While w;
     111          16 :     w.loop = graph()->NewNode(common()->Loop(2), control, control);
     112          16 :     w.branch = graph()->NewNode(common()->Branch(), cond, w.loop);
     113          16 :     w.if_true = graph()->NewNode(common()->IfTrue(), w.branch);
     114          16 :     w.if_false = graph()->NewNode(common()->IfFalse(), w.branch);
     115          16 :     w.exit = graph()->NewNode(common()->LoopExit(), w.if_false, w.loop);
     116           8 :     w.loop->ReplaceInput(1, w.if_true);
     117           8 :     return w;
     118             :   }
     119             : 
     120             :   void Chain(While* a, Node* control) { a->loop->ReplaceInput(0, control); }
     121             :   void Nest(While* a, While* b) {
     122           3 :     b->loop->ReplaceInput(1, a->exit);
     123           3 :     a->loop->ReplaceInput(0, b->if_true);
     124             :   }
     125           1 :   Node* NewPhi(While* w, Node* a, Node* b) {
     126           2 :     return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), a,
     127           1 :                             b, w->loop);
     128             :   }
     129             : 
     130           9 :   Branch NewBranch(Node* cond, Node* control = nullptr) {
     131             :     Branch b;
     132           9 :     if (control == nullptr) control = start();
     133          18 :     b.branch = graph()->NewNode(common()->Branch(), cond, control);
     134          18 :     b.if_true = graph()->NewNode(common()->IfTrue(), b.branch);
     135          18 :     b.if_false = graph()->NewNode(common()->IfFalse(), b.branch);
     136           9 :     return b;
     137             :   }
     138             : 
     139           4 :   Counter NewCounter(While* w, int32_t b, int32_t k) {
     140             :     Counter c;
     141           4 :     c.base = Int32Constant(b);
     142           4 :     c.inc = Int32Constant(k);
     143           8 :     c.phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     144           4 :                              c.base, c.base, w->loop);
     145           8 :     c.add = graph()->NewNode(machine()->Int32Add(), c.phi, c.inc);
     146           4 :     c.phi->ReplaceInput(1, c.add);
     147           8 :     c.exit_marker = graph()->NewNode(common()->LoopExitValue(), c.phi, w->exit);
     148           4 :     return c;
     149             :   }
     150             : };
     151             : 
     152             : 
     153       15419 : TEST_F(LoopPeelingTest, SimpleLoop) {
     154           1 :   Node* p0 = Parameter(0);
     155           1 :   While w = NewWhile(p0);
     156           1 :   Node* r = InsertReturn(p0, start(), w.exit);
     157             : 
     158           1 :   PeeledIteration* peeled = PeelOne();
     159             : 
     160           1 :   Node* br1 = ExpectPeeled(w.branch, peeled);
     161           1 :   Node* if_true1 = ExpectPeeled(w.if_true, peeled);
     162           1 :   Node* if_false1 = ExpectPeeled(w.if_false, peeled);
     163             : 
     164           6 :   EXPECT_THAT(br1, IsBranch(p0, start()));
     165           5 :   EXPECT_THAT(if_true1, IsIfTrue(br1));
     166           5 :   EXPECT_THAT(if_false1, IsIfFalse(br1));
     167             : 
     168           6 :   EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
     169           9 :   EXPECT_THAT(r, IsReturn(p0, start(), IsMerge(w.if_false, if_false1)));
     170           1 : }
     171             : 
     172             : 
     173       15419 : TEST_F(LoopPeelingTest, SimpleLoopWithCounter) {
     174           1 :   Node* p0 = Parameter(0);
     175           1 :   While w = NewWhile(p0);
     176           1 :   Counter c = NewCounter(&w, 0, 1);
     177           1 :   Node* r = InsertReturn(c.exit_marker, start(), w.exit);
     178             : 
     179           1 :   PeeledIteration* peeled = PeelOne();
     180             : 
     181           1 :   Node* br1 = ExpectPeeled(w.branch, peeled);
     182           1 :   Node* if_true1 = ExpectPeeled(w.if_true, peeled);
     183           1 :   Node* if_false1 = ExpectPeeled(w.if_false, peeled);
     184             : 
     185           6 :   EXPECT_THAT(br1, IsBranch(p0, start()));
     186           5 :   EXPECT_THAT(if_true1, IsIfTrue(br1));
     187           5 :   EXPECT_THAT(if_false1, IsIfFalse(br1));
     188           6 :   EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
     189             : 
     190           6 :   EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
     191             : 
     192           6 :   EXPECT_THAT(w.exit, IsMerge(w.if_false, if_false1));
     193          11 :   EXPECT_THAT(
     194             :       r, IsReturn(IsPhi(MachineRepresentation::kTagged, c.phi, c.base, w.exit),
     195           0 :                   start(), w.exit));
     196           1 : }
     197             : 
     198             : 
     199       15419 : TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_outer) {
     200           1 :   Node* p0 = Parameter(0);
     201           1 :   While outer = NewWhile(p0);
     202           1 :   While inner = NewWhile(p0);
     203             :   Nest(&inner, &outer);
     204             : 
     205           1 :   Counter c = NewCounter(&outer, 0, 1);
     206           1 :   Node* r = InsertReturn(c.exit_marker, start(), outer.exit);
     207             : 
     208           1 :   PeeledIteration* peeled = PeelOne();
     209             : 
     210           1 :   Node* bro = ExpectPeeled(outer.branch, peeled);
     211           1 :   Node* if_trueo = ExpectPeeled(outer.if_true, peeled);
     212           1 :   Node* if_falseo = ExpectPeeled(outer.if_false, peeled);
     213             : 
     214           6 :   EXPECT_THAT(bro, IsBranch(p0, start()));
     215           5 :   EXPECT_THAT(if_trueo, IsIfTrue(bro));
     216           5 :   EXPECT_THAT(if_falseo, IsIfFalse(bro));
     217             : 
     218           1 :   Node* bri = ExpectPeeled(inner.branch, peeled);
     219           1 :   Node* if_truei = ExpectPeeled(inner.if_true, peeled);
     220           1 :   Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
     221           1 :   Node* exiti = ExpectPeeled(inner.exit, peeled);
     222             : 
     223           6 :   EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
     224           5 :   EXPECT_THAT(if_truei, IsIfTrue(bri));
     225           5 :   EXPECT_THAT(if_falsei, IsIfFalse(bri));
     226             : 
     227           6 :   EXPECT_THAT(outer.loop, IsLoop(exiti, inner.exit));
     228           6 :   EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
     229             : 
     230             :   Capture<Node*> merge;
     231           6 :   EXPECT_THAT(outer.exit, IsMerge(outer.if_false, if_falseo));
     232          11 :   EXPECT_THAT(r, IsReturn(IsPhi(MachineRepresentation::kTagged, c.phi, c.base,
     233             :                                 outer.exit),
     234           0 :                           start(), outer.exit));
     235           1 : }
     236             : 
     237             : 
     238       15419 : TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_inner) {
     239           1 :   Node* p0 = Parameter(0);
     240           1 :   While outer = NewWhile(p0);
     241           1 :   While inner = NewWhile(p0);
     242             :   Nest(&inner, &outer);
     243             : 
     244           1 :   Counter c = NewCounter(&outer, 0, 1);
     245           1 :   Node* r = InsertReturn(c.exit_marker, start(), outer.exit);
     246             : 
     247           1 :   LoopTree* loop_tree = GetLoopTree();
     248           2 :   LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
     249           1 :   EXPECT_NE(nullptr, loop);
     250           3 :   EXPECT_EQ(1u, loop->depth());
     251             : 
     252             :   LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
     253             :                     node_origins());
     254           1 :   PeeledIteration* peeled = Peel(peeler, loop);
     255             : 
     256           1 :   ExpectNotPeeled(outer.loop, peeled);
     257           1 :   ExpectNotPeeled(outer.branch, peeled);
     258           1 :   ExpectNotPeeled(outer.if_true, peeled);
     259           1 :   ExpectNotPeeled(outer.if_false, peeled);
     260           1 :   ExpectNotPeeled(outer.exit, peeled);
     261             : 
     262           1 :   Node* bri = ExpectPeeled(inner.branch, peeled);
     263           1 :   Node* if_truei = ExpectPeeled(inner.if_true, peeled);
     264           1 :   Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
     265             : 
     266           6 :   EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
     267           5 :   EXPECT_THAT(if_truei, IsIfTrue(bri));
     268           5 :   EXPECT_THAT(if_falsei, IsIfFalse(bri));
     269             : 
     270           6 :   EXPECT_THAT(inner.exit, IsMerge(inner.if_false, if_falsei));
     271           6 :   EXPECT_THAT(outer.loop, IsLoop(start(), inner.exit));
     272           1 :   ExpectNotPeeled(c.add, peeled);
     273             : 
     274           7 :   EXPECT_THAT(r, IsReturn(c.exit_marker, start(), outer.exit));
     275             : }
     276             : 
     277             : 
     278       15419 : TEST_F(LoopPeelingTest, SimpleInnerCounter_peel_inner) {
     279           1 :   Node* p0 = Parameter(0);
     280           1 :   While outer = NewWhile(p0);
     281           1 :   While inner = NewWhile(p0);
     282             :   Nest(&inner, &outer);
     283           1 :   Counter c = NewCounter(&inner, 0, 1);
     284           1 :   Node* phi = NewPhi(&outer, Int32Constant(11), c.exit_marker);
     285             : 
     286           1 :   Node* r = InsertReturn(phi, start(), outer.exit);
     287             : 
     288           1 :   LoopTree* loop_tree = GetLoopTree();
     289           2 :   LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
     290           1 :   EXPECT_NE(nullptr, loop);
     291           3 :   EXPECT_EQ(1u, loop->depth());
     292             : 
     293             :   LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
     294             :                     node_origins());
     295           1 :   PeeledIteration* peeled = Peel(peeler, loop);
     296             : 
     297           1 :   ExpectNotPeeled(outer.loop, peeled);
     298           1 :   ExpectNotPeeled(outer.branch, peeled);
     299           1 :   ExpectNotPeeled(outer.if_true, peeled);
     300           1 :   ExpectNotPeeled(outer.if_false, peeled);
     301           1 :   ExpectNotPeeled(outer.exit, peeled);
     302             : 
     303           1 :   Node* bri = ExpectPeeled(inner.branch, peeled);
     304           1 :   Node* if_truei = ExpectPeeled(inner.if_true, peeled);
     305           1 :   Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
     306             : 
     307           6 :   EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
     308           5 :   EXPECT_THAT(if_truei, IsIfTrue(bri));
     309           5 :   EXPECT_THAT(if_falsei, IsIfFalse(bri));
     310             : 
     311           6 :   EXPECT_THAT(inner.exit, IsMerge(inner.if_false, if_falsei));
     312           6 :   EXPECT_THAT(outer.loop, IsLoop(start(), inner.exit));
     313           6 :   EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
     314             : 
     315           8 :   EXPECT_THAT(c.exit_marker,
     316           0 :               IsPhi(MachineRepresentation::kTagged, c.phi, c.base, inner.exit));
     317             : 
     318           9 :   EXPECT_THAT(phi, IsPhi(MachineRepresentation::kTagged, IsInt32Constant(11),
     319           0 :                          c.exit_marker, outer.loop));
     320             : 
     321           7 :   EXPECT_THAT(r, IsReturn(phi, start(), outer.exit));
     322           1 : }
     323             : 
     324             : 
     325       15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoop) {
     326           1 :   Node* p0 = Parameter(0);
     327           2 :   Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
     328           1 :   Branch b1 = NewBranch(p0, loop);
     329           1 :   Branch b2 = NewBranch(p0, b1.if_true);
     330             : 
     331           1 :   loop->ReplaceInput(1, b2.if_true);
     332           1 :   loop->ReplaceInput(2, b2.if_false);
     333             : 
     334           2 :   Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
     335             : 
     336           1 :   Node* r = InsertReturn(p0, start(), exit);
     337             : 
     338           1 :   PeeledIteration* peeled = PeelOne();
     339             : 
     340           1 :   Node* b1b = ExpectPeeled(b1.branch, peeled);
     341           1 :   Node* b1t = ExpectPeeled(b1.if_true, peeled);
     342           1 :   Node* b1f = ExpectPeeled(b1.if_false, peeled);
     343             : 
     344           6 :   EXPECT_THAT(b1b, IsBranch(p0, start()));
     345           5 :   EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
     346           5 :   EXPECT_THAT(b1f, IsIfFalse(b1b));
     347             : 
     348           1 :   Node* b2b = ExpectPeeled(b2.branch, peeled);
     349           1 :   Node* b2t = ExpectPeeled(b2.if_true, peeled);
     350           1 :   Node* b2f = ExpectPeeled(b2.if_false, peeled);
     351             : 
     352           6 :   EXPECT_THAT(b2b, IsBranch(p0, b1t));
     353           5 :   EXPECT_THAT(b2t, IsIfTrue(b2b));
     354           5 :   EXPECT_THAT(b2f, IsIfFalse(b2b));
     355             : 
     356           9 :   EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
     357           6 :   EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
     358           7 :   EXPECT_THAT(r, IsReturn(p0, start(), exit));
     359           1 : }
     360             : 
     361             : 
     362       15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoopWithPhi) {
     363           1 :   Node* p0 = Parameter(0);
     364           2 :   Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
     365           1 :   Branch b1 = NewBranch(p0, loop);
     366           1 :   Branch b2 = NewBranch(p0, b1.if_true);
     367           1 :   Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 3),
     368             :                                Int32Constant(0), Int32Constant(1),
     369           1 :                                Int32Constant(2), loop);
     370             : 
     371           1 :   loop->ReplaceInput(1, b2.if_true);
     372           1 :   loop->ReplaceInput(2, b2.if_false);
     373             : 
     374           2 :   Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
     375           2 :   Node* exit_marker = graph()->NewNode(common()->LoopExitValue(), phi, exit);
     376           1 :   Node* r = InsertReturn(exit_marker, start(), exit);
     377             : 
     378           1 :   PeeledIteration* peeled = PeelOne();
     379             : 
     380           1 :   Node* b1b = ExpectPeeled(b1.branch, peeled);
     381           1 :   Node* b1t = ExpectPeeled(b1.if_true, peeled);
     382           1 :   Node* b1f = ExpectPeeled(b1.if_false, peeled);
     383             : 
     384           6 :   EXPECT_THAT(b1b, IsBranch(p0, start()));
     385           5 :   EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
     386           5 :   EXPECT_THAT(b1f, IsIfFalse(b1b));
     387             : 
     388           1 :   Node* b2b = ExpectPeeled(b2.branch, peeled);
     389           1 :   Node* b2t = ExpectPeeled(b2.if_true, peeled);
     390           1 :   Node* b2f = ExpectPeeled(b2.if_false, peeled);
     391             : 
     392           6 :   EXPECT_THAT(b2b, IsBranch(p0, b1t));
     393           5 :   EXPECT_THAT(b2t, IsIfTrue(b2b));
     394           5 :   EXPECT_THAT(b2f, IsIfFalse(b2b));
     395             : 
     396           9 :   EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
     397             : 
     398          19 :   EXPECT_THAT(phi,
     399             :               IsPhi(MachineRepresentation::kTagged,
     400             :                     IsPhi(MachineRepresentation::kTagged, IsInt32Constant(1),
     401             :                           IsInt32Constant(2), IsMerge(b2t, b2f)),
     402           0 :                     IsInt32Constant(1), IsInt32Constant(2), loop));
     403             : 
     404           6 :   EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
     405           9 :   EXPECT_THAT(exit_marker, IsPhi(MachineRepresentation::kTagged, phi,
     406           0 :                                  IsInt32Constant(0), exit));
     407           7 :   EXPECT_THAT(r, IsReturn(exit_marker, start(), exit));
     408           1 : }
     409             : 
     410             : 
     411       15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoopWithCounter) {
     412           1 :   Node* p0 = Parameter(0);
     413           2 :   Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
     414           1 :   Branch b1 = NewBranch(p0, loop);
     415           1 :   Branch b2 = NewBranch(p0, b1.if_true);
     416           1 :   Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 3),
     417             :                                Int32Constant(0), Int32Constant(1),
     418           1 :                                Int32Constant(2), loop);
     419             : 
     420           3 :   phi->ReplaceInput(
     421           1 :       1, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(1)));
     422           2 :   phi->ReplaceInput(
     423           1 :       2, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(2)));
     424             : 
     425           1 :   loop->ReplaceInput(1, b2.if_true);
     426           1 :   loop->ReplaceInput(2, b2.if_false);
     427             : 
     428           2 :   Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
     429           2 :   Node* exit_marker = graph()->NewNode(common()->LoopExitValue(), phi, exit);
     430           1 :   Node* r = InsertReturn(exit_marker, start(), exit);
     431             : 
     432           1 :   PeeledIteration* peeled = PeelOne();
     433             : 
     434           1 :   Node* b1b = ExpectPeeled(b1.branch, peeled);
     435           1 :   Node* b1t = ExpectPeeled(b1.if_true, peeled);
     436           1 :   Node* b1f = ExpectPeeled(b1.if_false, peeled);
     437             : 
     438           6 :   EXPECT_THAT(b1b, IsBranch(p0, start()));
     439           5 :   EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
     440           5 :   EXPECT_THAT(b1f, IsIfFalse(b1b));
     441             : 
     442           1 :   Node* b2b = ExpectPeeled(b2.branch, peeled);
     443           1 :   Node* b2t = ExpectPeeled(b2.if_true, peeled);
     444           1 :   Node* b2f = ExpectPeeled(b2.if_false, peeled);
     445             : 
     446           6 :   EXPECT_THAT(b2b, IsBranch(p0, b1t));
     447           5 :   EXPECT_THAT(b2t, IsIfTrue(b2b));
     448           5 :   EXPECT_THAT(b2f, IsIfFalse(b2b));
     449             : 
     450             :   Capture<Node*> entry;
     451          13 :   EXPECT_THAT(loop, IsLoop(AllOf(CaptureEq(&entry), IsMerge(b2t, b2f)),
     452           0 :                            b2.if_true, b2.if_false));
     453             : 
     454           2 :   Node* eval = phi->InputAt(0);
     455             : 
     456          16 :   EXPECT_THAT(eval, IsPhi(MachineRepresentation::kTagged,
     457             :                           IsInt32Add(IsInt32Constant(0), IsInt32Constant(1)),
     458             :                           IsInt32Add(IsInt32Constant(0), IsInt32Constant(2)),
     459           0 :                           CaptureEq(&entry)));
     460             : 
     461          15 :   EXPECT_THAT(phi, IsPhi(MachineRepresentation::kTagged, eval,
     462             :                          IsInt32Add(phi, IsInt32Constant(1)),
     463           0 :                          IsInt32Add(phi, IsInt32Constant(2)), loop));
     464             : 
     465           6 :   EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
     466           9 :   EXPECT_THAT(exit_marker, IsPhi(MachineRepresentation::kTagged, phi,
     467           0 :                                  IsInt32Constant(0), exit));
     468           7 :   EXPECT_THAT(r, IsReturn(exit_marker, start(), exit));
     469           1 : }
     470             : 
     471       15419 : TEST_F(LoopPeelingTest, TwoExitLoop) {
     472           1 :   Node* p0 = Parameter(0);
     473           2 :   Node* loop = graph()->NewNode(common()->Loop(2), start(), start());
     474           1 :   Branch b1 = NewBranch(p0, loop);
     475           1 :   Branch b2 = NewBranch(p0, b1.if_true);
     476             : 
     477           1 :   loop->ReplaceInput(1, b2.if_true);
     478             : 
     479           2 :   Node* exit1 = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
     480           2 :   Node* exit2 = graph()->NewNode(common()->LoopExit(), b2.if_false, loop);
     481             : 
     482           2 :   Node* merge = graph()->NewNode(common()->Merge(2), exit1, exit2);
     483           1 :   Node* r = InsertReturn(p0, start(), merge);
     484             : 
     485           1 :   PeeledIteration* peeled = PeelOne();
     486             : 
     487           1 :   Node* b1p = ExpectPeeled(b1.branch, peeled);
     488           1 :   Node* if_true1p = ExpectPeeled(b1.if_true, peeled);
     489           1 :   Node* if_false1p = ExpectPeeled(b1.if_false, peeled);
     490             : 
     491           1 :   Node* b2p = ExpectPeeled(b2.branch, peeled);
     492           1 :   Node* if_true2p = ExpectPeeled(b2.if_true, peeled);
     493           1 :   Node* if_false2p = ExpectPeeled(b2.if_false, peeled);
     494             : 
     495           6 :   EXPECT_THAT(b1p, IsBranch(p0, start()));
     496           5 :   EXPECT_THAT(if_true1p, IsIfTrue(b1p));
     497           5 :   EXPECT_THAT(if_false1p, IsIfFalse(b1p));
     498             : 
     499           6 :   EXPECT_THAT(b2p, IsBranch(p0, if_true1p));
     500           5 :   EXPECT_THAT(if_true2p, IsIfTrue(b2p));
     501           5 :   EXPECT_THAT(if_false2p, IsIfFalse(b2p));
     502             : 
     503           6 :   EXPECT_THAT(exit1, IsMerge(b1.if_false, if_false1p));
     504           6 :   EXPECT_THAT(exit2, IsMerge(b2.if_false, if_false2p));
     505             : 
     506           6 :   EXPECT_THAT(loop, IsLoop(if_true2p, b2.if_true));
     507             : 
     508           6 :   EXPECT_THAT(merge, IsMerge(exit1, exit2));
     509           7 :   EXPECT_THAT(r, IsReturn(p0, start(), merge));
     510           1 : }
     511             : 
     512       15419 : TEST_F(LoopPeelingTest, SimpleLoopWithUnmarkedExit) {
     513           1 :   Node* p0 = Parameter(0);
     514           1 :   Node* loop = graph()->NewNode(common()->Loop(2), start(), start());
     515           1 :   Branch b = NewBranch(p0, loop);
     516           1 :   loop->ReplaceInput(1, b.if_true);
     517             : 
     518           1 :   InsertReturn(p0, start(), b.if_false);
     519             : 
     520             :   {
     521           1 :     LoopTree* loop_tree = GetLoopTree();
     522           1 :     LoopTree::Loop* loop = loop_tree->outer_loops()[0];
     523             :     LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
     524             :                       node_origins());
     525           2 :     EXPECT_FALSE(peeler.CanPeel(loop));
     526             :   }
     527           1 : }
     528             : 
     529             : 
     530             : }  // namespace compiler
     531             : }  // namespace internal
     532        9249 : }  // namespace v8

Generated by: LCOV version 1.10