xref: /aosp_15_r20/art/compiler/utils/arm/assembler_arm_vixl.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include <iostream>
18*795d594fSAndroid Build Coastguard Worker #include <type_traits>
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "assembler_arm_vixl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils_iterator.h"
23*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
24*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
25*795d594fSAndroid Build Coastguard Worker #include "thread.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker using namespace vixl::aarch32;  // NOLINT(build/namespaces)
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker namespace arm {
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker #ifdef ___
33*795d594fSAndroid Build Coastguard Worker #error "ARM Assembler macro already defined."
34*795d594fSAndroid Build Coastguard Worker #else
35*795d594fSAndroid Build Coastguard Worker #define ___   vixl_masm_.
36*795d594fSAndroid Build Coastguard Worker #endif
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // Thread register definition.
39*795d594fSAndroid Build Coastguard Worker extern const vixl32::Register tr(TR);
40*795d594fSAndroid Build Coastguard Worker // Marking register definition.
41*795d594fSAndroid Build Coastguard Worker extern const vixl32::Register mr(MR);
42*795d594fSAndroid Build Coastguard Worker 
FinalizeCode()43*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::FinalizeCode() {
44*795d594fSAndroid Build Coastguard Worker   vixl_masm_.FinalizeCode();
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker 
CodeSize() const47*795d594fSAndroid Build Coastguard Worker size_t ArmVIXLAssembler::CodeSize() const {
48*795d594fSAndroid Build Coastguard Worker   return vixl_masm_.GetSizeOfCodeGenerated();
49*795d594fSAndroid Build Coastguard Worker }
50*795d594fSAndroid Build Coastguard Worker 
CodeBufferBaseAddress() const51*795d594fSAndroid Build Coastguard Worker const uint8_t* ArmVIXLAssembler::CodeBufferBaseAddress() const {
52*795d594fSAndroid Build Coastguard Worker   return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker 
CopyInstructions(const MemoryRegion & region)55*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::CopyInstructions(const MemoryRegion& region) {
56*795d594fSAndroid Build Coastguard Worker   // Copy the instructions from the buffer.
57*795d594fSAndroid Build Coastguard Worker   MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
58*795d594fSAndroid Build Coastguard Worker   region.CopyFrom(0, from);
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker 
PoisonHeapReference(vixl::aarch32::Register reg)61*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::PoisonHeapReference(vixl::aarch32::Register reg) {
62*795d594fSAndroid Build Coastguard Worker   // reg = -reg.
63*795d594fSAndroid Build Coastguard Worker   ___ Rsb(reg, reg, 0);
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker 
UnpoisonHeapReference(vixl::aarch32::Register reg)66*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::UnpoisonHeapReference(vixl::aarch32::Register reg) {
67*795d594fSAndroid Build Coastguard Worker   // reg = -reg.
68*795d594fSAndroid Build Coastguard Worker   ___ Rsb(reg, reg, 0);
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
MaybePoisonHeapReference(vixl32::Register reg)71*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::MaybePoisonHeapReference(vixl32::Register reg) {
72*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
73*795d594fSAndroid Build Coastguard Worker     PoisonHeapReference(reg);
74*795d594fSAndroid Build Coastguard Worker   }
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker 
MaybeUnpoisonHeapReference(vixl32::Register reg)77*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::MaybeUnpoisonHeapReference(vixl32::Register reg) {
78*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
79*795d594fSAndroid Build Coastguard Worker     UnpoisonHeapReference(reg);
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
GenerateMarkingRegisterCheck(vixl32::Register temp,int code)83*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::GenerateMarkingRegisterCheck(vixl32::Register temp, int code) {
84*795d594fSAndroid Build Coastguard Worker   DCHECK(kReserveMarkingRegister);
85*795d594fSAndroid Build Coastguard Worker 
86*795d594fSAndroid Build Coastguard Worker   vixl32::Label mr_is_ok;
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker   // temp = self.tls32_.is.gc_marking
89*795d594fSAndroid Build Coastguard Worker   ___ Ldr(temp, MemOperand(tr, Thread::IsGcMarkingOffset<kArmPointerSize>().Int32Value()));
90*795d594fSAndroid Build Coastguard Worker   // Check that mr == self.tls32_.is.gc_marking.
91*795d594fSAndroid Build Coastguard Worker   ___ Cmp(mr, temp);
92*795d594fSAndroid Build Coastguard Worker   ___ B(eq, &mr_is_ok, /* is_far_target= */ false);
93*795d594fSAndroid Build Coastguard Worker   ___ Bkpt(code);
94*795d594fSAndroid Build Coastguard Worker   ___ Bind(&mr_is_ok);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker 
LoadImmediate(vixl32::Register rd,int32_t value)97*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::LoadImmediate(vixl32::Register rd, int32_t value) {
98*795d594fSAndroid Build Coastguard Worker   // TODO(VIXL): Implement this optimization in VIXL.
99*795d594fSAndroid Build Coastguard Worker   if (!ShifterOperandCanAlwaysHold(value) && ShifterOperandCanAlwaysHold(~value)) {
100*795d594fSAndroid Build Coastguard Worker     ___ Mvn(rd, ~value);
101*795d594fSAndroid Build Coastguard Worker   } else {
102*795d594fSAndroid Build Coastguard Worker     ___ Mov(rd, value);
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker 
ShifterOperandCanAlwaysHold(uint32_t immediate)106*795d594fSAndroid Build Coastguard Worker bool ArmVIXLAssembler::ShifterOperandCanAlwaysHold(uint32_t immediate) {
107*795d594fSAndroid Build Coastguard Worker   return vixl_masm_.IsModifiedImmediate(immediate);
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
ShifterOperandCanHold(Opcode opcode,uint32_t immediate,vixl::aarch32::FlagsUpdate update_flags)110*795d594fSAndroid Build Coastguard Worker bool ArmVIXLAssembler::ShifterOperandCanHold(Opcode opcode,
111*795d594fSAndroid Build Coastguard Worker                                              uint32_t immediate,
112*795d594fSAndroid Build Coastguard Worker                                              vixl::aarch32::FlagsUpdate update_flags) {
113*795d594fSAndroid Build Coastguard Worker   switch (opcode) {
114*795d594fSAndroid Build Coastguard Worker     case ADD:
115*795d594fSAndroid Build Coastguard Worker     case SUB:
116*795d594fSAndroid Build Coastguard Worker       // Less than (or equal to) 12 bits can be done if we don't need to set condition codes.
117*795d594fSAndroid Build Coastguard Worker       if (IsUint<12>(immediate) && update_flags != vixl::aarch32::SetFlags) {
118*795d594fSAndroid Build Coastguard Worker         return true;
119*795d594fSAndroid Build Coastguard Worker       }
120*795d594fSAndroid Build Coastguard Worker       return ShifterOperandCanAlwaysHold(immediate);
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker     case MOV:
123*795d594fSAndroid Build Coastguard Worker       // TODO: Support less than or equal to 12bits.
124*795d594fSAndroid Build Coastguard Worker       return ShifterOperandCanAlwaysHold(immediate);
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker     case MVN:
127*795d594fSAndroid Build Coastguard Worker     default:
128*795d594fSAndroid Build Coastguard Worker       return ShifterOperandCanAlwaysHold(immediate);
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker 
CanSplitLoadStoreOffset(int32_t allowed_offset_bits,int32_t offset,int32_t * add_to_base,int32_t * offset_for_load_store)132*795d594fSAndroid Build Coastguard Worker bool ArmVIXLAssembler::CanSplitLoadStoreOffset(int32_t allowed_offset_bits,
133*795d594fSAndroid Build Coastguard Worker                                                int32_t offset,
134*795d594fSAndroid Build Coastguard Worker                                                /*out*/ int32_t* add_to_base,
135*795d594fSAndroid Build Coastguard Worker                                                /*out*/ int32_t* offset_for_load_store) {
136*795d594fSAndroid Build Coastguard Worker   int32_t other_bits = offset & ~allowed_offset_bits;
137*795d594fSAndroid Build Coastguard Worker   if (ShifterOperandCanAlwaysHold(other_bits) || ShifterOperandCanAlwaysHold(-other_bits)) {
138*795d594fSAndroid Build Coastguard Worker     *add_to_base = offset & ~allowed_offset_bits;
139*795d594fSAndroid Build Coastguard Worker     *offset_for_load_store = offset & allowed_offset_bits;
140*795d594fSAndroid Build Coastguard Worker     return true;
141*795d594fSAndroid Build Coastguard Worker   }
142*795d594fSAndroid Build Coastguard Worker   return false;
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker 
AdjustLoadStoreOffset(int32_t allowed_offset_bits,vixl32::Register temp,vixl32::Register base,int32_t offset)145*795d594fSAndroid Build Coastguard Worker int32_t ArmVIXLAssembler::AdjustLoadStoreOffset(int32_t allowed_offset_bits,
146*795d594fSAndroid Build Coastguard Worker                                                 vixl32::Register temp,
147*795d594fSAndroid Build Coastguard Worker                                                 vixl32::Register base,
148*795d594fSAndroid Build Coastguard Worker                                                 int32_t offset) {
149*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(offset & ~allowed_offset_bits, 0);
150*795d594fSAndroid Build Coastguard Worker   int32_t add_to_base, offset_for_load;
151*795d594fSAndroid Build Coastguard Worker   if (CanSplitLoadStoreOffset(allowed_offset_bits, offset, &add_to_base, &offset_for_load)) {
152*795d594fSAndroid Build Coastguard Worker     ___ Add(temp, base, add_to_base);
153*795d594fSAndroid Build Coastguard Worker     return offset_for_load;
154*795d594fSAndroid Build Coastguard Worker   } else {
155*795d594fSAndroid Build Coastguard Worker     ___ Mov(temp, offset);
156*795d594fSAndroid Build Coastguard Worker     ___ Add(temp, temp, base);
157*795d594fSAndroid Build Coastguard Worker     return 0;
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement this in VIXL.
GetAllowedLoadOffsetBits(LoadOperandType type)162*795d594fSAndroid Build Coastguard Worker int32_t ArmVIXLAssembler::GetAllowedLoadOffsetBits(LoadOperandType type) {
163*795d594fSAndroid Build Coastguard Worker   switch (type) {
164*795d594fSAndroid Build Coastguard Worker     case kLoadSignedByte:
165*795d594fSAndroid Build Coastguard Worker     case kLoadSignedHalfword:
166*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedHalfword:
167*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedByte:
168*795d594fSAndroid Build Coastguard Worker     case kLoadWord:
169*795d594fSAndroid Build Coastguard Worker       // We can encode imm12 offset.
170*795d594fSAndroid Build Coastguard Worker       return 0xfff;
171*795d594fSAndroid Build Coastguard Worker     case kLoadSWord:
172*795d594fSAndroid Build Coastguard Worker     case kLoadDWord:
173*795d594fSAndroid Build Coastguard Worker     case kLoadWordPair:
174*795d594fSAndroid Build Coastguard Worker       // We can encode imm8:'00' offset.
175*795d594fSAndroid Build Coastguard Worker       return 0xff << 2;
176*795d594fSAndroid Build Coastguard Worker   }
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement this in VIXL.
GetAllowedStoreOffsetBits(StoreOperandType type)180*795d594fSAndroid Build Coastguard Worker int32_t ArmVIXLAssembler::GetAllowedStoreOffsetBits(StoreOperandType type) {
181*795d594fSAndroid Build Coastguard Worker   switch (type) {
182*795d594fSAndroid Build Coastguard Worker     case kStoreHalfword:
183*795d594fSAndroid Build Coastguard Worker     case kStoreByte:
184*795d594fSAndroid Build Coastguard Worker     case kStoreWord:
185*795d594fSAndroid Build Coastguard Worker       // We can encode imm12 offset.
186*795d594fSAndroid Build Coastguard Worker       return 0xfff;
187*795d594fSAndroid Build Coastguard Worker     case kStoreSWord:
188*795d594fSAndroid Build Coastguard Worker     case kStoreDWord:
189*795d594fSAndroid Build Coastguard Worker     case kStoreWordPair:
190*795d594fSAndroid Build Coastguard Worker       // We can encode imm8:'00' offset.
191*795d594fSAndroid Build Coastguard Worker       return 0xff << 2;
192*795d594fSAndroid Build Coastguard Worker   }
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement this in VIXL.
CanHoldLoadOffsetThumb(LoadOperandType type,int offset)196*795d594fSAndroid Build Coastguard Worker static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset) {
197*795d594fSAndroid Build Coastguard Worker   switch (type) {
198*795d594fSAndroid Build Coastguard Worker     case kLoadSignedByte:
199*795d594fSAndroid Build Coastguard Worker     case kLoadSignedHalfword:
200*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedHalfword:
201*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedByte:
202*795d594fSAndroid Build Coastguard Worker     case kLoadWord:
203*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<12>(offset);
204*795d594fSAndroid Build Coastguard Worker     case kLoadSWord:
205*795d594fSAndroid Build Coastguard Worker     case kLoadDWord:
206*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);  // VFP addressing mode.
207*795d594fSAndroid Build Coastguard Worker     case kLoadWordPair:
208*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
209*795d594fSAndroid Build Coastguard Worker   }
210*795d594fSAndroid Build Coastguard Worker }
211*795d594fSAndroid Build Coastguard Worker 
212*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement this in VIXL.
CanHoldStoreOffsetThumb(StoreOperandType type,int offset)213*795d594fSAndroid Build Coastguard Worker static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset) {
214*795d594fSAndroid Build Coastguard Worker   switch (type) {
215*795d594fSAndroid Build Coastguard Worker     case kStoreHalfword:
216*795d594fSAndroid Build Coastguard Worker     case kStoreByte:
217*795d594fSAndroid Build Coastguard Worker     case kStoreWord:
218*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<12>(offset);
219*795d594fSAndroid Build Coastguard Worker     case kStoreSWord:
220*795d594fSAndroid Build Coastguard Worker     case kStoreDWord:
221*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);  // VFP addressing mode.
222*795d594fSAndroid Build Coastguard Worker     case kStoreWordPair:
223*795d594fSAndroid Build Coastguard Worker       return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
224*795d594fSAndroid Build Coastguard Worker   }
225*795d594fSAndroid Build Coastguard Worker }
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker // Implementation note: this method must emit at most one instruction when
228*795d594fSAndroid Build Coastguard Worker // Address::CanHoldStoreOffsetThumb.
229*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL.
StoreToOffset(StoreOperandType type,vixl32::Register reg,vixl32::Register base,int32_t offset)230*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::StoreToOffset(StoreOperandType type,
231*795d594fSAndroid Build Coastguard Worker                                      vixl32::Register reg,
232*795d594fSAndroid Build Coastguard Worker                                      vixl32::Register base,
233*795d594fSAndroid Build Coastguard Worker                                      int32_t offset) {
234*795d594fSAndroid Build Coastguard Worker   vixl32::Register tmp_reg;
235*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(&vixl_masm_);
236*795d594fSAndroid Build Coastguard Worker 
237*795d594fSAndroid Build Coastguard Worker   if (!CanHoldStoreOffsetThumb(type, offset)) {
238*795d594fSAndroid Build Coastguard Worker     CHECK_NE(base.GetCode(), kIpCode);
239*795d594fSAndroid Build Coastguard Worker     if ((reg.GetCode() != kIpCode) &&
240*795d594fSAndroid Build Coastguard Worker         (!vixl_masm_.GetScratchRegisterList()->IsEmpty()) &&
241*795d594fSAndroid Build Coastguard Worker         ((type != kStoreWordPair) || (reg.GetCode() + 1 != kIpCode))) {
242*795d594fSAndroid Build Coastguard Worker       tmp_reg = temps.Acquire();
243*795d594fSAndroid Build Coastguard Worker     } else {
244*795d594fSAndroid Build Coastguard Worker       // Be careful not to use ip twice (for `reg` (or `reg` + 1 in
245*795d594fSAndroid Build Coastguard Worker       // the case of a word-pair store) and `base`) to build the
246*795d594fSAndroid Build Coastguard Worker       // Address object used by the store instruction(s) below.
247*795d594fSAndroid Build Coastguard Worker       // Instead, save R5 on the stack (or R6 if R5 is already used by
248*795d594fSAndroid Build Coastguard Worker       // `base`), use it as secondary temporary register, and restore
249*795d594fSAndroid Build Coastguard Worker       // it after the store instruction has been emitted.
250*795d594fSAndroid Build Coastguard Worker       tmp_reg = (base.GetCode() != 5) ? r5 : r6;
251*795d594fSAndroid Build Coastguard Worker       ___ Push(tmp_reg);
252*795d594fSAndroid Build Coastguard Worker       if (base.GetCode() == kSpCode) {
253*795d594fSAndroid Build Coastguard Worker         offset += kRegisterSize;
254*795d594fSAndroid Build Coastguard Worker       }
255*795d594fSAndroid Build Coastguard Worker     }
256*795d594fSAndroid Build Coastguard Worker     // TODO: Implement indexed store (not available for STRD), inline AdjustLoadStoreOffset()
257*795d594fSAndroid Build Coastguard Worker     // and in the "unsplittable" path get rid of the "add" by using the store indexed instead.
258*795d594fSAndroid Build Coastguard Worker     offset = AdjustLoadStoreOffset(GetAllowedStoreOffsetBits(type), tmp_reg, base, offset);
259*795d594fSAndroid Build Coastguard Worker     base = tmp_reg;
260*795d594fSAndroid Build Coastguard Worker   }
261*795d594fSAndroid Build Coastguard Worker   DCHECK(CanHoldStoreOffsetThumb(type, offset));
262*795d594fSAndroid Build Coastguard Worker   switch (type) {
263*795d594fSAndroid Build Coastguard Worker     case kStoreByte:
264*795d594fSAndroid Build Coastguard Worker       ___ Strb(reg, MemOperand(base, offset));
265*795d594fSAndroid Build Coastguard Worker       break;
266*795d594fSAndroid Build Coastguard Worker     case kStoreHalfword:
267*795d594fSAndroid Build Coastguard Worker       ___ Strh(reg, MemOperand(base, offset));
268*795d594fSAndroid Build Coastguard Worker       break;
269*795d594fSAndroid Build Coastguard Worker     case kStoreWord:
270*795d594fSAndroid Build Coastguard Worker       ___ Str(reg, MemOperand(base, offset));
271*795d594fSAndroid Build Coastguard Worker       break;
272*795d594fSAndroid Build Coastguard Worker     case kStoreWordPair:
273*795d594fSAndroid Build Coastguard Worker       ___ Strd(reg, vixl32::Register(reg.GetCode() + 1), MemOperand(base, offset));
274*795d594fSAndroid Build Coastguard Worker       break;
275*795d594fSAndroid Build Coastguard Worker     default:
276*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "UNREACHABLE";
277*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker   if ((tmp_reg.IsValid()) && (tmp_reg.GetCode() != kIpCode)) {
280*795d594fSAndroid Build Coastguard Worker     CHECK(tmp_reg.Is(r5) || tmp_reg.Is(r6)) << tmp_reg;
281*795d594fSAndroid Build Coastguard Worker     ___ Pop(tmp_reg);
282*795d594fSAndroid Build Coastguard Worker   }
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker // Implementation note: this method must emit at most one instruction when
286*795d594fSAndroid Build Coastguard Worker // Address::CanHoldLoadOffsetThumb.
287*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL.
LoadFromOffset(LoadOperandType type,vixl32::Register dest,vixl32::Register base,int32_t offset)288*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::LoadFromOffset(LoadOperandType type,
289*795d594fSAndroid Build Coastguard Worker                                       vixl32::Register dest,
290*795d594fSAndroid Build Coastguard Worker                                       vixl32::Register base,
291*795d594fSAndroid Build Coastguard Worker                                       int32_t offset) {
292*795d594fSAndroid Build Coastguard Worker   if (!CanHoldLoadOffsetThumb(type, offset)) {
293*795d594fSAndroid Build Coastguard Worker     CHECK(!base.Is(ip));
294*795d594fSAndroid Build Coastguard Worker     // Inlined AdjustLoadStoreOffset() allows us to pull a few more tricks.
295*795d594fSAndroid Build Coastguard Worker     int32_t allowed_offset_bits = GetAllowedLoadOffsetBits(type);
296*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(offset & ~allowed_offset_bits, 0);
297*795d594fSAndroid Build Coastguard Worker     int32_t add_to_base, offset_for_load;
298*795d594fSAndroid Build Coastguard Worker     if (CanSplitLoadStoreOffset(allowed_offset_bits, offset, &add_to_base, &offset_for_load)) {
299*795d594fSAndroid Build Coastguard Worker       // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
300*795d594fSAndroid Build Coastguard Worker       AddConstant(dest, base, add_to_base);
301*795d594fSAndroid Build Coastguard Worker       base = dest;
302*795d594fSAndroid Build Coastguard Worker       offset = offset_for_load;
303*795d594fSAndroid Build Coastguard Worker     } else {
304*795d594fSAndroid Build Coastguard Worker       UseScratchRegisterScope temps(&vixl_masm_);
305*795d594fSAndroid Build Coastguard Worker       vixl32::Register temp = (dest.Is(base)) ? temps.Acquire() : dest;
306*795d594fSAndroid Build Coastguard Worker       LoadImmediate(temp, offset);
307*795d594fSAndroid Build Coastguard Worker       // TODO: Implement indexed load (not available for LDRD) and use it here to avoid the ADD.
308*795d594fSAndroid Build Coastguard Worker       // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
309*795d594fSAndroid Build Coastguard Worker       ___ Add(dest, dest, (dest.Is(base)) ? temp : base);
310*795d594fSAndroid Build Coastguard Worker       base = dest;
311*795d594fSAndroid Build Coastguard Worker       offset = 0;
312*795d594fSAndroid Build Coastguard Worker     }
313*795d594fSAndroid Build Coastguard Worker   }
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker   DCHECK(CanHoldLoadOffsetThumb(type, offset));
316*795d594fSAndroid Build Coastguard Worker   switch (type) {
317*795d594fSAndroid Build Coastguard Worker     case kLoadSignedByte:
318*795d594fSAndroid Build Coastguard Worker       ___ Ldrsb(dest, MemOperand(base, offset));
319*795d594fSAndroid Build Coastguard Worker       break;
320*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedByte:
321*795d594fSAndroid Build Coastguard Worker       ___ Ldrb(dest, MemOperand(base, offset));
322*795d594fSAndroid Build Coastguard Worker       break;
323*795d594fSAndroid Build Coastguard Worker     case kLoadSignedHalfword:
324*795d594fSAndroid Build Coastguard Worker       ___ Ldrsh(dest, MemOperand(base, offset));
325*795d594fSAndroid Build Coastguard Worker       break;
326*795d594fSAndroid Build Coastguard Worker     case kLoadUnsignedHalfword:
327*795d594fSAndroid Build Coastguard Worker       ___ Ldrh(dest, MemOperand(base, offset));
328*795d594fSAndroid Build Coastguard Worker       break;
329*795d594fSAndroid Build Coastguard Worker     case kLoadWord:
330*795d594fSAndroid Build Coastguard Worker       CHECK(!dest.IsSP());
331*795d594fSAndroid Build Coastguard Worker       ___ Ldr(dest, MemOperand(base, offset));
332*795d594fSAndroid Build Coastguard Worker       break;
333*795d594fSAndroid Build Coastguard Worker     case kLoadWordPair:
334*795d594fSAndroid Build Coastguard Worker       ___ Ldrd(dest, vixl32::Register(dest.GetCode() + 1), MemOperand(base, offset));
335*795d594fSAndroid Build Coastguard Worker       break;
336*795d594fSAndroid Build Coastguard Worker     default:
337*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "UNREACHABLE";
338*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker }
341*795d594fSAndroid Build Coastguard Worker 
StoreSToOffset(vixl32::SRegister source,vixl32::Register base,int32_t offset)342*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::StoreSToOffset(vixl32::SRegister source,
343*795d594fSAndroid Build Coastguard Worker                                       vixl32::Register base,
344*795d594fSAndroid Build Coastguard Worker                                       int32_t offset) {
345*795d594fSAndroid Build Coastguard Worker   ___ Vstr(source, MemOperand(base, offset));
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker 
StoreDToOffset(vixl32::DRegister source,vixl32::Register base,int32_t offset)348*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::StoreDToOffset(vixl32::DRegister source,
349*795d594fSAndroid Build Coastguard Worker                                       vixl32::Register base,
350*795d594fSAndroid Build Coastguard Worker                                       int32_t offset) {
351*795d594fSAndroid Build Coastguard Worker   ___ Vstr(source, MemOperand(base, offset));
352*795d594fSAndroid Build Coastguard Worker }
353*795d594fSAndroid Build Coastguard Worker 
LoadSFromOffset(vixl32::SRegister reg,vixl32::Register base,int32_t offset)354*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::LoadSFromOffset(vixl32::SRegister reg,
355*795d594fSAndroid Build Coastguard Worker                                        vixl32::Register base,
356*795d594fSAndroid Build Coastguard Worker                                        int32_t offset) {
357*795d594fSAndroid Build Coastguard Worker   ___ Vldr(reg, MemOperand(base, offset));
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker 
LoadDFromOffset(vixl32::DRegister reg,vixl32::Register base,int32_t offset)360*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::LoadDFromOffset(vixl32::DRegister reg,
361*795d594fSAndroid Build Coastguard Worker                                        vixl32::Register base,
362*795d594fSAndroid Build Coastguard Worker                                        int32_t offset) {
363*795d594fSAndroid Build Coastguard Worker   ___ Vldr(reg, MemOperand(base, offset));
364*795d594fSAndroid Build Coastguard Worker }
365*795d594fSAndroid Build Coastguard Worker 
366*795d594fSAndroid Build Coastguard Worker // Prefer Str to Add/Stm in ArmVIXLAssembler::StoreRegisterList and
367*795d594fSAndroid Build Coastguard Worker // ArmVIXLAssembler::LoadRegisterList where this generates less code (size).
368*795d594fSAndroid Build Coastguard Worker static constexpr int kRegListThreshold = 4;
369*795d594fSAndroid Build Coastguard Worker 
StoreRegisterList(RegList regs,size_t stack_offset)370*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::StoreRegisterList(RegList regs, size_t stack_offset) {
371*795d594fSAndroid Build Coastguard Worker   int number_of_regs = POPCOUNT(static_cast<uint32_t>(regs));
372*795d594fSAndroid Build Coastguard Worker   if (number_of_regs != 0) {
373*795d594fSAndroid Build Coastguard Worker     if (number_of_regs > kRegListThreshold) {
374*795d594fSAndroid Build Coastguard Worker       UseScratchRegisterScope temps(GetVIXLAssembler());
375*795d594fSAndroid Build Coastguard Worker       vixl32::Register base = sp;
376*795d594fSAndroid Build Coastguard Worker       if (stack_offset != 0) {
377*795d594fSAndroid Build Coastguard Worker         base = temps.Acquire();
378*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(regs & (1u << base.GetCode()), 0u);
379*795d594fSAndroid Build Coastguard Worker         ___ Add(base, sp, Operand::From(stack_offset));
380*795d594fSAndroid Build Coastguard Worker       }
381*795d594fSAndroid Build Coastguard Worker       ___ Stm(base, NO_WRITE_BACK, RegisterList(regs));
382*795d594fSAndroid Build Coastguard Worker     } else {
383*795d594fSAndroid Build Coastguard Worker       for (uint32_t i : LowToHighBits(static_cast<uint32_t>(regs))) {
384*795d594fSAndroid Build Coastguard Worker         ___ Str(vixl32::Register(i), MemOperand(sp, stack_offset));
385*795d594fSAndroid Build Coastguard Worker         stack_offset += kRegSizeInBytes;
386*795d594fSAndroid Build Coastguard Worker       }
387*795d594fSAndroid Build Coastguard Worker     }
388*795d594fSAndroid Build Coastguard Worker   }
389*795d594fSAndroid Build Coastguard Worker }
390*795d594fSAndroid Build Coastguard Worker 
LoadRegisterList(RegList regs,size_t stack_offset)391*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::LoadRegisterList(RegList regs, size_t stack_offset) {
392*795d594fSAndroid Build Coastguard Worker   int number_of_regs = POPCOUNT(static_cast<uint32_t>(regs));
393*795d594fSAndroid Build Coastguard Worker   if (number_of_regs != 0) {
394*795d594fSAndroid Build Coastguard Worker     if (number_of_regs > kRegListThreshold) {
395*795d594fSAndroid Build Coastguard Worker       UseScratchRegisterScope temps(GetVIXLAssembler());
396*795d594fSAndroid Build Coastguard Worker       vixl32::Register base = sp;
397*795d594fSAndroid Build Coastguard Worker       if (stack_offset != 0) {
398*795d594fSAndroid Build Coastguard Worker         base = temps.Acquire();
399*795d594fSAndroid Build Coastguard Worker         ___ Add(base, sp, Operand::From(stack_offset));
400*795d594fSAndroid Build Coastguard Worker       }
401*795d594fSAndroid Build Coastguard Worker       ___ Ldm(base, NO_WRITE_BACK, RegisterList(regs));
402*795d594fSAndroid Build Coastguard Worker     } else {
403*795d594fSAndroid Build Coastguard Worker       for (uint32_t i : LowToHighBits(static_cast<uint32_t>(regs))) {
404*795d594fSAndroid Build Coastguard Worker         ___ Ldr(vixl32::Register(i), MemOperand(sp, stack_offset));
405*795d594fSAndroid Build Coastguard Worker         stack_offset += kRegSizeInBytes;
406*795d594fSAndroid Build Coastguard Worker       }
407*795d594fSAndroid Build Coastguard Worker     }
408*795d594fSAndroid Build Coastguard Worker   }
409*795d594fSAndroid Build Coastguard Worker }
410*795d594fSAndroid Build Coastguard Worker 
AddConstant(vixl32::Register rd,int32_t value)411*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::AddConstant(vixl32::Register rd, int32_t value) {
412*795d594fSAndroid Build Coastguard Worker   AddConstant(rd, rd, value);
413*795d594fSAndroid Build Coastguard Worker }
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): think about using adds which updates flags where possible.
AddConstant(vixl32::Register rd,vixl32::Register rn,int32_t value)416*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::AddConstant(vixl32::Register rd,
417*795d594fSAndroid Build Coastguard Worker                                    vixl32::Register rn,
418*795d594fSAndroid Build Coastguard Worker                                    int32_t value) {
419*795d594fSAndroid Build Coastguard Worker   DCHECK(vixl_masm_.OutsideITBlock());
420*795d594fSAndroid Build Coastguard Worker   // TODO(VIXL): implement this optimization in VIXL.
421*795d594fSAndroid Build Coastguard Worker   if (value == 0) {
422*795d594fSAndroid Build Coastguard Worker     if (!rd.Is(rn)) {
423*795d594fSAndroid Build Coastguard Worker       ___ Mov(rd, rn);
424*795d594fSAndroid Build Coastguard Worker     }
425*795d594fSAndroid Build Coastguard Worker     return;
426*795d594fSAndroid Build Coastguard Worker   }
427*795d594fSAndroid Build Coastguard Worker   ___ Add(rd, rn, value);
428*795d594fSAndroid Build Coastguard Worker }
429*795d594fSAndroid Build Coastguard Worker 
430*795d594fSAndroid Build Coastguard Worker // Inside IT block we must use assembler, macroassembler instructions are not permitted.
AddConstantInIt(vixl32::Register rd,vixl32::Register rn,int32_t value,vixl32::Condition cond)431*795d594fSAndroid Build Coastguard Worker void ArmVIXLAssembler::AddConstantInIt(vixl32::Register rd,
432*795d594fSAndroid Build Coastguard Worker                                        vixl32::Register rn,
433*795d594fSAndroid Build Coastguard Worker                                        int32_t value,
434*795d594fSAndroid Build Coastguard Worker                                        vixl32::Condition cond) {
435*795d594fSAndroid Build Coastguard Worker   DCHECK(vixl_masm_.InITBlock());
436*795d594fSAndroid Build Coastguard Worker   if (value == 0) {
437*795d594fSAndroid Build Coastguard Worker     ___ mov(cond, rd, rn);
438*795d594fSAndroid Build Coastguard Worker   } else {
439*795d594fSAndroid Build Coastguard Worker     ___ add(cond, rd, rn, value);
440*795d594fSAndroid Build Coastguard Worker   }
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker 
CompareAndBranchIfZero(vixl32::Register rn,vixl32::Label * label,bool is_far_target)443*795d594fSAndroid Build Coastguard Worker void ArmVIXLMacroAssembler::CompareAndBranchIfZero(vixl32::Register rn,
444*795d594fSAndroid Build Coastguard Worker                                                    vixl32::Label* label,
445*795d594fSAndroid Build Coastguard Worker                                                    bool is_far_target) {
446*795d594fSAndroid Build Coastguard Worker   if (!is_far_target && rn.IsLow() && !label->IsBound()) {
447*795d594fSAndroid Build Coastguard Worker     // In T32, Cbz/Cbnz instructions have following limitations:
448*795d594fSAndroid Build Coastguard Worker     // - There are only 7 bits (i:imm5:0) to encode branch target address (cannot be far target).
449*795d594fSAndroid Build Coastguard Worker     // - Only low registers (i.e R0 .. R7) can be encoded.
450*795d594fSAndroid Build Coastguard Worker     // - Only forward branches (unbound labels) are supported.
451*795d594fSAndroid Build Coastguard Worker     Cbz(rn, label);
452*795d594fSAndroid Build Coastguard Worker     return;
453*795d594fSAndroid Build Coastguard Worker   }
454*795d594fSAndroid Build Coastguard Worker   Cmp(rn, 0);
455*795d594fSAndroid Build Coastguard Worker   B(eq, label, is_far_target);
456*795d594fSAndroid Build Coastguard Worker }
457*795d594fSAndroid Build Coastguard Worker 
CompareAndBranchIfNonZero(vixl32::Register rn,vixl32::Label * label,bool is_far_target)458*795d594fSAndroid Build Coastguard Worker void ArmVIXLMacroAssembler::CompareAndBranchIfNonZero(vixl32::Register rn,
459*795d594fSAndroid Build Coastguard Worker                                                       vixl32::Label* label,
460*795d594fSAndroid Build Coastguard Worker                                                       bool is_far_target) {
461*795d594fSAndroid Build Coastguard Worker   if (!is_far_target && rn.IsLow() && !label->IsBound()) {
462*795d594fSAndroid Build Coastguard Worker     Cbnz(rn, label);
463*795d594fSAndroid Build Coastguard Worker     return;
464*795d594fSAndroid Build Coastguard Worker   }
465*795d594fSAndroid Build Coastguard Worker   Cmp(rn, 0);
466*795d594fSAndroid Build Coastguard Worker   B(ne, label, is_far_target);
467*795d594fSAndroid Build Coastguard Worker }
468*795d594fSAndroid Build Coastguard Worker 
B(vixl32::Label * label)469*795d594fSAndroid Build Coastguard Worker void ArmVIXLMacroAssembler::B(vixl32::Label* label) {
470*795d594fSAndroid Build Coastguard Worker   if (!label->IsBound()) {
471*795d594fSAndroid Build Coastguard Worker     // Try to use a 16-bit encoding of the B instruction.
472*795d594fSAndroid Build Coastguard Worker     DCHECK(OutsideITBlock());
473*795d594fSAndroid Build Coastguard Worker     BPreferNear(label);
474*795d594fSAndroid Build Coastguard Worker     return;
475*795d594fSAndroid Build Coastguard Worker   }
476*795d594fSAndroid Build Coastguard Worker   MacroAssembler::B(label);
477*795d594fSAndroid Build Coastguard Worker }
478*795d594fSAndroid Build Coastguard Worker 
B(vixl32::Condition cond,vixl32::Label * label,bool is_far_target)479*795d594fSAndroid Build Coastguard Worker void ArmVIXLMacroAssembler::B(vixl32::Condition cond, vixl32::Label* label, bool is_far_target) {
480*795d594fSAndroid Build Coastguard Worker   if (!label->IsBound() && !is_far_target) {
481*795d594fSAndroid Build Coastguard Worker     // Try to use a 16-bit encoding of the B instruction.
482*795d594fSAndroid Build Coastguard Worker     DCHECK(OutsideITBlock());
483*795d594fSAndroid Build Coastguard Worker     BPreferNear(cond, label);
484*795d594fSAndroid Build Coastguard Worker     return;
485*795d594fSAndroid Build Coastguard Worker   }
486*795d594fSAndroid Build Coastguard Worker   MacroAssembler::B(cond, label);
487*795d594fSAndroid Build Coastguard Worker }
488*795d594fSAndroid Build Coastguard Worker 
489*795d594fSAndroid Build Coastguard Worker }  // namespace arm
490*795d594fSAndroid Build Coastguard Worker }  // namespace art
491