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/instruction.h"
      6 #include "src/compiler/instruction-codes.h"
      7 #include "src/compiler/jump-threading.h"
      8 #include "test/cctest/cctest.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace compiler {
     13 
     14 class TestCode : public HandleAndZoneScope {
     15  public:
     16   TestCode()
     17       : HandleAndZoneScope(),
     18         blocks_(main_zone()),
     19         sequence_(main_isolate(), main_zone(), &blocks_),
     20         rpo_number_(RpoNumber::FromInt(0)),
     21         current_(NULL) {}
     22 
     23   ZoneVector<InstructionBlock*> blocks_;
     24   InstructionSequence sequence_;
     25   RpoNumber rpo_number_;
     26   InstructionBlock* current_;
     27 
     28   int Jump(int target) {
     29     Start();
     30     InstructionOperand ops[] = {UseRpo(target)};
     31     sequence_.AddInstruction(
     32         Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, ops, 0, NULL));
     33     int pos = static_cast<int>(sequence_.instructions().size() - 1);
     34     End();
     35     return pos;
     36   }
     37   void Fallthru() {
     38     Start();
     39     End();
     40   }
     41   int Branch(int ttarget, int ftarget) {
     42     Start();
     43     InstructionOperand ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
     44     InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
     45                            FlagsConditionField::encode(kEqual);
     46     sequence_.AddInstruction(
     47         Instruction::New(main_zone(), code, 0, NULL, 2, ops, 0, NULL));
     48     int pos = static_cast<int>(sequence_.instructions().size() - 1);
     49     End();
     50     return pos;
     51   }
     52   void Nop() {
     53     Start();
     54     sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
     55   }
     56   void RedundantMoves() {
     57     Start();
     58     sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
     59     int index = static_cast<int>(sequence_.instructions().size()) - 1;
     60     AddGapMove(index, AllocatedOperand(LocationOperand::REGISTER,
     61                                        MachineRepresentation::kWord32, 13),
     62                AllocatedOperand(LocationOperand::REGISTER,
     63                                 MachineRepresentation::kWord32, 13));
     64   }
     65   void NonRedundantMoves() {
     66     Start();
     67     sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
     68     int index = static_cast<int>(sequence_.instructions().size()) - 1;
     69     AddGapMove(index, ConstantOperand(11),
     70                AllocatedOperand(LocationOperand::REGISTER,
     71                                 MachineRepresentation::kWord32, 11));
     72   }
     73   void Other() {
     74     Start();
     75     sequence_.AddInstruction(Instruction::New(main_zone(), 155));
     76   }
     77   void End() {
     78     Start();
     79     sequence_.EndBlock(current_->rpo_number());
     80     current_ = NULL;
     81     rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
     82   }
     83   InstructionOperand UseRpo(int num) {
     84     return sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
     85   }
     86   void Start(bool deferred = false) {
     87     if (current_ == NULL) {
     88       current_ = new (main_zone())
     89           InstructionBlock(main_zone(), rpo_number_, RpoNumber::Invalid(),
     90                            RpoNumber::Invalid(), deferred, false);
     91       blocks_.push_back(current_);
     92       sequence_.StartBlock(rpo_number_);
     93     }
     94   }
     95   void Defer() {
     96     CHECK(current_ == NULL);
     97     Start(true);
     98   }
     99   void AddGapMove(int index, const InstructionOperand& from,
    100                   const InstructionOperand& to) {
    101     sequence_.InstructionAt(index)
    102         ->GetOrCreateParallelMove(Instruction::START, main_zone())
    103         ->AddMove(from, to);
    104   }
    105 };
    106 
    107 
    108 void VerifyForwarding(TestCode& code, int count, int* expected) {
    109   Zone local_zone;
    110   ZoneVector<RpoNumber> result(&local_zone);
    111   JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_);
    112 
    113   CHECK(count == static_cast<int>(result.size()));
    114   for (int i = 0; i < count; i++) {
    115     CHECK(expected[i] == result[i].ToInt());
    116   }
    117 }
    118 
    119 
    120 TEST(FwEmpty1) {
    121   TestCode code;
    122 
    123   // B0
    124   code.Jump(1);
    125   // B1
    126   code.Jump(2);
    127   // B2
    128   code.End();
    129 
    130   static int expected[] = {2, 2, 2};
    131   VerifyForwarding(code, 3, expected);
    132 }
    133 
    134 
    135 TEST(FwEmptyN) {
    136   for (int i = 0; i < 9; i++) {
    137     TestCode code;
    138 
    139     // B0
    140     code.Jump(1);
    141     // B1
    142     for (int j = 0; j < i; j++) code.Nop();
    143     code.Jump(2);
    144     // B2
    145     code.End();
    146 
    147     static int expected[] = {2, 2, 2};
    148     VerifyForwarding(code, 3, expected);
    149   }
    150 }
    151 
    152 
    153 TEST(FwNone1) {
    154   TestCode code;
    155 
    156   // B0
    157   code.End();
    158 
    159   static int expected[] = {0};
    160   VerifyForwarding(code, 1, expected);
    161 }
    162 
    163 
    164 TEST(FwMoves1) {
    165   TestCode code;
    166 
    167   // B0
    168   code.RedundantMoves();
    169   code.End();
    170 
    171   static int expected[] = {0};
    172   VerifyForwarding(code, 1, expected);
    173 }
    174 
    175 
    176 TEST(FwMoves2) {
    177   TestCode code;
    178 
    179   // B0
    180   code.RedundantMoves();
    181   code.Fallthru();
    182   // B1
    183   code.End();
    184 
    185   static int expected[] = {1, 1};
    186   VerifyForwarding(code, 2, expected);
    187 }
    188 
    189 
    190 TEST(FwMoves2b) {
    191   TestCode code;
    192 
    193   // B0
    194   code.NonRedundantMoves();
    195   code.Fallthru();
    196   // B1
    197   code.End();
    198 
    199   static int expected[] = {0, 1};
    200   VerifyForwarding(code, 2, expected);
    201 }
    202 
    203 
    204 TEST(FwOther2) {
    205   TestCode code;
    206 
    207   // B0
    208   code.Other();
    209   code.Fallthru();
    210   // B1
    211   code.End();
    212 
    213   static int expected[] = {0, 1};
    214   VerifyForwarding(code, 2, expected);
    215 }
    216 
    217 
    218 TEST(FwNone2a) {
    219   TestCode code;
    220 
    221   // B0
    222   code.Fallthru();
    223   // B1
    224   code.End();
    225 
    226   static int expected[] = {1, 1};
    227   VerifyForwarding(code, 2, expected);
    228 }
    229 
    230 
    231 TEST(FwNone2b) {
    232   TestCode code;
    233 
    234   // B0
    235   code.Jump(1);
    236   // B1
    237   code.End();
    238 
    239   static int expected[] = {1, 1};
    240   VerifyForwarding(code, 2, expected);
    241 }
    242 
    243 
    244 TEST(FwLoop1) {
    245   TestCode code;
    246 
    247   // B0
    248   code.Jump(0);
    249 
    250   static int expected[] = {0};
    251   VerifyForwarding(code, 1, expected);
    252 }
    253 
    254 
    255 TEST(FwLoop2) {
    256   TestCode code;
    257 
    258   // B0
    259   code.Fallthru();
    260   // B1
    261   code.Jump(0);
    262 
    263   static int expected[] = {0, 0};
    264   VerifyForwarding(code, 2, expected);
    265 }
    266 
    267 
    268 TEST(FwLoop3) {
    269   TestCode code;
    270 
    271   // B0
    272   code.Fallthru();
    273   // B1
    274   code.Fallthru();
    275   // B2
    276   code.Jump(0);
    277 
    278   static int expected[] = {0, 0, 0};
    279   VerifyForwarding(code, 3, expected);
    280 }
    281 
    282 
    283 TEST(FwLoop1b) {
    284   TestCode code;
    285 
    286   // B0
    287   code.Fallthru();
    288   // B1
    289   code.Jump(1);
    290 
    291   static int expected[] = {1, 1};
    292   VerifyForwarding(code, 2, expected);
    293 }
    294 
    295 
    296 TEST(FwLoop2b) {
    297   TestCode code;
    298 
    299   // B0
    300   code.Fallthru();
    301   // B1
    302   code.Fallthru();
    303   // B2
    304   code.Jump(1);
    305 
    306   static int expected[] = {1, 1, 1};
    307   VerifyForwarding(code, 3, expected);
    308 }
    309 
    310 
    311 TEST(FwLoop3b) {
    312   TestCode code;
    313 
    314   // B0
    315   code.Fallthru();
    316   // B1
    317   code.Fallthru();
    318   // B2
    319   code.Fallthru();
    320   // B3
    321   code.Jump(1);
    322 
    323   static int expected[] = {1, 1, 1, 1};
    324   VerifyForwarding(code, 4, expected);
    325 }
    326 
    327 
    328 TEST(FwLoop2_1a) {
    329   TestCode code;
    330 
    331   // B0
    332   code.Fallthru();
    333   // B1
    334   code.Fallthru();
    335   // B2
    336   code.Fallthru();
    337   // B3
    338   code.Jump(1);
    339   // B4
    340   code.Jump(2);
    341 
    342   static int expected[] = {1, 1, 1, 1, 1};
    343   VerifyForwarding(code, 5, expected);
    344 }
    345 
    346 
    347 TEST(FwLoop2_1b) {
    348   TestCode code;
    349 
    350   // B0
    351   code.Fallthru();
    352   // B1
    353   code.Fallthru();
    354   // B2
    355   code.Jump(4);
    356   // B3
    357   code.Jump(1);
    358   // B4
    359   code.Jump(2);
    360 
    361   static int expected[] = {2, 2, 2, 2, 2};
    362   VerifyForwarding(code, 5, expected);
    363 }
    364 
    365 
    366 TEST(FwLoop2_1c) {
    367   TestCode code;
    368 
    369   // B0
    370   code.Fallthru();
    371   // B1
    372   code.Fallthru();
    373   // B2
    374   code.Jump(4);
    375   // B3
    376   code.Jump(2);
    377   // B4
    378   code.Jump(1);
    379 
    380   static int expected[] = {1, 1, 1, 1, 1};
    381   VerifyForwarding(code, 5, expected);
    382 }
    383 
    384 
    385 TEST(FwLoop2_1d) {
    386   TestCode code;
    387 
    388   // B0
    389   code.Fallthru();
    390   // B1
    391   code.Fallthru();
    392   // B2
    393   code.Jump(1);
    394   // B3
    395   code.Jump(1);
    396   // B4
    397   code.Jump(1);
    398 
    399   static int expected[] = {1, 1, 1, 1, 1};
    400   VerifyForwarding(code, 5, expected);
    401 }
    402 
    403 
    404 TEST(FwLoop3_1a) {
    405   TestCode code;
    406 
    407   // B0
    408   code.Fallthru();
    409   // B1
    410   code.Fallthru();
    411   // B2
    412   code.Fallthru();
    413   // B3
    414   code.Jump(2);
    415   // B4
    416   code.Jump(1);
    417   // B5
    418   code.Jump(0);
    419 
    420   static int expected[] = {2, 2, 2, 2, 2, 2};
    421   VerifyForwarding(code, 6, expected);
    422 }
    423 
    424 
    425 TEST(FwDiamonds) {
    426   for (int i = 0; i < 2; i++) {
    427     for (int j = 0; j < 2; j++) {
    428       TestCode code;
    429       // B0
    430       code.Branch(1, 2);
    431       // B1
    432       if (i) code.Other();
    433       code.Jump(3);
    434       // B2
    435       if (j) code.Other();
    436       code.Jump(3);
    437       // B3
    438       code.End();
    439 
    440       int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
    441       VerifyForwarding(code, 4, expected);
    442     }
    443   }
    444 }
    445 
    446 
    447 TEST(FwDiamonds2) {
    448   for (int i = 0; i < 2; i++) {
    449     for (int j = 0; j < 2; j++) {
    450       for (int k = 0; k < 2; k++) {
    451         TestCode code;
    452         // B0
    453         code.Branch(1, 2);
    454         // B1
    455         if (i) code.Other();
    456         code.Jump(3);
    457         // B2
    458         if (j) code.Other();
    459         code.Jump(3);
    460         // B3
    461         if (k) code.NonRedundantMoves();
    462         code.Jump(4);
    463         // B4
    464         code.End();
    465 
    466         int merge = k ? 3 : 4;
    467         int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
    468         VerifyForwarding(code, 5, expected);
    469       }
    470     }
    471   }
    472 }
    473 
    474 
    475 TEST(FwDoubleDiamonds) {
    476   for (int i = 0; i < 2; i++) {
    477     for (int j = 0; j < 2; j++) {
    478       for (int x = 0; x < 2; x++) {
    479         for (int y = 0; y < 2; y++) {
    480           TestCode code;
    481           // B0
    482           code.Branch(1, 2);
    483           // B1
    484           if (i) code.Other();
    485           code.Jump(3);
    486           // B2
    487           if (j) code.Other();
    488           code.Jump(3);
    489           // B3
    490           code.Branch(4, 5);
    491           // B4
    492           if (x) code.Other();
    493           code.Jump(6);
    494           // B5
    495           if (y) code.Other();
    496           code.Jump(6);
    497           // B6
    498           code.End();
    499 
    500           int expected[] = {0,         i ? 1 : 3, j ? 2 : 3, 3,
    501                             x ? 4 : 6, y ? 5 : 6, 6};
    502           VerifyForwarding(code, 7, expected);
    503         }
    504       }
    505     }
    506   }
    507 }
    508 
    509 template <int kSize>
    510 void RunPermutationsRecursive(int outer[kSize], int start,
    511                               void (*run)(int*, int)) {
    512   int permutation[kSize];
    513 
    514   for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
    515 
    516   int count = kSize - start;
    517   if (count == 0) return run(permutation, kSize);
    518   for (int i = start; i < kSize; i++) {
    519     permutation[start] = outer[i];
    520     permutation[i] = outer[start];
    521     RunPermutationsRecursive<kSize>(permutation, start + 1, run);
    522     permutation[i] = outer[i];
    523     permutation[start] = outer[start];
    524   }
    525 }
    526 
    527 
    528 template <int kSize>
    529 void RunAllPermutations(void (*run)(int*, int)) {
    530   int permutation[kSize];
    531   for (int i = 0; i < kSize; i++) permutation[i] = i;
    532   RunPermutationsRecursive<kSize>(permutation, 0, run);
    533 }
    534 
    535 
    536 void PrintPermutation(int* permutation, int size) {
    537   printf("{ ");
    538   for (int i = 0; i < size; i++) {
    539     if (i > 0) printf(", ");
    540     printf("%d", permutation[i]);
    541   }
    542   printf(" }\n");
    543 }
    544 
    545 
    546 int find(int x, int* permutation, int size) {
    547   for (int i = 0; i < size; i++) {
    548     if (permutation[i] == x) return i;
    549   }
    550   return size;
    551 }
    552 
    553 
    554 void RunPermutedChain(int* permutation, int size) {
    555   TestCode code;
    556   int cur = -1;
    557   for (int i = 0; i < size; i++) {
    558     code.Jump(find(cur + 1, permutation, size) + 1);
    559     cur = permutation[i];
    560   }
    561   code.Jump(find(cur + 1, permutation, size) + 1);
    562   code.End();
    563 
    564   int expected[] = {size + 1, size + 1, size + 1, size + 1,
    565                     size + 1, size + 1, size + 1};
    566   VerifyForwarding(code, size + 2, expected);
    567 }
    568 
    569 
    570 TEST(FwPermuted_chain) {
    571   RunAllPermutations<3>(RunPermutedChain);
    572   RunAllPermutations<4>(RunPermutedChain);
    573   RunAllPermutations<5>(RunPermutedChain);
    574 }
    575 
    576 
    577 void RunPermutedDiamond(int* permutation, int size) {
    578   TestCode code;
    579   int br = 1 + find(0, permutation, size);
    580   code.Jump(br);
    581   for (int i = 0; i < size; i++) {
    582     switch (permutation[i]) {
    583       case 0:
    584         code.Branch(1 + find(1, permutation, size),
    585                     1 + find(2, permutation, size));
    586         break;
    587       case 1:
    588         code.Jump(1 + find(3, permutation, size));
    589         break;
    590       case 2:
    591         code.Jump(1 + find(3, permutation, size));
    592         break;
    593       case 3:
    594         code.Jump(5);
    595         break;
    596     }
    597   }
    598   code.End();
    599 
    600   int expected[] = {br, 5, 5, 5, 5, 5};
    601   expected[br] = br;
    602   VerifyForwarding(code, 6, expected);
    603 }
    604 
    605 
    606 TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
    607 
    608 
    609 void ApplyForwarding(TestCode& code, int size, int* forward) {
    610   ZoneVector<RpoNumber> vector(code.main_zone());
    611   for (int i = 0; i < size; i++) {
    612     vector.push_back(RpoNumber::FromInt(forward[i]));
    613   }
    614   JumpThreading::ApplyForwarding(vector, &code.sequence_);
    615 }
    616 
    617 
    618 void CheckJump(TestCode& code, int pos, int target) {
    619   Instruction* instr = code.sequence_.InstructionAt(pos);
    620   CHECK_EQ(kArchJmp, instr->arch_opcode());
    621   CHECK_EQ(1, static_cast<int>(instr->InputCount()));
    622   CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
    623   CHECK_EQ(0, static_cast<int>(instr->TempCount()));
    624   CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
    625 }
    626 
    627 
    628 void CheckNop(TestCode& code, int pos) {
    629   Instruction* instr = code.sequence_.InstructionAt(pos);
    630   CHECK_EQ(kArchNop, instr->arch_opcode());
    631   CHECK_EQ(0, static_cast<int>(instr->InputCount()));
    632   CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
    633   CHECK_EQ(0, static_cast<int>(instr->TempCount()));
    634 }
    635 
    636 
    637 void CheckBranch(TestCode& code, int pos, int t1, int t2) {
    638   Instruction* instr = code.sequence_.InstructionAt(pos);
    639   CHECK_EQ(2, static_cast<int>(instr->InputCount()));
    640   CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
    641   CHECK_EQ(0, static_cast<int>(instr->TempCount()));
    642   CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
    643   CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
    644 }
    645 
    646 
    647 void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
    648   int i = 0;
    649   for (auto const block : code.sequence_.instruction_blocks()) {
    650     CHECK_EQ(expected[i++], block->ao_number().ToInt());
    651   }
    652 }
    653 
    654 
    655 TEST(Rewire1) {
    656   TestCode code;
    657 
    658   // B0
    659   int j1 = code.Jump(1);
    660   // B1
    661   int j2 = code.Jump(2);
    662   // B2
    663   code.End();
    664 
    665   static int forward[] = {2, 2, 2};
    666   ApplyForwarding(code, 3, forward);
    667   CheckJump(code, j1, 2);
    668   CheckNop(code, j2);
    669 
    670   static int assembly[] = {0, 1, 1};
    671   CheckAssemblyOrder(code, 3, assembly);
    672 }
    673 
    674 
    675 TEST(Rewire1_deferred) {
    676   TestCode code;
    677 
    678   // B0
    679   int j1 = code.Jump(1);
    680   // B1
    681   int j2 = code.Jump(2);
    682   // B2
    683   code.Defer();
    684   int j3 = code.Jump(3);
    685   // B3
    686   code.End();
    687 
    688   static int forward[] = {3, 3, 3, 3};
    689   ApplyForwarding(code, 4, forward);
    690   CheckJump(code, j1, 3);
    691   CheckNop(code, j2);
    692   CheckNop(code, j3);
    693 
    694   static int assembly[] = {0, 1, 2, 1};
    695   CheckAssemblyOrder(code, 4, assembly);
    696 }
    697 
    698 
    699 TEST(Rewire2_deferred) {
    700   TestCode code;
    701 
    702   // B0
    703   code.Other();
    704   int j1 = code.Jump(1);
    705   // B1
    706   code.Defer();
    707   code.Fallthru();
    708   // B2
    709   code.Defer();
    710   int j2 = code.Jump(3);
    711   // B3
    712   code.End();
    713 
    714   static int forward[] = {0, 1, 2, 3};
    715   ApplyForwarding(code, 4, forward);
    716   CheckJump(code, j1, 1);
    717   CheckJump(code, j2, 3);
    718 
    719   static int assembly[] = {0, 2, 3, 1};
    720   CheckAssemblyOrder(code, 4, assembly);
    721 }
    722 
    723 
    724 TEST(Rewire_diamond) {
    725   for (int i = 0; i < 2; i++) {
    726     for (int j = 0; j < 2; j++) {
    727       TestCode code;
    728       // B0
    729       int j1 = code.Jump(1);
    730       // B1
    731       int b1 = code.Branch(2, 3);
    732       // B2
    733       int j2 = code.Jump(4);
    734       // B3
    735       int j3 = code.Jump(4);
    736       // B5
    737       code.End();
    738 
    739       int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
    740       ApplyForwarding(code, 5, forward);
    741       CheckJump(code, j1, 1);
    742       CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
    743       if (i) {
    744         CheckNop(code, j2);
    745       } else {
    746         CheckJump(code, j2, 4);
    747       }
    748       if (j) {
    749         CheckNop(code, j3);
    750       } else {
    751         CheckJump(code, j3, 4);
    752       }
    753 
    754       int assembly[] = {0, 1, 2, 3, 4};
    755       if (i) {
    756         for (int k = 3; k < 5; k++) assembly[k]--;
    757       }
    758       if (j) {
    759         for (int k = 4; k < 5; k++) assembly[k]--;
    760       }
    761       CheckAssemblyOrder(code, 5, assembly);
    762     }
    763   }
    764 }
    765 
    766 }  // namespace compiler
    767 }  // namespace internal
    768 }  // namespace v8
    769