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 #ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
      6 #define V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
      7 
      8 #include "src/compiler/instruction.h"
      9 #include "test/unittests/test-utils.h"
     10 #include "testing/gmock/include/gmock/gmock.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 class InstructionSequenceTest : public TestWithIsolateAndZone {
     17  public:
     18   static const int kDefaultNRegs = 8;
     19   static const int kNoValue = kMinInt;
     20 
     21   typedef RpoNumber Rpo;
     22 
     23   struct VReg {
     24     VReg() : value_(kNoValue) {}
     25     VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {}  // NOLINT
     26     explicit VReg(int value) : value_(value) {}
     27     int value_;
     28   };
     29 
     30   typedef std::pair<VReg, VReg> VRegPair;
     31 
     32   enum TestOperandType {
     33     kInvalid,
     34     kSameAsFirst,
     35     kRegister,
     36     kFixedRegister,
     37     kSlot,
     38     kFixedSlot,
     39     kExplicit,
     40     kImmediate,
     41     kNone,
     42     kConstant,
     43     kUnique,
     44     kUniqueRegister
     45   };
     46 
     47   struct TestOperand {
     48     TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
     49     TestOperand(TestOperandType type, int imm)
     50         : type_(type), vreg_(), value_(imm) {}
     51     TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
     52         : type_(type), vreg_(vreg), value_(value) {}
     53 
     54     TestOperandType type_;
     55     VReg vreg_;
     56     int value_;
     57   };
     58 
     59   static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
     60 
     61   static TestOperand ExplicitReg(int index) {
     62     TestOperandType type = kExplicit;
     63     return TestOperand(type, VReg(), index);
     64   }
     65 
     66   static TestOperand Reg(VReg vreg, int index = kNoValue) {
     67     TestOperandType type = kRegister;
     68     if (index != kNoValue) type = kFixedRegister;
     69     return TestOperand(type, vreg, index);
     70   }
     71 
     72   static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
     73 
     74   static TestOperand Slot(VReg vreg, int index = kNoValue) {
     75     TestOperandType type = kSlot;
     76     if (index != kNoValue) type = kFixedSlot;
     77     return TestOperand(type, vreg, index);
     78   }
     79 
     80   static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
     81 
     82   static TestOperand Const(int index) {
     83     CHECK_NE(kNoValue, index);
     84     return TestOperand(kConstant, VReg(), index);
     85   }
     86 
     87   static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
     88 
     89   static TestOperand Use() { return Use(VReg()); }
     90 
     91   static TestOperand Unique(VReg vreg) { return TestOperand(kUnique, vreg); }
     92 
     93   static TestOperand UniqueReg(VReg vreg) {
     94     return TestOperand(kUniqueRegister, vreg);
     95   }
     96 
     97   enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
     98 
     99   struct BlockCompletion {
    100     BlockCompletionType type_;
    101     TestOperand op_;
    102     int offset_0_;
    103     int offset_1_;
    104   };
    105 
    106   static BlockCompletion FallThrough() {
    107     BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
    108     return completion;
    109   }
    110 
    111   static BlockCompletion Jump(int offset) {
    112     BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
    113     return completion;
    114   }
    115 
    116   static BlockCompletion Branch(TestOperand op, int left_offset,
    117                                 int right_offset) {
    118     BlockCompletion completion = {kBranch, op, left_offset, right_offset};
    119     return completion;
    120   }
    121 
    122   static BlockCompletion Last() {
    123     BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
    124     return completion;
    125   }
    126 
    127   InstructionSequenceTest();
    128 
    129   void SetNumRegs(int num_general_registers, int num_double_registers);
    130   RegisterConfiguration* config();
    131   InstructionSequence* sequence();
    132 
    133   void StartLoop(int loop_blocks);
    134   void EndLoop();
    135   void StartBlock(bool deferred = false);
    136   Instruction* EndBlock(BlockCompletion completion = FallThrough());
    137 
    138   TestOperand Imm(int32_t imm = 0);
    139   VReg Define(TestOperand output_op);
    140   VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
    141 
    142   Instruction* Return(TestOperand input_op_0);
    143   Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); }
    144 
    145   PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
    146                       VReg incoming_vreg_1 = VReg(),
    147                       VReg incoming_vreg_2 = VReg(),
    148                       VReg incoming_vreg_3 = VReg());
    149   PhiInstruction* Phi(VReg incoming_vreg_0, size_t input_count);
    150   void SetInput(PhiInstruction* phi, size_t input, VReg vreg);
    151 
    152   VReg DefineConstant(int32_t imm = 0);
    153   Instruction* EmitNop();
    154   Instruction* EmitI(size_t input_size, TestOperand* inputs);
    155   Instruction* EmitI(TestOperand input_op_0 = TestOperand(),
    156                      TestOperand input_op_1 = TestOperand(),
    157                      TestOperand input_op_2 = TestOperand(),
    158                      TestOperand input_op_3 = TestOperand());
    159   VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
    160   VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
    161               TestOperand input_op_1 = TestOperand(),
    162               TestOperand input_op_2 = TestOperand(),
    163               TestOperand input_op_3 = TestOperand());
    164   VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
    165                    size_t input_size, TestOperand* inputs);
    166   VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
    167                    TestOperand input_op_0 = TestOperand(),
    168                    TestOperand input_op_1 = TestOperand(),
    169                    TestOperand input_op_2 = TestOperand(),
    170                    TestOperand input_op_3 = TestOperand());
    171   VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
    172   VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
    173                 TestOperand input_op_1 = TestOperand(),
    174                 TestOperand input_op_2 = TestOperand(),
    175                 TestOperand input_op_3 = TestOperand());
    176 
    177   InstructionBlock* current_block() const { return current_block_; }
    178   int num_general_registers() const { return num_general_registers_; }
    179   int num_double_registers() const { return num_double_registers_; }
    180 
    181   // Called after all instructions have been inserted.
    182   void WireBlocks();
    183 
    184  private:
    185   VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
    186 
    187   static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
    188 
    189   Instruction* EmitBranch(TestOperand input_op);
    190   Instruction* EmitFallThrough();
    191   Instruction* EmitJump();
    192   Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
    193                               InstructionOperand* outputs,
    194                               size_t inputs_size = 0,
    195                               InstructionOperand* inputs = nullptr,
    196                               size_t temps_size = 0,
    197                               InstructionOperand* temps = nullptr);
    198   InstructionOperand Unallocated(TestOperand op,
    199                                  UnallocatedOperand::ExtendedPolicy policy);
    200   InstructionOperand Unallocated(TestOperand op,
    201                                  UnallocatedOperand::ExtendedPolicy policy,
    202                                  UnallocatedOperand::Lifetime lifetime);
    203   InstructionOperand Unallocated(TestOperand op,
    204                                  UnallocatedOperand::ExtendedPolicy policy,
    205                                  int index);
    206   InstructionOperand Unallocated(TestOperand op,
    207                                  UnallocatedOperand::BasicPolicy policy,
    208                                  int index);
    209   InstructionOperand* ConvertInputs(size_t input_size, TestOperand* inputs);
    210   InstructionOperand ConvertInputOp(TestOperand op);
    211   InstructionOperand ConvertOutputOp(VReg vreg, TestOperand op);
    212   InstructionBlock* NewBlock(bool deferred = false);
    213   void WireBlock(size_t block_offset, int jump_offset);
    214 
    215   Instruction* Emit(InstructionCode code, size_t outputs_size = 0,
    216                     InstructionOperand* outputs = nullptr,
    217                     size_t inputs_size = 0,
    218                     InstructionOperand* inputs = nullptr, size_t temps_size = 0,
    219                     InstructionOperand* temps = nullptr, bool is_call = false);
    220 
    221   Instruction* AddInstruction(Instruction* instruction);
    222 
    223   struct LoopData {
    224     Rpo loop_header_;
    225     int expected_blocks_;
    226   };
    227 
    228   typedef std::vector<LoopData> LoopBlocks;
    229   typedef std::map<int, const Instruction*> Instructions;
    230   typedef std::vector<BlockCompletion> Completions;
    231 
    232   base::SmartPointer<RegisterConfiguration> config_;
    233   InstructionSequence* sequence_;
    234   int num_general_registers_;
    235   int num_double_registers_;
    236 
    237   // Block building state.
    238   InstructionBlocks instruction_blocks_;
    239   Instructions instructions_;
    240   Completions completions_;
    241   LoopBlocks loop_blocks_;
    242   InstructionBlock* current_block_;
    243   bool block_returns_;
    244 };
    245 
    246 }  // namespace compiler
    247 }  // namespace internal
    248 }  // namespace v8
    249 
    250 #endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
    251