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_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
      6 #define V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
      7 
      8 #include "src/compiler/instruction.h"
      9 #include "src/compiler/instruction-selector.h"
     10 #include "src/compiler/linkage.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 // A helper class for the instruction selector that simplifies construction of
     17 // Operands. This class implements a base for architecture-specific helpers.
     18 class OperandGenerator {
     19  public:
     20   explicit OperandGenerator(InstructionSelector* selector)
     21       : selector_(selector) {}
     22 
     23   InstructionOperand* DefineAsRegister(Node* node) {
     24     return Define(node, new (zone())
     25                   UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
     26   }
     27 
     28   InstructionOperand* DefineSameAsFirst(Node* result) {
     29     return Define(result, new (zone())
     30                   UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT));
     31   }
     32 
     33   InstructionOperand* DefineAsFixed(Node* node, Register reg) {
     34     return Define(node, new (zone())
     35                   UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
     36                                      Register::ToAllocationIndex(reg)));
     37   }
     38 
     39   InstructionOperand* DefineAsFixed(Node* node, DoubleRegister reg) {
     40     return Define(node, new (zone())
     41                   UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
     42                                      DoubleRegister::ToAllocationIndex(reg)));
     43   }
     44 
     45   InstructionOperand* DefineAsConstant(Node* node) {
     46     selector()->MarkAsDefined(node);
     47     sequence()->AddConstant(node->id(), ToConstant(node));
     48     return ConstantOperand::Create(node->id(), zone());
     49   }
     50 
     51   InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location,
     52                                        MachineType type) {
     53     return Define(node, ToUnallocatedOperand(location, type));
     54   }
     55 
     56   InstructionOperand* Use(Node* node) {
     57     return Use(node,
     58                new (zone()) UnallocatedOperand(
     59                    UnallocatedOperand::ANY, UnallocatedOperand::USED_AT_START));
     60   }
     61 
     62   InstructionOperand* UseRegister(Node* node) {
     63     return Use(node, new (zone())
     64                UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
     65                                   UnallocatedOperand::USED_AT_START));
     66   }
     67 
     68   // Use register or operand for the node. If a register is chosen, it won't
     69   // alias any temporary or output registers.
     70   InstructionOperand* UseUnique(Node* node) {
     71     return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::ANY));
     72   }
     73 
     74   // Use a unique register for the node that does not alias any temporary or
     75   // output registers.
     76   InstructionOperand* UseUniqueRegister(Node* node) {
     77     return Use(node, new (zone())
     78                UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
     79   }
     80 
     81   InstructionOperand* UseFixed(Node* node, Register reg) {
     82     return Use(node, new (zone())
     83                UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
     84                                   Register::ToAllocationIndex(reg)));
     85   }
     86 
     87   InstructionOperand* UseFixed(Node* node, DoubleRegister reg) {
     88     return Use(node, new (zone())
     89                UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
     90                                   DoubleRegister::ToAllocationIndex(reg)));
     91   }
     92 
     93   InstructionOperand* UseImmediate(Node* node) {
     94     int index = sequence()->AddImmediate(ToConstant(node));
     95     return ImmediateOperand::Create(index, zone());
     96   }
     97 
     98   InstructionOperand* UseLocation(Node* node, LinkageLocation location,
     99                                   MachineType type) {
    100     return Use(node, ToUnallocatedOperand(location, type));
    101   }
    102 
    103   InstructionOperand* TempRegister() {
    104     UnallocatedOperand* op =
    105         new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
    106                                         UnallocatedOperand::USED_AT_START);
    107     op->set_virtual_register(sequence()->NextVirtualRegister());
    108     return op;
    109   }
    110 
    111   InstructionOperand* TempDoubleRegister() {
    112     UnallocatedOperand* op =
    113         new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
    114                                         UnallocatedOperand::USED_AT_START);
    115     op->set_virtual_register(sequence()->NextVirtualRegister());
    116     sequence()->MarkAsDouble(op->virtual_register());
    117     return op;
    118   }
    119 
    120   InstructionOperand* TempRegister(Register reg) {
    121     return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
    122                                            Register::ToAllocationIndex(reg));
    123   }
    124 
    125   InstructionOperand* TempImmediate(int32_t imm) {
    126     int index = sequence()->AddImmediate(Constant(imm));
    127     return ImmediateOperand::Create(index, zone());
    128   }
    129 
    130   InstructionOperand* Label(BasicBlock* block) {
    131     // TODO(bmeurer): We misuse ImmediateOperand here.
    132     return TempImmediate(block->id());
    133   }
    134 
    135  protected:
    136   Graph* graph() const { return selector()->graph(); }
    137   InstructionSelector* selector() const { return selector_; }
    138   InstructionSequence* sequence() const { return selector()->sequence(); }
    139   Isolate* isolate() const { return zone()->isolate(); }
    140   Zone* zone() const { return selector()->instruction_zone(); }
    141 
    142  private:
    143   static Constant ToConstant(const Node* node) {
    144     switch (node->opcode()) {
    145       case IrOpcode::kInt32Constant:
    146         return Constant(OpParameter<int32_t>(node));
    147       case IrOpcode::kInt64Constant:
    148         return Constant(OpParameter<int64_t>(node));
    149       case IrOpcode::kNumberConstant:
    150       case IrOpcode::kFloat64Constant:
    151         return Constant(OpParameter<double>(node));
    152       case IrOpcode::kExternalConstant:
    153         return Constant(OpParameter<ExternalReference>(node));
    154       case IrOpcode::kHeapConstant:
    155         return Constant(OpParameter<Unique<HeapObject> >(node).handle());
    156       default:
    157         break;
    158     }
    159     UNREACHABLE();
    160     return Constant(static_cast<int32_t>(0));
    161   }
    162 
    163   UnallocatedOperand* Define(Node* node, UnallocatedOperand* operand) {
    164     DCHECK_NOT_NULL(node);
    165     DCHECK_NOT_NULL(operand);
    166     operand->set_virtual_register(node->id());
    167     selector()->MarkAsDefined(node);
    168     return operand;
    169   }
    170 
    171   UnallocatedOperand* Use(Node* node, UnallocatedOperand* operand) {
    172     DCHECK_NOT_NULL(node);
    173     DCHECK_NOT_NULL(operand);
    174     operand->set_virtual_register(node->id());
    175     selector()->MarkAsUsed(node);
    176     return operand;
    177   }
    178 
    179   UnallocatedOperand* ToUnallocatedOperand(LinkageLocation location,
    180                                            MachineType type) {
    181     if (location.location_ == LinkageLocation::ANY_REGISTER) {
    182       return new (zone())
    183           UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER);
    184     }
    185     if (location.location_ < 0) {
    186       return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
    187                                              location.location_);
    188     }
    189     if (RepresentationOf(type) == kRepFloat64) {
    190       return new (zone()) UnallocatedOperand(
    191           UnallocatedOperand::FIXED_DOUBLE_REGISTER, location.location_);
    192     }
    193     return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
    194                                            location.location_);
    195   }
    196 
    197   InstructionSelector* selector_;
    198 };
    199 
    200 
    201 // The flags continuation is a way to combine a branch or a materialization
    202 // of a boolean value with an instruction that sets the flags register.
    203 // The whole instruction is treated as a unit by the register allocator, and
    204 // thus no spills or moves can be introduced between the flags-setting
    205 // instruction and the branch or set it should be combined with.
    206 class FlagsContinuation FINAL {
    207  public:
    208   FlagsContinuation() : mode_(kFlags_none) {}
    209 
    210   // Creates a new flags continuation from the given condition and true/false
    211   // blocks.
    212   FlagsContinuation(FlagsCondition condition, BasicBlock* true_block,
    213                     BasicBlock* false_block)
    214       : mode_(kFlags_branch),
    215         condition_(condition),
    216         true_block_(true_block),
    217         false_block_(false_block) {
    218     DCHECK_NOT_NULL(true_block);
    219     DCHECK_NOT_NULL(false_block);
    220   }
    221 
    222   // Creates a new flags continuation from the given condition and result node.
    223   FlagsContinuation(FlagsCondition condition, Node* result)
    224       : mode_(kFlags_set), condition_(condition), result_(result) {
    225     DCHECK_NOT_NULL(result);
    226   }
    227 
    228   bool IsNone() const { return mode_ == kFlags_none; }
    229   bool IsBranch() const { return mode_ == kFlags_branch; }
    230   bool IsSet() const { return mode_ == kFlags_set; }
    231   FlagsCondition condition() const {
    232     DCHECK(!IsNone());
    233     return condition_;
    234   }
    235   Node* result() const {
    236     DCHECK(IsSet());
    237     return result_;
    238   }
    239   BasicBlock* true_block() const {
    240     DCHECK(IsBranch());
    241     return true_block_;
    242   }
    243   BasicBlock* false_block() const {
    244     DCHECK(IsBranch());
    245     return false_block_;
    246   }
    247 
    248   void Negate() {
    249     DCHECK(!IsNone());
    250     condition_ = static_cast<FlagsCondition>(condition_ ^ 1);
    251   }
    252 
    253   void Commute() {
    254     DCHECK(!IsNone());
    255     switch (condition_) {
    256       case kEqual:
    257       case kNotEqual:
    258       case kOverflow:
    259       case kNotOverflow:
    260         return;
    261       case kSignedLessThan:
    262         condition_ = kSignedGreaterThan;
    263         return;
    264       case kSignedGreaterThanOrEqual:
    265         condition_ = kSignedLessThanOrEqual;
    266         return;
    267       case kSignedLessThanOrEqual:
    268         condition_ = kSignedGreaterThanOrEqual;
    269         return;
    270       case kSignedGreaterThan:
    271         condition_ = kSignedLessThan;
    272         return;
    273       case kUnsignedLessThan:
    274         condition_ = kUnsignedGreaterThan;
    275         return;
    276       case kUnsignedGreaterThanOrEqual:
    277         condition_ = kUnsignedLessThanOrEqual;
    278         return;
    279       case kUnsignedLessThanOrEqual:
    280         condition_ = kUnsignedGreaterThanOrEqual;
    281         return;
    282       case kUnsignedGreaterThan:
    283         condition_ = kUnsignedLessThan;
    284         return;
    285       case kUnorderedEqual:
    286       case kUnorderedNotEqual:
    287         return;
    288       case kUnorderedLessThan:
    289         condition_ = kUnorderedGreaterThan;
    290         return;
    291       case kUnorderedGreaterThanOrEqual:
    292         condition_ = kUnorderedLessThanOrEqual;
    293         return;
    294       case kUnorderedLessThanOrEqual:
    295         condition_ = kUnorderedGreaterThanOrEqual;
    296         return;
    297       case kUnorderedGreaterThan:
    298         condition_ = kUnorderedLessThan;
    299         return;
    300     }
    301     UNREACHABLE();
    302   }
    303 
    304   void OverwriteAndNegateIfEqual(FlagsCondition condition) {
    305     bool negate = condition_ == kEqual;
    306     condition_ = condition;
    307     if (negate) Negate();
    308   }
    309 
    310   void SwapBlocks() { std::swap(true_block_, false_block_); }
    311 
    312   // Encodes this flags continuation into the given opcode.
    313   InstructionCode Encode(InstructionCode opcode) {
    314     opcode |= FlagsModeField::encode(mode_);
    315     if (mode_ != kFlags_none) {
    316       opcode |= FlagsConditionField::encode(condition_);
    317     }
    318     return opcode;
    319   }
    320 
    321  private:
    322   FlagsMode mode_;
    323   FlagsCondition condition_;
    324   Node* result_;             // Only valid if mode_ == kFlags_set.
    325   BasicBlock* true_block_;   // Only valid if mode_ == kFlags_branch.
    326   BasicBlock* false_block_;  // Only valid if mode_ == kFlags_branch.
    327 };
    328 
    329 
    330 // An internal helper class for generating the operands to calls.
    331 // TODO(bmeurer): Get rid of the CallBuffer business and make
    332 // InstructionSelector::VisitCall platform independent instead.
    333 struct CallBuffer {
    334   CallBuffer(Zone* zone, CallDescriptor* descriptor,
    335              FrameStateDescriptor* frame_state);
    336 
    337   CallDescriptor* descriptor;
    338   FrameStateDescriptor* frame_state_descriptor;
    339   NodeVector output_nodes;
    340   InstructionOperandVector outputs;
    341   InstructionOperandVector instruction_args;
    342   NodeVector pushed_nodes;
    343 
    344   size_t input_count() const { return descriptor->InputCount(); }
    345 
    346   size_t frame_state_count() const { return descriptor->FrameStateCount(); }
    347 
    348   size_t frame_state_value_count() const {
    349     return (frame_state_descriptor == NULL)
    350                ? 0
    351                : (frame_state_descriptor->GetTotalSize() +
    352                   1);  // Include deopt id.
    353   }
    354 };
    355 
    356 }  // namespace compiler
    357 }  // namespace internal
    358 }  // namespace v8
    359 
    360 #endif  // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
    361