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