LCOV - code coverage report
Current view: top level - test/unittests/compiler - effect-control-linearizer-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 143 146 97.9 %
Date: 2017-10-20 Functions: 21 23 91.3 %

          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/effect-control-linearizer.h"
       6             : #include "src/compiler/access-builder.h"
       7             : #include "src/compiler/compiler-source-position-table.h"
       8             : #include "src/compiler/js-graph.h"
       9             : #include "src/compiler/linkage.h"
      10             : #include "src/compiler/node-properties.h"
      11             : #include "src/compiler/schedule.h"
      12             : #include "src/compiler/simplified-operator.h"
      13             : #include "test/unittests/compiler/graph-unittest.h"
      14             : #include "test/unittests/compiler/node-test-utils.h"
      15             : #include "test/unittests/test-utils.h"
      16             : #include "testing/gmock-support.h"
      17             : #include "testing/gmock/include/gmock/gmock.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : namespace compiler {
      22             : 
      23             : using testing::Capture;
      24             : 
      25           4 : class EffectControlLinearizerTest : public GraphTest {
      26             :  public:
      27           4 :   EffectControlLinearizerTest()
      28             :       : GraphTest(3),
      29             :         machine_(zone()),
      30             :         javascript_(zone()),
      31             :         simplified_(zone()),
      32             :         jsgraph_(isolate(), graph(), common(), &javascript_, &simplified_,
      33           8 :                  &machine_) {
      34           8 :     source_positions_ = new (zone()) SourcePositionTable(graph());
      35           4 :   }
      36             : 
      37             :   JSGraph* jsgraph() { return &jsgraph_; }
      38             :   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
      39             :   SourcePositionTable* source_positions() { return source_positions_; }
      40             : 
      41             :  private:
      42             :   MachineOperatorBuilder machine_;
      43             :   JSOperatorBuilder javascript_;
      44             :   SimplifiedOperatorBuilder simplified_;
      45             :   JSGraph jsgraph_;
      46             :   SourcePositionTable* source_positions_;
      47             : };
      48             : 
      49             : namespace {
      50             : 
      51          12 : BasicBlock* AddBlockToSchedule(Schedule* schedule) {
      52          12 :   BasicBlock* block = schedule->NewBasicBlock();
      53          24 :   block->set_rpo_number(static_cast<int32_t>(schedule->rpo_order()->size()));
      54          12 :   schedule->rpo_order()->push_back(block);
      55          12 :   return block;
      56             : }
      57             : 
      58             : }  // namespace
      59             : 
      60       13160 : TEST_F(EffectControlLinearizerTest, SimpleLoad) {
      61           1 :   Schedule schedule(zone());
      62             : 
      63             :   // Create the graph.
      64           1 :   Node* heap_number = NumberConstant(0.5);
      65             :   Node* load = graph()->NewNode(
      66             :       simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number,
      67           3 :       graph()->start(), graph()->start());
      68           1 :   Node* zero = graph()->NewNode(common()->Int32Constant(0));
      69             :   Node* ret = graph()->NewNode(common()->Return(), zero, load, graph()->start(),
      70           2 :                                graph()->start());
      71             : 
      72             :   // Build the basic block structure.
      73           1 :   BasicBlock* start = schedule.start();
      74           1 :   schedule.rpo_order()->push_back(start);
      75           1 :   start->set_rpo_number(0);
      76             : 
      77             :   // Populate the basic blocks with nodes.
      78           1 :   schedule.AddNode(start, graph()->start());
      79           1 :   schedule.AddNode(start, heap_number);
      80           1 :   schedule.AddNode(start, load);
      81           1 :   schedule.AddReturn(start, ret);
      82             : 
      83             :   // Run the state effect introducer.
      84             :   EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
      85           1 :                                      source_positions());
      86           1 :   introducer.Run();
      87             : 
      88           7 :   EXPECT_THAT(load,
      89             :               IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number,
      90           0 :                           graph()->start(), graph()->start()));
      91             :   // The return should have reconnected effect edge to the load.
      92           6 :   EXPECT_THAT(ret, IsReturn(load, load, graph()->start()));
      93           1 : }
      94             : 
      95       13160 : TEST_F(EffectControlLinearizerTest, DiamondLoad) {
      96           1 :   Schedule schedule(zone());
      97             : 
      98             :   // Create the graph.
      99             :   Node* branch =
     100           1 :       graph()->NewNode(common()->Branch(), Int32Constant(0), graph()->start());
     101             : 
     102           1 :   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     103           1 :   Node* heap_number = NumberConstant(0.5);
     104             :   Node* vtrue = graph()->NewNode(
     105             :       simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number,
     106           3 :       graph()->start(), if_true);
     107             : 
     108           1 :   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     109           1 :   Node* vfalse = Float64Constant(2);
     110             : 
     111           1 :   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
     112             :   Node* phi = graph()->NewNode(
     113           1 :       common()->Phi(MachineRepresentation::kFloat64, 2), vtrue, vfalse, merge);
     114             : 
     115           1 :   Node* zero = graph()->NewNode(common()->Int32Constant(0));
     116             :   Node* ret =
     117           2 :       graph()->NewNode(common()->Return(), zero, phi, graph()->start(), merge);
     118             : 
     119             :   // Build the basic block structure.
     120           1 :   BasicBlock* start = schedule.start();
     121           1 :   schedule.rpo_order()->push_back(start);
     122           1 :   start->set_rpo_number(0);
     123             : 
     124           1 :   BasicBlock* tblock = AddBlockToSchedule(&schedule);
     125           1 :   BasicBlock* fblock = AddBlockToSchedule(&schedule);
     126           1 :   BasicBlock* mblock = AddBlockToSchedule(&schedule);
     127             : 
     128             :   // Populate the basic blocks with nodes.
     129           1 :   schedule.AddNode(start, graph()->start());
     130           1 :   schedule.AddBranch(start, branch, tblock, fblock);
     131             : 
     132           1 :   schedule.AddNode(tblock, if_true);
     133           1 :   schedule.AddNode(tblock, heap_number);
     134           1 :   schedule.AddNode(tblock, vtrue);
     135           1 :   schedule.AddGoto(tblock, mblock);
     136             : 
     137           1 :   schedule.AddNode(fblock, if_false);
     138           1 :   schedule.AddNode(fblock, vfalse);
     139           1 :   schedule.AddGoto(fblock, mblock);
     140             : 
     141           1 :   schedule.AddNode(mblock, merge);
     142           1 :   schedule.AddNode(mblock, phi);
     143           1 :   schedule.AddReturn(mblock, ret);
     144             : 
     145             :   // Run the state effect introducer.
     146             :   EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
     147           1 :                                      source_positions());
     148           1 :   introducer.Run();
     149             : 
     150             :   // The effect input to the return should be an effect phi with the
     151             :   // newly introduced effectful change operators.
     152          10 :   ASSERT_THAT(
     153             :       ret, IsReturn(phi, IsEffectPhi(vtrue, graph()->start(), merge), merge));
     154             : }
     155             : 
     156       13160 : TEST_F(EffectControlLinearizerTest, LoopLoad) {
     157           1 :   Schedule schedule(zone());
     158             : 
     159             :   // Create the graph.
     160           1 :   Node* loop = graph()->NewNode(common()->Loop(1), graph()->start());
     161             :   Node* effect_phi =
     162           1 :       graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop);
     163             : 
     164           1 :   Node* cond = Int32Constant(0);
     165           1 :   Node* branch = graph()->NewNode(common()->Branch(), cond, loop);
     166             : 
     167           1 :   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     168             : 
     169           1 :   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     170             : 
     171           1 :   loop->AppendInput(zone(), if_false);
     172           1 :   NodeProperties::ChangeOp(loop, common()->Loop(2));
     173             : 
     174           1 :   effect_phi->InsertInput(zone(), 1, effect_phi);
     175           1 :   NodeProperties::ChangeOp(effect_phi, common()->EffectPhi(2));
     176             : 
     177           1 :   Node* heap_number = NumberConstant(0.5);
     178             :   Node* load = graph()->NewNode(
     179             :       simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number,
     180           3 :       graph()->start(), loop);
     181             : 
     182           1 :   Node* zero = graph()->NewNode(common()->Int32Constant(0));
     183             :   Node* ret =
     184           2 :       graph()->NewNode(common()->Return(), zero, load, effect_phi, if_true);
     185             : 
     186             :   // Build the basic block structure.
     187           1 :   BasicBlock* start = schedule.start();
     188           1 :   schedule.rpo_order()->push_back(start);
     189           1 :   start->set_rpo_number(0);
     190             : 
     191           1 :   BasicBlock* lblock = AddBlockToSchedule(&schedule);
     192           1 :   BasicBlock* fblock = AddBlockToSchedule(&schedule);
     193           1 :   BasicBlock* rblock = AddBlockToSchedule(&schedule);
     194             : 
     195             :   // Populate the basic blocks with nodes.
     196           1 :   schedule.AddNode(start, graph()->start());
     197           1 :   schedule.AddGoto(start, lblock);
     198             : 
     199           1 :   schedule.AddNode(lblock, loop);
     200           1 :   schedule.AddNode(lblock, effect_phi);
     201           1 :   schedule.AddNode(lblock, heap_number);
     202           1 :   schedule.AddNode(lblock, load);
     203           1 :   schedule.AddNode(lblock, cond);
     204           1 :   schedule.AddBranch(lblock, branch, rblock, fblock);
     205             : 
     206           1 :   schedule.AddNode(fblock, if_false);
     207           1 :   schedule.AddGoto(fblock, lblock);
     208             : 
     209           1 :   schedule.AddNode(rblock, if_true);
     210           1 :   schedule.AddReturn(rblock, ret);
     211             : 
     212             :   // Run the state effect introducer.
     213             :   EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
     214           1 :                                      source_positions());
     215           1 :   introducer.Run();
     216             : 
     217           7 :   ASSERT_THAT(ret, IsReturn(load, load, if_true));
     218           7 :   EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(),
     219           0 :                                 heap_number, effect_phi, loop));
     220             : }
     221             : 
     222       13160 : TEST_F(EffectControlLinearizerTest, CloneBranch) {
     223           1 :   Schedule schedule(zone());
     224             : 
     225           1 :   Node* cond0 = Parameter(0);
     226           1 :   Node* cond1 = Parameter(1);
     227           1 :   Node* cond2 = Parameter(2);
     228           1 :   Node* branch0 = graph()->NewNode(common()->Branch(), cond0, start());
     229           1 :   Node* control1 = graph()->NewNode(common()->IfTrue(), branch0);
     230           1 :   Node* control2 = graph()->NewNode(common()->IfFalse(), branch0);
     231           1 :   Node* merge0 = graph()->NewNode(common()->Merge(2), control1, control2);
     232             :   Node* phi0 = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2),
     233           1 :                                 cond1, cond2, merge0);
     234           1 :   Node* branch = graph()->NewNode(common()->Branch(), phi0, merge0);
     235           1 :   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     236           1 :   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     237           1 :   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
     238           1 :   graph()->SetEnd(graph()->NewNode(common()->End(1), merge));
     239             : 
     240           1 :   BasicBlock* start = schedule.start();
     241           1 :   schedule.rpo_order()->push_back(start);
     242           1 :   start->set_rpo_number(0);
     243             : 
     244           1 :   BasicBlock* f1block = AddBlockToSchedule(&schedule);
     245           1 :   BasicBlock* t1block = AddBlockToSchedule(&schedule);
     246           1 :   BasicBlock* bblock = AddBlockToSchedule(&schedule);
     247             : 
     248           1 :   BasicBlock* f2block = AddBlockToSchedule(&schedule);
     249           1 :   BasicBlock* t2block = AddBlockToSchedule(&schedule);
     250           1 :   BasicBlock* mblock = AddBlockToSchedule(&schedule);
     251             : 
     252             :   // Populate the basic blocks with nodes.
     253           1 :   schedule.AddNode(start, graph()->start());
     254             : 
     255           1 :   schedule.AddBranch(start, branch0, t1block, f1block);
     256             : 
     257           1 :   schedule.AddNode(t1block, control1);
     258           1 :   schedule.AddGoto(t1block, bblock);
     259             : 
     260           1 :   schedule.AddNode(f1block, control2);
     261           1 :   schedule.AddGoto(f1block, bblock);
     262             : 
     263           1 :   schedule.AddNode(bblock, merge0);
     264           1 :   schedule.AddNode(bblock, phi0);
     265           1 :   schedule.AddBranch(bblock, branch, t2block, f2block);
     266             : 
     267           1 :   schedule.AddNode(t2block, if_true);
     268           1 :   schedule.AddGoto(t2block, mblock);
     269             : 
     270           1 :   schedule.AddNode(f2block, if_false);
     271           1 :   schedule.AddGoto(f2block, mblock);
     272             : 
     273           1 :   schedule.AddNode(mblock, merge);
     274           1 :   schedule.AddNode(mblock, graph()->end());
     275             : 
     276             :   EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
     277           1 :                                      source_positions());
     278           1 :   introducer.Run();
     279             : 
     280             :   Capture<Node *> branch1_capture, branch2_capture;
     281          26 :   EXPECT_THAT(
     282             :       end(),
     283             :       IsEnd(IsMerge(IsMerge(IsIfTrue(CaptureEq(&branch1_capture)),
     284             :                             IsIfTrue(CaptureEq(&branch2_capture))),
     285             :                     IsMerge(IsIfFalse(AllOf(CaptureEq(&branch1_capture),
     286             :                                             IsBranch(cond1, control1))),
     287             :                             IsIfFalse(AllOf(CaptureEq(&branch2_capture),
     288           0 :                                             IsBranch(cond2, control2)))))));
     289           1 : }
     290             : 
     291             : }  // namespace compiler
     292             : }  // namespace internal
     293        7893 : }  // namespace v8

Generated by: LCOV version 1.10