LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-instruction.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 146 146 100.0 %
Date: 2019-04-17 Functions: 14 14 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/backend/code-generator.h"
       6             : #include "src/compiler/backend/instruction.h"
       7             : #include "src/compiler/common-operator.h"
       8             : #include "src/compiler/graph.h"
       9             : #include "src/compiler/linkage.h"
      10             : #include "src/compiler/machine-operator.h"
      11             : #include "src/compiler/node.h"
      12             : #include "src/compiler/operator.h"
      13             : #include "src/compiler/schedule.h"
      14             : #include "src/compiler/scheduler.h"
      15             : #include "src/objects-inl.h"
      16             : #include "test/cctest/cctest.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : namespace compiler {
      21             : 
      22             : typedef v8::internal::compiler::Instruction TestInstr;
      23             : typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
      24             : 
      25             : // A testing helper for the register code abstraction.
      26          25 : class InstructionTester : public HandleAndZoneScope {
      27             :  public:  // We're all friends here.
      28          25 :   InstructionTester()
      29             :       : graph(zone()),
      30             :         schedule(zone()),
      31             :         common(zone()),
      32             :         machine(zone()),
      33         125 :         code(nullptr) {}
      34             : 
      35             :   Graph graph;
      36             :   Schedule schedule;
      37             :   CommonOperatorBuilder common;
      38             :   MachineOperatorBuilder machine;
      39             :   TestInstrSeq* code;
      40             : 
      41             :   Zone* zone() { return main_zone(); }
      42             : 
      43          25 :   void allocCode() {
      44          25 :     if (schedule.rpo_order()->size() == 0) {
      45             :       // Compute the RPO order.
      46          50 :       Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
      47          25 :       CHECK_NE(0u, schedule.rpo_order()->size());
      48             :     }
      49             :     InstructionBlocks* instruction_blocks =
      50          50 :         TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
      51             :     code = new (main_zone())
      52          25 :         TestInstrSeq(main_isolate(), main_zone(), instruction_blocks);
      53          25 :   }
      54             : 
      55          65 :   Node* Int32Constant(int32_t val) {
      56          65 :     Node* node = graph.NewNode(common.Int32Constant(val));
      57          65 :     schedule.AddNode(schedule.start(), node);
      58          65 :     return node;
      59             :   }
      60             : 
      61             :   Node* Float64Constant(double val) {
      62             :     Node* node = graph.NewNode(common.Float64Constant(val));
      63             :     schedule.AddNode(schedule.start(), node);
      64             :     return node;
      65             :   }
      66             : 
      67             :   Node* Parameter(int32_t which) {
      68             :     Node* node = graph.NewNode(common.Parameter(which));
      69             :     schedule.AddNode(schedule.start(), node);
      70             :     return node;
      71             :   }
      72             : 
      73             :   Node* NewNode(BasicBlock* block) {
      74             :     Node* node = graph.NewNode(common.Int32Constant(111));
      75             :     schedule.AddNode(block, node);
      76             :     return node;
      77             :   }
      78             : 
      79          45 :   int NewInstr() {
      80             :     InstructionCode opcode = static_cast<InstructionCode>(110);
      81             :     TestInstr* instr = TestInstr::New(zone(), opcode);
      82          45 :     return code->AddInstruction(instr);
      83             :   }
      84             : 
      85           5 :   int NewNop() {
      86             :     TestInstr* instr = TestInstr::New(zone(), kArchNop);
      87           5 :     return code->AddInstruction(instr);
      88             :   }
      89             : 
      90             :   UnallocatedOperand Unallocated(int vreg) {
      91             :     return UnallocatedOperand(UnallocatedOperand::REGISTER_OR_SLOT, vreg);
      92             :   }
      93             : 
      94             :   RpoNumber RpoFor(BasicBlock* block) {
      95             :     return RpoNumber::FromInt(block->rpo_number());
      96             :   }
      97             : 
      98             :   InstructionBlock* BlockAt(BasicBlock* block) {
      99          70 :     return code->InstructionBlockAt(RpoFor(block));
     100             :   }
     101          85 :   BasicBlock* GetBasicBlock(int instruction_index) {
     102             :     const InstructionBlock* block =
     103          85 :         code->GetInstructionBlock(instruction_index);
     104          85 :     return schedule.rpo_order()->at(block->rpo_number().ToSize());
     105             :   }
     106             :   int first_instruction_index(BasicBlock* block) {
     107             :     return BlockAt(block)->first_instruction_index();
     108             :   }
     109             :   int last_instruction_index(BasicBlock* block) {
     110             :     return BlockAt(block)->last_instruction_index();
     111             :   }
     112             : };
     113             : 
     114             : 
     115       26644 : TEST(InstructionBasic) {
     116           5 :   InstructionTester R;
     117             : 
     118         105 :   for (int i = 0; i < 10; i++) {
     119          50 :     R.Int32Constant(i);  // Add some nodes to the graph.
     120             :   }
     121             : 
     122             :   BasicBlock* last = R.schedule.start();
     123          55 :   for (int i = 0; i < 5; i++) {
     124          25 :     BasicBlock* block = R.schedule.NewBasicBlock();
     125          25 :     R.schedule.AddGoto(last, block);
     126             :     last = block;
     127             :   }
     128             : 
     129           5 :   R.allocCode();
     130             : 
     131             :   BasicBlockVector* blocks = R.schedule.rpo_order();
     132          10 :   CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
     133             : 
     134          35 :   for (auto block : *blocks) {
     135          30 :     CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
     136          30 :     CHECK(!block->loop_end());
     137             :   }
     138           5 : }
     139             : 
     140             : 
     141       26644 : TEST(InstructionGetBasicBlock) {
     142           5 :   InstructionTester R;
     143             : 
     144             :   BasicBlock* b0 = R.schedule.start();
     145           5 :   BasicBlock* b1 = R.schedule.NewBasicBlock();
     146           5 :   BasicBlock* b2 = R.schedule.NewBasicBlock();
     147             :   BasicBlock* b3 = R.schedule.end();
     148             : 
     149           5 :   R.schedule.AddGoto(b0, b1);
     150           5 :   R.schedule.AddGoto(b1, b2);
     151           5 :   R.schedule.AddGoto(b2, b3);
     152             : 
     153           5 :   R.allocCode();
     154             : 
     155           5 :   R.code->StartBlock(R.RpoFor(b0));
     156           5 :   int i0 = R.NewInstr();
     157           5 :   int i1 = R.NewInstr();
     158           5 :   R.code->EndBlock(R.RpoFor(b0));
     159           5 :   R.code->StartBlock(R.RpoFor(b1));
     160           5 :   int i2 = R.NewInstr();
     161           5 :   int i3 = R.NewInstr();
     162           5 :   int i4 = R.NewInstr();
     163           5 :   int i5 = R.NewInstr();
     164           5 :   R.code->EndBlock(R.RpoFor(b1));
     165           5 :   R.code->StartBlock(R.RpoFor(b2));
     166           5 :   int i6 = R.NewInstr();
     167           5 :   int i7 = R.NewInstr();
     168           5 :   int i8 = R.NewInstr();
     169           5 :   R.code->EndBlock(R.RpoFor(b2));
     170           5 :   R.code->StartBlock(R.RpoFor(b3));
     171           5 :   R.NewNop();
     172           5 :   R.code->EndBlock(R.RpoFor(b3));
     173             : 
     174           5 :   CHECK_EQ(b0, R.GetBasicBlock(i0));
     175           5 :   CHECK_EQ(b0, R.GetBasicBlock(i1));
     176             : 
     177           5 :   CHECK_EQ(b1, R.GetBasicBlock(i2));
     178           5 :   CHECK_EQ(b1, R.GetBasicBlock(i3));
     179           5 :   CHECK_EQ(b1, R.GetBasicBlock(i4));
     180           5 :   CHECK_EQ(b1, R.GetBasicBlock(i5));
     181             : 
     182           5 :   CHECK_EQ(b2, R.GetBasicBlock(i6));
     183           5 :   CHECK_EQ(b2, R.GetBasicBlock(i7));
     184           5 :   CHECK_EQ(b2, R.GetBasicBlock(i8));
     185             : 
     186           5 :   CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
     187           5 :   CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
     188             : 
     189           5 :   CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
     190           5 :   CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
     191             : 
     192           5 :   CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
     193           5 :   CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
     194             : 
     195           5 :   CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
     196           5 :   CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
     197           5 : }
     198             : 
     199             : 
     200       26644 : TEST(InstructionIsGapAt) {
     201           5 :   InstructionTester R;
     202             : 
     203             :   BasicBlock* b0 = R.schedule.start();
     204           5 :   R.schedule.AddReturn(b0, R.Int32Constant(1));
     205             : 
     206           5 :   R.allocCode();
     207             :   TestInstr* i0 = TestInstr::New(R.zone(), 100);
     208             :   TestInstr* g = TestInstr::New(R.zone(), 103);
     209           5 :   R.code->StartBlock(R.RpoFor(b0));
     210           5 :   R.code->AddInstruction(i0);
     211           5 :   R.code->AddInstruction(g);
     212           5 :   R.code->EndBlock(R.RpoFor(b0));
     213             : 
     214          10 :   CHECK_EQ(2, R.code->instructions().size());
     215           5 : }
     216             : 
     217             : 
     218       26644 : TEST(InstructionIsGapAt2) {
     219           5 :   InstructionTester R;
     220             : 
     221             :   BasicBlock* b0 = R.schedule.start();
     222             :   BasicBlock* b1 = R.schedule.end();
     223           5 :   R.schedule.AddGoto(b0, b1);
     224           5 :   R.schedule.AddReturn(b1, R.Int32Constant(1));
     225             : 
     226           5 :   R.allocCode();
     227             :   TestInstr* i0 = TestInstr::New(R.zone(), 100);
     228             :   TestInstr* g = TestInstr::New(R.zone(), 103);
     229           5 :   R.code->StartBlock(R.RpoFor(b0));
     230           5 :   R.code->AddInstruction(i0);
     231           5 :   R.code->AddInstruction(g);
     232           5 :   R.code->EndBlock(R.RpoFor(b0));
     233             : 
     234             :   TestInstr* i1 = TestInstr::New(R.zone(), 102);
     235             :   TestInstr* g1 = TestInstr::New(R.zone(), 104);
     236           5 :   R.code->StartBlock(R.RpoFor(b1));
     237           5 :   R.code->AddInstruction(i1);
     238           5 :   R.code->AddInstruction(g1);
     239           5 :   R.code->EndBlock(R.RpoFor(b1));
     240             : 
     241          10 :   CHECK_EQ(4, R.code->instructions().size());
     242           5 : }
     243             : 
     244             : 
     245       26644 : TEST(InstructionAddGapMove) {
     246           5 :   InstructionTester R;
     247             : 
     248             :   BasicBlock* b0 = R.schedule.start();
     249           5 :   R.schedule.AddReturn(b0, R.Int32Constant(1));
     250             : 
     251           5 :   R.allocCode();
     252             :   TestInstr* i0 = TestInstr::New(R.zone(), 100);
     253             :   TestInstr* g = TestInstr::New(R.zone(), 103);
     254           5 :   R.code->StartBlock(R.RpoFor(b0));
     255           5 :   R.code->AddInstruction(i0);
     256           5 :   R.code->AddInstruction(g);
     257           5 :   R.code->EndBlock(R.RpoFor(b0));
     258             : 
     259          10 :   CHECK_EQ(2, R.code->instructions().size());
     260             : 
     261             :   int index = 0;
     262          15 :   for (auto instr : R.code->instructions()) {
     263          20 :     UnallocatedOperand op1 = R.Unallocated(index++);
     264          20 :     UnallocatedOperand op2 = R.Unallocated(index++);
     265             :     instr->GetOrCreateParallelMove(TestInstr::START, R.zone())
     266             :         ->AddMove(op1, op2);
     267             :     ParallelMove* move = instr->GetParallelMove(TestInstr::START);
     268          10 :     CHECK(move);
     269          10 :     CHECK_EQ(1u, move->size());
     270          10 :     MoveOperands* cur = move->at(0);
     271          10 :     CHECK(op1.Equals(cur->source()));
     272          10 :     CHECK(op2.Equals(cur->destination()));
     273             :   }
     274           5 : }
     275             : 
     276             : 
     277       26644 : TEST(InstructionOperands) {
     278          10 :   v8::internal::AccountingAllocator allocator;
     279          10 :   Zone zone(&allocator, ZONE_NAME);
     280             : 
     281             :   {
     282             :     TestInstr* i = TestInstr::New(&zone, 101);
     283           5 :     CHECK_EQ(0, static_cast<int>(i->OutputCount()));
     284           5 :     CHECK_EQ(0, static_cast<int>(i->InputCount()));
     285           5 :     CHECK_EQ(0, static_cast<int>(i->TempCount()));
     286             :   }
     287             : 
     288             :   int vreg = 15;
     289             :   InstructionOperand outputs[] = {
     290             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     291             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     292             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     293           5 :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
     294             : 
     295             :   InstructionOperand inputs[] = {
     296             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     297             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     298             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     299           5 :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
     300             : 
     301             :   InstructionOperand temps[] = {
     302             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     303             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     304             :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
     305           5 :       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
     306             : 
     307          45 :   for (size_t i = 0; i < arraysize(outputs); i++) {
     308         180 :     for (size_t j = 0; j < arraysize(inputs); j++) {
     309         720 :       for (size_t k = 0; k < arraysize(temps); k++) {
     310             :         TestInstr* m =
     311         320 :             TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
     312         320 :         CHECK(i == m->OutputCount());
     313         320 :         CHECK(j == m->InputCount());
     314         320 :         CHECK(k == m->TempCount());
     315             : 
     316        1280 :         for (size_t z = 0; z < i; z++) {
     317         480 :           CHECK(outputs[z].Equals(*m->OutputAt(z)));
     318             :         }
     319             : 
     320        1280 :         for (size_t z = 0; z < j; z++) {
     321         480 :           CHECK(inputs[z].Equals(*m->InputAt(z)));
     322             :         }
     323             : 
     324        1280 :         for (size_t z = 0; z < k; z++) {
     325         480 :           CHECK(temps[z].Equals(*m->TempAt(z)));
     326             :         }
     327             :       }
     328             :     }
     329             :   }
     330           5 : }
     331             : 
     332             : }  // namespace compiler
     333             : }  // namespace internal
     334       79917 : }  // namespace v8

Generated by: LCOV version 1.10