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