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 #if V8_TARGET_ARCH_ARM64
6 
7 #include "src/crankshaft/arm64/delayed-masm-arm64.h"
8 #include "src/crankshaft/arm64/lithium-codegen-arm64.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 #define __ ACCESS_MASM(masm_)
14 
15 
StackSlotMove(LOperand * src,LOperand * dst)16 void DelayedMasm::StackSlotMove(LOperand* src, LOperand* dst) {
17   DCHECK((src->IsStackSlot() && dst->IsStackSlot()) ||
18          (src->IsDoubleStackSlot() && dst->IsDoubleStackSlot()));
19   MemOperand src_operand = cgen_->ToMemOperand(src);
20   MemOperand dst_operand = cgen_->ToMemOperand(dst);
21   if (pending_ == kStackSlotMove) {
22     DCHECK(pending_pc_ == masm_->pc_offset());
23     UseScratchRegisterScope scope(masm_);
24     DoubleRegister temp1 = scope.AcquireD();
25     DoubleRegister temp2 = scope.AcquireD();
26     switch (MemOperand::AreConsistentForPair(pending_address_src_,
27                                              src_operand)) {
28       case MemOperand::kNotPair:
29         __ Ldr(temp1, pending_address_src_);
30         __ Ldr(temp2, src_operand);
31         break;
32       case MemOperand::kPairAB:
33         __ Ldp(temp1, temp2, pending_address_src_);
34         break;
35       case MemOperand::kPairBA:
36         __ Ldp(temp2, temp1, src_operand);
37         break;
38     }
39     switch (MemOperand::AreConsistentForPair(pending_address_dst_,
40                                              dst_operand)) {
41       case MemOperand::kNotPair:
42         __ Str(temp1, pending_address_dst_);
43         __ Str(temp2, dst_operand);
44         break;
45       case MemOperand::kPairAB:
46         __ Stp(temp1, temp2, pending_address_dst_);
47         break;
48       case MemOperand::kPairBA:
49         __ Stp(temp2, temp1, dst_operand);
50         break;
51     }
52     ResetPending();
53     return;
54   }
55 
56   EmitPending();
57   pending_ = kStackSlotMove;
58   pending_address_src_ = src_operand;
59   pending_address_dst_ = dst_operand;
60 #ifdef DEBUG
61   pending_pc_ = masm_->pc_offset();
62 #endif
63 }
64 
65 
StoreConstant(uint64_t value,const MemOperand & operand)66 void DelayedMasm::StoreConstant(uint64_t value, const MemOperand& operand) {
67   DCHECK(!scratch_register_acquired_);
68   if ((pending_ == kStoreConstant) && (value == pending_value_)) {
69     MemOperand::PairResult result =
70         MemOperand::AreConsistentForPair(pending_address_dst_, operand);
71     if (result != MemOperand::kNotPair) {
72       const MemOperand& dst =
73           (result == MemOperand::kPairAB) ?
74               pending_address_dst_ :
75               operand;
76       DCHECK(pending_pc_ == masm_->pc_offset());
77       if (pending_value_ == 0) {
78         __ Stp(xzr, xzr, dst);
79       } else {
80         SetSavedValue(pending_value_);
81         __ Stp(ScratchRegister(), ScratchRegister(), dst);
82       }
83       ResetPending();
84       return;
85     }
86   }
87 
88   EmitPending();
89   pending_ = kStoreConstant;
90   pending_address_dst_ = operand;
91   pending_value_ = value;
92 #ifdef DEBUG
93   pending_pc_ = masm_->pc_offset();
94 #endif
95 }
96 
97 
Load(const CPURegister & rd,const MemOperand & operand)98 void DelayedMasm::Load(const CPURegister& rd, const MemOperand& operand) {
99   if ((pending_ == kLoad) &&
100       pending_register_.IsSameSizeAndType(rd)) {
101     switch (MemOperand::AreConsistentForPair(pending_address_src_, operand)) {
102       case MemOperand::kNotPair:
103         break;
104       case MemOperand::kPairAB:
105         DCHECK(pending_pc_ == masm_->pc_offset());
106         DCHECK(!IsScratchRegister(pending_register_) ||
107                scratch_register_acquired_);
108         DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
109         __ Ldp(pending_register_, rd, pending_address_src_);
110         ResetPending();
111         return;
112       case MemOperand::kPairBA:
113         DCHECK(pending_pc_ == masm_->pc_offset());
114         DCHECK(!IsScratchRegister(pending_register_) ||
115                scratch_register_acquired_);
116         DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
117         __ Ldp(rd, pending_register_, operand);
118         ResetPending();
119         return;
120     }
121   }
122 
123   EmitPending();
124   pending_ = kLoad;
125   pending_register_ = rd;
126   pending_address_src_ = operand;
127 #ifdef DEBUG
128   pending_pc_ = masm_->pc_offset();
129 #endif
130 }
131 
132 
Store(const CPURegister & rd,const MemOperand & operand)133 void DelayedMasm::Store(const CPURegister& rd, const MemOperand& operand) {
134   if ((pending_ == kStore) &&
135       pending_register_.IsSameSizeAndType(rd)) {
136     switch (MemOperand::AreConsistentForPair(pending_address_dst_, operand)) {
137       case MemOperand::kNotPair:
138         break;
139       case MemOperand::kPairAB:
140         DCHECK(pending_pc_ == masm_->pc_offset());
141         __ Stp(pending_register_, rd, pending_address_dst_);
142         ResetPending();
143         return;
144       case MemOperand::kPairBA:
145         DCHECK(pending_pc_ == masm_->pc_offset());
146         __ Stp(rd, pending_register_, operand);
147         ResetPending();
148         return;
149     }
150   }
151 
152   EmitPending();
153   pending_ = kStore;
154   pending_register_ = rd;
155   pending_address_dst_ = operand;
156 #ifdef DEBUG
157   pending_pc_ = masm_->pc_offset();
158 #endif
159 }
160 
161 
EmitPending()162 void DelayedMasm::EmitPending() {
163   DCHECK((pending_ == kNone) || (pending_pc_ == masm_->pc_offset()));
164   switch (pending_) {
165     case kNone:
166       return;
167     case kStoreConstant:
168       if (pending_value_ == 0) {
169         __ Str(xzr, pending_address_dst_);
170       } else {
171         SetSavedValue(pending_value_);
172         __ Str(ScratchRegister(), pending_address_dst_);
173       }
174       break;
175     case kLoad:
176       DCHECK(!IsScratchRegister(pending_register_) ||
177               scratch_register_acquired_);
178       __ Ldr(pending_register_, pending_address_src_);
179       break;
180     case kStore:
181       __ Str(pending_register_, pending_address_dst_);
182       break;
183     case kStackSlotMove: {
184       UseScratchRegisterScope scope(masm_);
185       DoubleRegister temp = scope.AcquireD();
186       __ Ldr(temp, pending_address_src_);
187       __ Str(temp, pending_address_dst_);
188       break;
189     }
190   }
191   ResetPending();
192 }
193 
194 }  // namespace internal
195 }  // namespace v8
196 
197 #endif  // V8_TARGET_ARCH_ARM64
198