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 explicit DelayedMasm(LCodeGen* owner, MacroAssembler* masm) | |
24 : cgen_(owner), masm_(masm), need_to_restore_root_(false), pending_(kNone), | |
25 saved_value_(0) { | |
26 #ifdef DEBUG | |
27 pending_register_ = no_reg; | |
28 pending_value_ = 0; | |
29 pending_pc_ = 0; | |
30 #endif | |
31 } | |
32 ~DelayedMasm() { | |
33 ASSERT(!need_to_restore_root_); | |
34 ASSERT(!pending()); | |
35 } | |
36 inline void EndDelayedUse(); | |
37 | |
38 // We use the root register as an extra scratch register. | |
39 // The root register has two advantages: | |
40 // - It is not in crankshaft allocatable registers list, so it can't | |
41 // interfere with the allocatable registers. | |
42 // - We don't need to push it on the stack, as we can reload it with its | |
43 // value once we have finish. | |
44 const Register& ScratchRegister() { | |
45 need_to_restore_root_ = true; | |
ulan
2014/06/04 09:28:19
I think the root register and its management belon
vincent.belliard
2014/06/09 10:31:15
The scratch register is now defined by the caller
| |
46 return root; | |
47 } | |
48 bool IsScratchRegister(const CPURegister& reg) { | |
49 return reg.Is(root); | |
50 } | |
51 bool pending() { return pending_ != kNone; } | |
52 | |
53 // Extra layer over the macro-assembler instructions (which emits the | |
54 // potential pending instruction). | |
55 inline void Mov(const Register& rd, | |
56 const Operand& operand, | |
57 DiscardMoveMode discard_mode = kDontDiscardForSameWReg); | |
58 inline void Fmov(FPRegister fd, FPRegister fn); | |
59 inline void Fmov(FPRegister fd, double imm); | |
60 inline void LoadObject(Register result, Handle<Object> object); | |
61 // Instructions which try to merge which the pending instructions. | |
62 void StackSlotMove(LOperand* src, LOperand* dst); | |
63 void StoreConstant(uint64_t value, const MemOperand& operand); | |
64 void Load(const CPURegister& rd, const MemOperand& operand); | |
65 void Store(const CPURegister& rd, const MemOperand& operand); | |
66 // Emit the potential pending instruction. | |
67 void EmitPending(); | |
68 // Reset the pending state. | |
69 void ResetPending() { | |
70 pending_ = kNone; | |
71 #ifdef DEBUG | |
72 pending_register_ = no_reg; | |
73 MemOperand tmp; | |
74 pending_address_src_ = tmp; | |
75 pending_address_dst_ = tmp; | |
76 pending_value_ = 0; | |
77 pending_pc_ = 0; | |
78 #endif | |
79 } | |
80 | |
81 private: | |
82 // Set the saved value and load the ScratchRegister with it. | |
83 void SetSavedValue(uint64_t saved_value) { | |
84 ASSERT(saved_value != 0); | |
85 if (saved_value_ != saved_value) { | |
86 masm_->Mov(ScratchRegister(), saved_value); | |
87 saved_value_ = saved_value; | |
88 } | |
89 } | |
90 // Reset the saved value (i.e. the value of ScratchRegister is no longer | |
91 // known). | |
92 void ResetSavedValue() { | |
93 saved_value_ = 0; | |
94 } | |
95 | |
96 LCodeGen* cgen_; | |
97 MacroAssembler* masm_; | |
98 | |
99 // We use the root register as a scratch in a few places. When that happens, | |
100 // this flag is set to indicate that it needs to be restored. | |
101 bool need_to_restore_root_; | |
102 | |
103 // Sometimes we store or load two values in two contiguous stack slots. | |
104 // In this case, we try to use the ldp/stp instructions to reduce code size. | |
105 // To be able to do that, instead of generating directly the instructions, | |
106 // we register with the following fields that an instruction needs to be | |
107 // generated. Then with the next instruction, if the instruction is | |
108 // consistent with the pending one for stp/ldp we generate ldp/stp. Else, | |
109 // if they are not consistent, we generate the pending instruction and we | |
110 // register the new instruction (which becomes pending). | |
111 | |
112 // Enumeration of instructions which can be pending. | |
113 enum Pending { | |
114 kNone, | |
115 kStoreConstant, | |
116 kLoad, kStore, | |
117 kStackSlotMove | |
118 }; | |
119 // The pending instruction. | |
120 Pending pending_; | |
121 // For kLoad, kStore: register which must be loaded/stored. | |
122 CPURegister pending_register_; | |
123 // For kLoad, kStackSlotMove: address of the load. | |
124 MemOperand pending_address_src_; | |
125 // For kStoreConstant, kStore, kStackSlotMove: address of the store. | |
126 MemOperand pending_address_dst_; | |
127 // For kStoreConstant: value to be stored. | |
128 uint64_t pending_value_; | |
129 // Value held into the ScratchRegister (root register) if | |
130 // the saved_value_ is not 0 (for 0, we use xzr). | |
131 uint64_t saved_value_; | |
132 #ifdef DEBUG | |
133 // Address where the pending instruction must be generated. It's only used to | |
134 // check that nothing else has been generated since we set the pending | |
135 // instruction. | |
136 int pending_pc_; | |
137 #endif | |
138 }; | |
139 | |
140 } } // namespace v8::internal | |
141 | |
142 #endif // V8_ARM64_DELAYED_MASM_ARM64_H_ | |
OLD | NEW |