xref: /aosp_15_r20/art/compiler/utils/arm64/assembler_arm64.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 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 "arch/arm64/instruction_set_features_arm64.h"
18*795d594fSAndroid Build Coastguard Worker #include "assembler_arm64.h"
19*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
20*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
21*795d594fSAndroid Build Coastguard Worker #include "offsets.h"
22*795d594fSAndroid Build Coastguard Worker #include "thread.h"
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker using namespace vixl::aarch64;  // NOLINT(build/namespaces)
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker namespace arm64 {
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker #ifdef ___
30*795d594fSAndroid Build Coastguard Worker #error "ARM64 Assembler macro already defined."
31*795d594fSAndroid Build Coastguard Worker #else
32*795d594fSAndroid Build Coastguard Worker #define ___   vixl_masm_.
33*795d594fSAndroid Build Coastguard Worker #endif
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker // Sets vixl::CPUFeatures according to ART instruction set features.
SetVIXLCPUFeaturesFromART(vixl::aarch64::MacroAssembler * vixl_masm_,const Arm64InstructionSetFeatures * art_features)36*795d594fSAndroid Build Coastguard Worker static void SetVIXLCPUFeaturesFromART(vixl::aarch64::MacroAssembler* vixl_masm_,
37*795d594fSAndroid Build Coastguard Worker                                       const Arm64InstructionSetFeatures* art_features) {
38*795d594fSAndroid Build Coastguard Worker   // Retrieve already initialized default features of vixl.
39*795d594fSAndroid Build Coastguard Worker   vixl::CPUFeatures* features = vixl_masm_->GetCPUFeatures();
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker   DCHECK(features->Has(vixl::CPUFeatures::kFP));
42*795d594fSAndroid Build Coastguard Worker   DCHECK(features->Has(vixl::CPUFeatures::kNEON));
43*795d594fSAndroid Build Coastguard Worker   DCHECK(art_features != nullptr);
44*795d594fSAndroid Build Coastguard Worker   if (art_features->HasCRC()) {
45*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kCRC32);
46*795d594fSAndroid Build Coastguard Worker   }
47*795d594fSAndroid Build Coastguard Worker   if (art_features->HasDotProd()) {
48*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kDotProduct);
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker   if (art_features->HasFP16()) {
51*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kFPHalf);
52*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kNEONHalf);
53*795d594fSAndroid Build Coastguard Worker   }
54*795d594fSAndroid Build Coastguard Worker   if (art_features->HasLSE()) {
55*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kAtomics);
56*795d594fSAndroid Build Coastguard Worker   }
57*795d594fSAndroid Build Coastguard Worker   if (art_features->HasSVE()) {
58*795d594fSAndroid Build Coastguard Worker     features->Combine(vixl::CPUFeatures::kSVE);
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker 
Arm64Assembler(ArenaAllocator * allocator,const Arm64InstructionSetFeatures * art_features)62*795d594fSAndroid Build Coastguard Worker Arm64Assembler::Arm64Assembler(ArenaAllocator* allocator,
63*795d594fSAndroid Build Coastguard Worker                                const Arm64InstructionSetFeatures* art_features)
64*795d594fSAndroid Build Coastguard Worker     : Assembler(allocator) {
65*795d594fSAndroid Build Coastguard Worker   if (art_features != nullptr) {
66*795d594fSAndroid Build Coastguard Worker     SetVIXLCPUFeaturesFromART(&vixl_masm_, art_features);
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker 
FinalizeCode()70*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::FinalizeCode() {
71*795d594fSAndroid Build Coastguard Worker   ___ FinalizeCode();
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker 
CodeSize() const74*795d594fSAndroid Build Coastguard Worker size_t Arm64Assembler::CodeSize() const {
75*795d594fSAndroid Build Coastguard Worker   return vixl_masm_.GetSizeOfCodeGenerated();
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker 
CodeBufferBaseAddress() const78*795d594fSAndroid Build Coastguard Worker const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
79*795d594fSAndroid Build Coastguard Worker   return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
80*795d594fSAndroid Build Coastguard Worker }
81*795d594fSAndroid Build Coastguard Worker 
CopyInstructions(const MemoryRegion & region)82*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::CopyInstructions(const MemoryRegion& region) {
83*795d594fSAndroid Build Coastguard Worker   // Copy the instructions from the buffer.
84*795d594fSAndroid Build Coastguard Worker   MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
85*795d594fSAndroid Build Coastguard Worker   region.CopyFrom(0, from);
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker 
LoadRawPtr(ManagedRegister m_dst,ManagedRegister m_base,Offset offs)88*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, Offset offs) {
89*795d594fSAndroid Build Coastguard Worker   Arm64ManagedRegister dst = m_dst.AsArm64();
90*795d594fSAndroid Build Coastguard Worker   Arm64ManagedRegister base = m_base.AsArm64();
91*795d594fSAndroid Build Coastguard Worker   CHECK(dst.IsXRegister() && base.IsXRegister());
92*795d594fSAndroid Build Coastguard Worker   // Remove dst and base form the temp list - higher level API uses IP1, IP0.
93*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(&vixl_masm_);
94*795d594fSAndroid Build Coastguard Worker   temps.Exclude(reg_x(dst.AsXRegister()), reg_x(base.AsXRegister()));
95*795d594fSAndroid Build Coastguard Worker   ___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker 
JumpTo(ManagedRegister m_base,Offset offs,ManagedRegister m_scratch)98*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) {
99*795d594fSAndroid Build Coastguard Worker   Arm64ManagedRegister base = m_base.AsArm64();
100*795d594fSAndroid Build Coastguard Worker   Arm64ManagedRegister scratch = m_scratch.AsArm64();
101*795d594fSAndroid Build Coastguard Worker   CHECK(base.IsXRegister()) << base;
102*795d594fSAndroid Build Coastguard Worker   CHECK(scratch.IsXRegister()) << scratch;
103*795d594fSAndroid Build Coastguard Worker   // Remove base and scratch form the temp list - higher level API uses IP1, IP0.
104*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(&vixl_masm_);
105*795d594fSAndroid Build Coastguard Worker   temps.Exclude(reg_x(base.AsXRegister()), reg_x(scratch.AsXRegister()));
106*795d594fSAndroid Build Coastguard Worker   ___ Ldr(reg_x(scratch.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
107*795d594fSAndroid Build Coastguard Worker   ___ Br(reg_x(scratch.AsXRegister()));
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
SpillRegisters(CPURegList registers,int offset)110*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::SpillRegisters(CPURegList registers, int offset) {
111*795d594fSAndroid Build Coastguard Worker   int size = registers.GetRegisterSizeInBytes();
112*795d594fSAndroid Build Coastguard Worker   const Register sp = vixl_masm_.StackPointer();
113*795d594fSAndroid Build Coastguard Worker   // Since we are operating on register pairs, we would like to align on
114*795d594fSAndroid Build Coastguard Worker   // double the standard size; on the other hand, we don't want to insert
115*795d594fSAndroid Build Coastguard Worker   // an extra store, which will happen if the number of registers is even.
116*795d594fSAndroid Build Coastguard Worker   if (!IsAlignedParam(offset, 2 * size) && registers.GetCount() % 2 != 0) {
117*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
118*795d594fSAndroid Build Coastguard Worker     ___ Str(dst0, MemOperand(sp, offset));
119*795d594fSAndroid Build Coastguard Worker     cfi_.RelOffset(DWARFReg(dst0), offset);
120*795d594fSAndroid Build Coastguard Worker     offset += size;
121*795d594fSAndroid Build Coastguard Worker   }
122*795d594fSAndroid Build Coastguard Worker   while (registers.GetCount() >= 2) {
123*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
124*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst1 = registers.PopLowestIndex();
125*795d594fSAndroid Build Coastguard Worker     ___ Stp(dst0, dst1, MemOperand(sp, offset));
126*795d594fSAndroid Build Coastguard Worker     cfi_.RelOffset(DWARFReg(dst0), offset);
127*795d594fSAndroid Build Coastguard Worker     cfi_.RelOffset(DWARFReg(dst1), offset + size);
128*795d594fSAndroid Build Coastguard Worker     offset += 2 * size;
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker   if (!registers.IsEmpty()) {
131*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
132*795d594fSAndroid Build Coastguard Worker     ___ Str(dst0, MemOperand(sp, offset));
133*795d594fSAndroid Build Coastguard Worker     cfi_.RelOffset(DWARFReg(dst0), offset);
134*795d594fSAndroid Build Coastguard Worker   }
135*795d594fSAndroid Build Coastguard Worker   DCHECK(registers.IsEmpty());
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker 
UnspillRegisters(CPURegList registers,int offset)138*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::UnspillRegisters(CPURegList registers, int offset) {
139*795d594fSAndroid Build Coastguard Worker   int size = registers.GetRegisterSizeInBytes();
140*795d594fSAndroid Build Coastguard Worker   const Register sp = vixl_masm_.StackPointer();
141*795d594fSAndroid Build Coastguard Worker   // Be consistent with the logic for spilling registers.
142*795d594fSAndroid Build Coastguard Worker   if (!IsAlignedParam(offset, 2 * size) && registers.GetCount() % 2 != 0) {
143*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
144*795d594fSAndroid Build Coastguard Worker     ___ Ldr(dst0, MemOperand(sp, offset));
145*795d594fSAndroid Build Coastguard Worker     cfi_.Restore(DWARFReg(dst0));
146*795d594fSAndroid Build Coastguard Worker     offset += size;
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker   while (registers.GetCount() >= 2) {
149*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
150*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst1 = registers.PopLowestIndex();
151*795d594fSAndroid Build Coastguard Worker     ___ Ldp(dst0, dst1, MemOperand(sp, offset));
152*795d594fSAndroid Build Coastguard Worker     cfi_.Restore(DWARFReg(dst0));
153*795d594fSAndroid Build Coastguard Worker     cfi_.Restore(DWARFReg(dst1));
154*795d594fSAndroid Build Coastguard Worker     offset += 2 * size;
155*795d594fSAndroid Build Coastguard Worker   }
156*795d594fSAndroid Build Coastguard Worker   if (!registers.IsEmpty()) {
157*795d594fSAndroid Build Coastguard Worker     const CPURegister& dst0 = registers.PopLowestIndex();
158*795d594fSAndroid Build Coastguard Worker     ___ Ldr(dst0, MemOperand(sp, offset));
159*795d594fSAndroid Build Coastguard Worker     cfi_.Restore(DWARFReg(dst0));
160*795d594fSAndroid Build Coastguard Worker   }
161*795d594fSAndroid Build Coastguard Worker   DCHECK(registers.IsEmpty());
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker 
PoisonHeapReference(Register reg)164*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::PoisonHeapReference(Register reg) {
165*795d594fSAndroid Build Coastguard Worker   DCHECK(reg.IsW());
166*795d594fSAndroid Build Coastguard Worker   // reg = -reg.
167*795d594fSAndroid Build Coastguard Worker   ___ Neg(reg, Operand(reg));
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker 
UnpoisonHeapReference(Register reg)170*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::UnpoisonHeapReference(Register reg) {
171*795d594fSAndroid Build Coastguard Worker   DCHECK(reg.IsW());
172*795d594fSAndroid Build Coastguard Worker   // reg = -reg.
173*795d594fSAndroid Build Coastguard Worker   ___ Neg(reg, Operand(reg));
174*795d594fSAndroid Build Coastguard Worker }
175*795d594fSAndroid Build Coastguard Worker 
MaybePoisonHeapReference(Register reg)176*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::MaybePoisonHeapReference(Register reg) {
177*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
178*795d594fSAndroid Build Coastguard Worker     PoisonHeapReference(reg);
179*795d594fSAndroid Build Coastguard Worker   }
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker 
MaybeUnpoisonHeapReference(Register reg)182*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::MaybeUnpoisonHeapReference(Register reg) {
183*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
184*795d594fSAndroid Build Coastguard Worker     UnpoisonHeapReference(reg);
185*795d594fSAndroid Build Coastguard Worker   }
186*795d594fSAndroid Build Coastguard Worker }
187*795d594fSAndroid Build Coastguard Worker 
GenerateMarkingRegisterCheck(Register temp,int code)188*795d594fSAndroid Build Coastguard Worker void Arm64Assembler::GenerateMarkingRegisterCheck(Register temp, int code) {
189*795d594fSAndroid Build Coastguard Worker   DCHECK(kReserveMarkingRegister);
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Register mr = reg_x(MR);  // Marking Register.
192*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Register tr = reg_x(TR);  // Thread Register.
193*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label mr_is_ok;
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker   // temp = self.tls32_.is.gc_marking
196*795d594fSAndroid Build Coastguard Worker   ___ Ldr(temp, MemOperand(tr, Thread::IsGcMarkingOffset<kArm64PointerSize>().Int32Value()));
197*795d594fSAndroid Build Coastguard Worker   // Check that mr == self.tls32_.is.gc_marking.
198*795d594fSAndroid Build Coastguard Worker   ___ Cmp(mr.W(), temp);
199*795d594fSAndroid Build Coastguard Worker   ___ B(eq, &mr_is_ok);
200*795d594fSAndroid Build Coastguard Worker   ___ Brk(code);
201*795d594fSAndroid Build Coastguard Worker   ___ Bind(&mr_is_ok);
202*795d594fSAndroid Build Coastguard Worker }
203*795d594fSAndroid Build Coastguard Worker 
204*795d594fSAndroid Build Coastguard Worker #undef ___
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker }  // namespace arm64
207*795d594fSAndroid Build Coastguard Worker }  // namespace art
208