Home | History | Annotate | Download | only in arm64
      1 // Copyright 2013 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_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
      6 #define V8_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
      7 
      8 #include "src/crankshaft/lithium.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 class LCodeGen;
     14 
     15 // This class delays the generation of some instructions. This way, we have a
     16 // chance to merge two instructions in one (with load/store pair).
     17 // Each instruction must either:
     18 //  - merge with the pending instruction and generate just one instruction.
     19 //  - emit the pending instruction and then generate the instruction (or set the
     20 //    pending instruction).
     21 class DelayedMasm BASE_EMBEDDED {
     22  public:
     23   DelayedMasm(LCodeGen* owner,
     24               MacroAssembler* masm,
     25               const Register& scratch_register)
     26     : cgen_(owner), masm_(masm), scratch_register_(scratch_register),
     27       scratch_register_used_(false), pending_(kNone), saved_value_(0) {
     28 #ifdef DEBUG
     29     pending_register_ = no_reg;
     30     pending_value_ = 0;
     31     pending_pc_ = 0;
     32     scratch_register_acquired_ = false;
     33 #endif
     34   }
     35   ~DelayedMasm() {
     36     DCHECK(!scratch_register_acquired_);
     37     DCHECK(!scratch_register_used_);
     38     DCHECK(!pending());
     39   }
     40   inline void EndDelayedUse();
     41 
     42   const Register& ScratchRegister() {
     43     scratch_register_used_ = true;
     44     return scratch_register_;
     45   }
     46   bool IsScratchRegister(const CPURegister& reg) {
     47     return reg.Is(scratch_register_);
     48   }
     49   bool scratch_register_used() const { return scratch_register_used_; }
     50   void reset_scratch_register_used() { scratch_register_used_ = false; }
     51   // Acquire/Release scratch register for use outside this class.
     52   void AcquireScratchRegister() {
     53     EmitPending();
     54     ResetSavedValue();
     55 #ifdef DEBUG
     56     DCHECK(!scratch_register_acquired_);
     57     scratch_register_acquired_ = true;
     58 #endif
     59   }
     60   void ReleaseScratchRegister() {
     61 #ifdef DEBUG
     62     DCHECK(scratch_register_acquired_);
     63     scratch_register_acquired_ = false;
     64 #endif
     65   }
     66   bool pending() { return pending_ != kNone; }
     67 
     68   // Extra layer over the macro-assembler instructions (which emits the
     69   // potential pending instruction).
     70   inline void Mov(const Register& rd,
     71                   const Operand& operand,
     72                   DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
     73   inline void Fmov(FPRegister fd, FPRegister fn);
     74   inline void Fmov(FPRegister fd, double imm);
     75   inline void LoadObject(Register result, Handle<Object> object);
     76   // Instructions which try to merge which the pending instructions.
     77   void StackSlotMove(LOperand* src, LOperand* dst);
     78   // StoreConstant can only be used if the scratch register is not acquired.
     79   void StoreConstant(uint64_t value, const MemOperand& operand);
     80   void Load(const CPURegister& rd, const MemOperand& operand);
     81   void Store(const CPURegister& rd, const MemOperand& operand);
     82   // Emit the potential pending instruction.
     83   void EmitPending();
     84   // Reset the pending state.
     85   void ResetPending() {
     86     pending_ = kNone;
     87 #ifdef DEBUG
     88     pending_register_ = no_reg;
     89     MemOperand tmp;
     90     pending_address_src_ = tmp;
     91     pending_address_dst_ = tmp;
     92     pending_value_ = 0;
     93     pending_pc_ = 0;
     94 #endif
     95   }
     96   void InitializeRootRegister() {
     97     masm_->InitializeRootRegister();
     98   }
     99 
    100  private:
    101   // Set the saved value and load the ScratchRegister with it.
    102   void SetSavedValue(uint64_t saved_value) {
    103     DCHECK(saved_value != 0);
    104     if (saved_value_ != saved_value) {
    105       masm_->Mov(ScratchRegister(), saved_value);
    106       saved_value_ = saved_value;
    107     }
    108   }
    109   // Reset the saved value (i.e. the value of ScratchRegister is no longer
    110   // known).
    111   void ResetSavedValue() {
    112     saved_value_ = 0;
    113   }
    114 
    115   LCodeGen* cgen_;
    116   MacroAssembler* masm_;
    117 
    118   // Register used to store a constant.
    119   Register scratch_register_;
    120   bool scratch_register_used_;
    121 
    122   // Sometimes we store or load two values in two contiguous stack slots.
    123   // In this case, we try to use the ldp/stp instructions to reduce code size.
    124   // To be able to do that, instead of generating directly the instructions,
    125   // we register with the following fields that an instruction needs to be
    126   // generated. Then with the next instruction, if the instruction is
    127   // consistent with the pending one for stp/ldp we generate ldp/stp. Else,
    128   // if they are not consistent, we generate the pending instruction and we
    129   // register the new instruction (which becomes pending).
    130 
    131   // Enumeration of instructions which can be pending.
    132   enum Pending {
    133     kNone,
    134     kStoreConstant,
    135     kLoad, kStore,
    136     kStackSlotMove
    137   };
    138   // The pending instruction.
    139   Pending pending_;
    140   // For kLoad, kStore: register which must be loaded/stored.
    141   CPURegister pending_register_;
    142   // For kLoad, kStackSlotMove: address of the load.
    143   MemOperand pending_address_src_;
    144   // For kStoreConstant, kStore, kStackSlotMove: address of the store.
    145   MemOperand pending_address_dst_;
    146   // For kStoreConstant: value to be stored.
    147   uint64_t pending_value_;
    148   // Value held into the ScratchRegister if the saved_value_ is not 0.
    149   // For 0, we use xzr.
    150   uint64_t saved_value_;
    151 #ifdef DEBUG
    152   // Address where the pending instruction must be generated. It's only used to
    153   // check that nothing else has been generated since we set the pending
    154   // instruction.
    155   int pending_pc_;
    156   // If true, the scratch register has been acquired outside this class. The
    157   // scratch register can no longer be used for constants.
    158   bool scratch_register_acquired_;
    159 #endif
    160 };
    161 
    162 }  // namespace internal
    163 }  // namespace v8
    164 
    165 #endif  // V8_CRANKSHAFT_ARM64_DELAYED_MASM_ARM64_H_
    166