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_ARM64_DELAYED_MASM_ARM64_H_
6 #define V8_ARM64_DELAYED_MASM_ARM64_H_
7 
8 #include "src/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:
DelayedMasm(LCodeGen * owner,MacroAssembler * masm,const Register & scratch_register)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   }
~DelayedMasm()35   ~DelayedMasm() {
36     DCHECK(!scratch_register_acquired_);
37     DCHECK(!scratch_register_used_);
38     DCHECK(!pending());
39   }
40   inline void EndDelayedUse();
41 
ScratchRegister()42   const Register& ScratchRegister() {
43     scratch_register_used_ = true;
44     return scratch_register_;
45   }
IsScratchRegister(const CPURegister & reg)46   bool IsScratchRegister(const CPURegister& reg) {
47     return reg.Is(scratch_register_);
48   }
scratch_register_used()49   bool scratch_register_used() const { return scratch_register_used_; }
reset_scratch_register_used()50   void reset_scratch_register_used() { scratch_register_used_ = false; }
51   // Acquire/Release scratch register for use outside this class.
AcquireScratchRegister()52   void AcquireScratchRegister() {
53     EmitPending();
54     ResetSavedValue();
55 #ifdef DEBUG
56     DCHECK(!scratch_register_acquired_);
57     scratch_register_acquired_ = true;
58 #endif
59   }
ReleaseScratchRegister()60   void ReleaseScratchRegister() {
61 #ifdef DEBUG
62     DCHECK(scratch_register_acquired_);
63     scratch_register_acquired_ = false;
64 #endif
65   }
pending()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.
ResetPending()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   }
InitializeRootRegister()96   void InitializeRootRegister() {
97     masm_->InitializeRootRegister();
98   }
99 
100  private:
101   // Set the saved value and load the ScratchRegister with it.
SetSavedValue(uint64_t saved_value)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).
ResetSavedValue()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 v8::internal
163 
164 #endif  // V8_ARM64_DELAYED_MASM_ARM64_H_
165