OLD | NEW |
| (Empty) |
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: | |
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_ARM64_DELAYED_MASM_ARM64_H_ | |
OLD | NEW |