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 "code_generator_arm64.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "aarch64/assembler-aarch64.h"
20*795d594fSAndroid Build Coastguard Worker #include "aarch64/registers-aarch64.h"
21*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/asm_support_arm64.h"
22*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/instruction_set_features_arm64.h"
23*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/jni_frame_arm64.h"
24*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils_iterator.h"
27*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "class_table.h"
29*795d594fSAndroid Build Coastguard Worker #include "code_generator_utils.h"
30*795d594fSAndroid Build Coastguard Worker #include "com_android_art_flags.h"
31*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
32*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
33*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints_enum.h"
34*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/card_table.h"
35*795d594fSAndroid Build Coastguard Worker #include "gc/space/image_space.h"
36*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
37*795d594fSAndroid Build Coastguard Worker #include "interpreter/mterp/nterp.h"
38*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
39*795d594fSAndroid Build Coastguard Worker #include "intrinsics_arm64.h"
40*795d594fSAndroid Build Coastguard Worker #include "intrinsics_list.h"
41*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
42*795d594fSAndroid Build Coastguard Worker #include "jit/profiling_info.h"
43*795d594fSAndroid Build Coastguard Worker #include "linker/linker_patch.h"
44*795d594fSAndroid Build Coastguard Worker #include "lock_word.h"
45*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
46*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
47*795d594fSAndroid Build Coastguard Worker #include "mirror/var_handle.h"
48*795d594fSAndroid Build Coastguard Worker #include "offsets.h"
49*795d594fSAndroid Build Coastguard Worker #include "optimizing/common_arm64.h"
50*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
51*795d594fSAndroid Build Coastguard Worker #include "profiling_info_builder.h"
52*795d594fSAndroid Build Coastguard Worker #include "thread.h"
53*795d594fSAndroid Build Coastguard Worker #include "trace.h"
54*795d594fSAndroid Build Coastguard Worker #include "utils/arm64/assembler_arm64.h"
55*795d594fSAndroid Build Coastguard Worker #include "utils/assembler.h"
56*795d594fSAndroid Build Coastguard Worker #include "utils/stack_checks.h"
57*795d594fSAndroid Build Coastguard Worker
58*795d594fSAndroid Build Coastguard Worker using namespace vixl::aarch64; // NOLINT(build/namespaces)
59*795d594fSAndroid Build Coastguard Worker using vixl::ExactAssemblyScope;
60*795d594fSAndroid Build Coastguard Worker using vixl::CodeBufferCheckScope;
61*795d594fSAndroid Build Coastguard Worker using vixl::EmissionCheckScope;
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker namespace art_flags = com::android::art::flags;
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker #ifdef __
66*795d594fSAndroid Build Coastguard Worker #error "ARM64 Codegen VIXL macro-assembler macro already defined."
67*795d594fSAndroid Build Coastguard Worker #endif
68*795d594fSAndroid Build Coastguard Worker
69*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker template<class MirrorType>
72*795d594fSAndroid Build Coastguard Worker class GcRoot;
73*795d594fSAndroid Build Coastguard Worker
74*795d594fSAndroid Build Coastguard Worker namespace arm64 {
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Worker using helpers::ARM64EncodableConstantOrRegister;
77*795d594fSAndroid Build Coastguard Worker using helpers::ArtVixlRegCodeCoherentForRegSet;
78*795d594fSAndroid Build Coastguard Worker using helpers::CPURegisterFrom;
79*795d594fSAndroid Build Coastguard Worker using helpers::DRegisterFrom;
80*795d594fSAndroid Build Coastguard Worker using helpers::FPRegisterFrom;
81*795d594fSAndroid Build Coastguard Worker using helpers::HeapOperand;
82*795d594fSAndroid Build Coastguard Worker using helpers::HeapOperandFrom;
83*795d594fSAndroid Build Coastguard Worker using helpers::InputCPURegisterOrZeroRegAt;
84*795d594fSAndroid Build Coastguard Worker using helpers::InputFPRegisterAt;
85*795d594fSAndroid Build Coastguard Worker using helpers::InputOperandAt;
86*795d594fSAndroid Build Coastguard Worker using helpers::InputRegisterAt;
87*795d594fSAndroid Build Coastguard Worker using helpers::Int64FromLocation;
88*795d594fSAndroid Build Coastguard Worker using helpers::LocationFrom;
89*795d594fSAndroid Build Coastguard Worker using helpers::OperandFromMemOperand;
90*795d594fSAndroid Build Coastguard Worker using helpers::OutputCPURegister;
91*795d594fSAndroid Build Coastguard Worker using helpers::OutputFPRegister;
92*795d594fSAndroid Build Coastguard Worker using helpers::OutputRegister;
93*795d594fSAndroid Build Coastguard Worker using helpers::RegisterFrom;
94*795d594fSAndroid Build Coastguard Worker using helpers::StackOperandFrom;
95*795d594fSAndroid Build Coastguard Worker using helpers::VIXLRegCodeFromART;
96*795d594fSAndroid Build Coastguard Worker using helpers::WRegisterFrom;
97*795d594fSAndroid Build Coastguard Worker using helpers::XRegisterFrom;
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker // TODO(mythria): Expand SystemRegister in vixl to include this value.
100*795d594fSAndroid Build Coastguard Worker uint16_t SYS_CNTVCT_EL0 = SystemRegisterEncoder<1, 3, 14, 0, 2>::value;
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker // The compare/jump sequence will generate about (1.5 * num_entries + 3) instructions. While jump
103*795d594fSAndroid Build Coastguard Worker // table version generates 7 instructions and num_entries literals. Compare/jump sequence will
104*795d594fSAndroid Build Coastguard Worker // generates less code/data with a small num_entries.
105*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
106*795d594fSAndroid Build Coastguard Worker
ARM64Condition(IfCondition cond)107*795d594fSAndroid Build Coastguard Worker inline Condition ARM64Condition(IfCondition cond) {
108*795d594fSAndroid Build Coastguard Worker switch (cond) {
109*795d594fSAndroid Build Coastguard Worker case kCondEQ: return eq;
110*795d594fSAndroid Build Coastguard Worker case kCondNE: return ne;
111*795d594fSAndroid Build Coastguard Worker case kCondLT: return lt;
112*795d594fSAndroid Build Coastguard Worker case kCondLE: return le;
113*795d594fSAndroid Build Coastguard Worker case kCondGT: return gt;
114*795d594fSAndroid Build Coastguard Worker case kCondGE: return ge;
115*795d594fSAndroid Build Coastguard Worker case kCondB: return lo;
116*795d594fSAndroid Build Coastguard Worker case kCondBE: return ls;
117*795d594fSAndroid Build Coastguard Worker case kCondA: return hi;
118*795d594fSAndroid Build Coastguard Worker case kCondAE: return hs;
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
121*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker
ARM64FPCondition(IfCondition cond,bool gt_bias)124*795d594fSAndroid Build Coastguard Worker inline Condition ARM64FPCondition(IfCondition cond, bool gt_bias) {
125*795d594fSAndroid Build Coastguard Worker // The ARM64 condition codes can express all the necessary branches, see the
126*795d594fSAndroid Build Coastguard Worker // "Meaning (floating-point)" column in the table C1-1 in the ARMv8 reference manual.
127*795d594fSAndroid Build Coastguard Worker // There is no dex instruction or HIR that would need the missing conditions
128*795d594fSAndroid Build Coastguard Worker // "equal or unordered" or "not equal".
129*795d594fSAndroid Build Coastguard Worker switch (cond) {
130*795d594fSAndroid Build Coastguard Worker case kCondEQ: return eq;
131*795d594fSAndroid Build Coastguard Worker case kCondNE: return ne /* unordered */;
132*795d594fSAndroid Build Coastguard Worker case kCondLT: return gt_bias ? cc : lt /* unordered */;
133*795d594fSAndroid Build Coastguard Worker case kCondLE: return gt_bias ? ls : le /* unordered */;
134*795d594fSAndroid Build Coastguard Worker case kCondGT: return gt_bias ? hi /* unordered */ : gt;
135*795d594fSAndroid Build Coastguard Worker case kCondGE: return gt_bias ? cs /* unordered */ : ge;
136*795d594fSAndroid Build Coastguard Worker default:
137*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "UNREACHABLE";
138*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker
ARM64PCondition(HVecPredToBoolean::PCondKind cond)142*795d594fSAndroid Build Coastguard Worker Condition ARM64PCondition(HVecPredToBoolean::PCondKind cond) {
143*795d594fSAndroid Build Coastguard Worker switch (cond) {
144*795d594fSAndroid Build Coastguard Worker case HVecPredToBoolean::PCondKind::kFirst: return mi;
145*795d594fSAndroid Build Coastguard Worker case HVecPredToBoolean::PCondKind::kNFirst: return pl;
146*795d594fSAndroid Build Coastguard Worker default:
147*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unsupported condition type: " << enum_cast<uint32_t>(cond);
148*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker }
151*795d594fSAndroid Build Coastguard Worker
ARM64ReturnLocation(DataType::Type return_type)152*795d594fSAndroid Build Coastguard Worker Location ARM64ReturnLocation(DataType::Type return_type) {
153*795d594fSAndroid Build Coastguard Worker // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
154*795d594fSAndroid Build Coastguard Worker // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
155*795d594fSAndroid Build Coastguard Worker // but we use the exact registers for clarity.
156*795d594fSAndroid Build Coastguard Worker if (return_type == DataType::Type::kFloat32) {
157*795d594fSAndroid Build Coastguard Worker return LocationFrom(s0);
158*795d594fSAndroid Build Coastguard Worker } else if (return_type == DataType::Type::kFloat64) {
159*795d594fSAndroid Build Coastguard Worker return LocationFrom(d0);
160*795d594fSAndroid Build Coastguard Worker } else if (return_type == DataType::Type::kInt64) {
161*795d594fSAndroid Build Coastguard Worker return LocationFrom(x0);
162*795d594fSAndroid Build Coastguard Worker } else if (return_type == DataType::Type::kVoid) {
163*795d594fSAndroid Build Coastguard Worker return Location::NoLocation();
164*795d594fSAndroid Build Coastguard Worker } else {
165*795d594fSAndroid Build Coastguard Worker return LocationFrom(w0);
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker
GetReturnLocation(DataType::Type return_type)169*795d594fSAndroid Build Coastguard Worker Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type return_type) {
170*795d594fSAndroid Build Coastguard Worker return ARM64ReturnLocation(return_type);
171*795d594fSAndroid Build Coastguard Worker }
172*795d594fSAndroid Build Coastguard Worker
OneRegInReferenceOutSaveEverythingCallerSaves()173*795d594fSAndroid Build Coastguard Worker static RegisterSet OneRegInReferenceOutSaveEverythingCallerSaves() {
174*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
175*795d594fSAndroid Build Coastguard Worker RegisterSet caller_saves = RegisterSet::Empty();
176*795d594fSAndroid Build Coastguard Worker caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
177*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(),
178*795d594fSAndroid Build Coastguard Worker RegisterFrom(calling_convention.GetReturnLocation(DataType::Type::kReference),
179*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference).GetCode());
180*795d594fSAndroid Build Coastguard Worker return caller_saves;
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker
183*795d594fSAndroid Build Coastguard Worker // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
184*795d594fSAndroid Build Coastguard Worker #define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()-> // NOLINT
185*795d594fSAndroid Build Coastguard Worker #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, x).Int32Value()
186*795d594fSAndroid Build Coastguard Worker
SaveLiveRegisters(CodeGenerator * codegen,LocationSummary * locations)187*795d594fSAndroid Build Coastguard Worker void SlowPathCodeARM64::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
188*795d594fSAndroid Build Coastguard Worker size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
189*795d594fSAndroid Build Coastguard Worker const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers= */ true);
190*795d594fSAndroid Build Coastguard Worker for (uint32_t i : LowToHighBits(core_spills)) {
191*795d594fSAndroid Build Coastguard Worker // If the register holds an object, update the stack mask.
192*795d594fSAndroid Build Coastguard Worker if (locations->RegisterContainsObject(i)) {
193*795d594fSAndroid Build Coastguard Worker locations->SetStackBit(stack_offset / kVRegSize);
194*795d594fSAndroid Build Coastguard Worker }
195*795d594fSAndroid Build Coastguard Worker DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
196*795d594fSAndroid Build Coastguard Worker DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
197*795d594fSAndroid Build Coastguard Worker saved_core_stack_offsets_[i] = stack_offset;
198*795d594fSAndroid Build Coastguard Worker stack_offset += kXRegSizeInBytes;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker const size_t fp_reg_size = codegen->GetSlowPathFPWidth();
202*795d594fSAndroid Build Coastguard Worker const uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers= */ false);
203*795d594fSAndroid Build Coastguard Worker for (uint32_t i : LowToHighBits(fp_spills)) {
204*795d594fSAndroid Build Coastguard Worker DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
205*795d594fSAndroid Build Coastguard Worker DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
206*795d594fSAndroid Build Coastguard Worker saved_fpu_stack_offsets_[i] = stack_offset;
207*795d594fSAndroid Build Coastguard Worker stack_offset += fp_reg_size;
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker
210*795d594fSAndroid Build Coastguard Worker InstructionCodeGeneratorARM64* visitor =
211*795d594fSAndroid Build Coastguard Worker down_cast<CodeGeneratorARM64*>(codegen)->GetInstructionCodeGeneratorArm64();
212*795d594fSAndroid Build Coastguard Worker visitor->SaveLiveRegistersHelper(locations, codegen->GetFirstRegisterSlotInSlowPath());
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker
RestoreLiveRegisters(CodeGenerator * codegen,LocationSummary * locations)215*795d594fSAndroid Build Coastguard Worker void SlowPathCodeARM64::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
216*795d594fSAndroid Build Coastguard Worker InstructionCodeGeneratorARM64* visitor =
217*795d594fSAndroid Build Coastguard Worker down_cast<CodeGeneratorARM64*>(codegen)->GetInstructionCodeGeneratorArm64();
218*795d594fSAndroid Build Coastguard Worker visitor->RestoreLiveRegistersHelper(locations, codegen->GetFirstRegisterSlotInSlowPath());
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker
221*795d594fSAndroid Build Coastguard Worker class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
222*795d594fSAndroid Build Coastguard Worker public:
BoundsCheckSlowPathARM64(HBoundsCheck * instruction)223*795d594fSAndroid Build Coastguard Worker explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction) : SlowPathCodeARM64(instruction) {}
224*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)225*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
226*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
227*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
228*795d594fSAndroid Build Coastguard Worker
229*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
230*795d594fSAndroid Build Coastguard Worker if (instruction_->CanThrowIntoCatchBlock()) {
231*795d594fSAndroid Build Coastguard Worker // Live registers will be restored in the catch block if caught.
232*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, instruction_->GetLocations());
233*795d594fSAndroid Build Coastguard Worker }
234*795d594fSAndroid Build Coastguard Worker // We're moving two locations to locations that could overlap, so we need a parallel
235*795d594fSAndroid Build Coastguard Worker // move resolver.
236*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
237*795d594fSAndroid Build Coastguard Worker codegen->EmitParallelMoves(locations->InAt(0),
238*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(0)),
239*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32,
240*795d594fSAndroid Build Coastguard Worker locations->InAt(1),
241*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(1)),
242*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32);
243*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
244*795d594fSAndroid Build Coastguard Worker ? kQuickThrowStringBounds
245*795d594fSAndroid Build Coastguard Worker : kQuickThrowArrayBounds;
246*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
247*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
248*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
249*795d594fSAndroid Build Coastguard Worker }
250*795d594fSAndroid Build Coastguard Worker
IsFatal() const251*795d594fSAndroid Build Coastguard Worker bool IsFatal() const override { return true; }
252*795d594fSAndroid Build Coastguard Worker
GetDescription() const253*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "BoundsCheckSlowPathARM64"; }
254*795d594fSAndroid Build Coastguard Worker
255*795d594fSAndroid Build Coastguard Worker private:
256*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
257*795d594fSAndroid Build Coastguard Worker };
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
260*795d594fSAndroid Build Coastguard Worker public:
DivZeroCheckSlowPathARM64(HDivZeroCheck * instruction)261*795d594fSAndroid Build Coastguard Worker explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : SlowPathCodeARM64(instruction) {}
262*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)263*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
264*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
265*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
266*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
267*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker
IsFatal() const270*795d594fSAndroid Build Coastguard Worker bool IsFatal() const override { return true; }
271*795d594fSAndroid Build Coastguard Worker
GetDescription() const272*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "DivZeroCheckSlowPathARM64"; }
273*795d594fSAndroid Build Coastguard Worker
274*795d594fSAndroid Build Coastguard Worker private:
275*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
276*795d594fSAndroid Build Coastguard Worker };
277*795d594fSAndroid Build Coastguard Worker
278*795d594fSAndroid Build Coastguard Worker class LoadMethodTypeSlowPathARM64 : public SlowPathCodeARM64 {
279*795d594fSAndroid Build Coastguard Worker public:
LoadMethodTypeSlowPathARM64(HLoadMethodType * mt)280*795d594fSAndroid Build Coastguard Worker explicit LoadMethodTypeSlowPathARM64(HLoadMethodType* mt) : SlowPathCodeARM64(mt) {}
281*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)282*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
283*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
284*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
285*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
286*795d594fSAndroid Build Coastguard Worker
287*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
288*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
289*795d594fSAndroid Build Coastguard Worker
290*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
291*795d594fSAndroid Build Coastguard Worker const dex::ProtoIndex proto_index = instruction_->AsLoadMethodType()->GetProtoIndex();
292*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0).W(), proto_index.index_);
293*795d594fSAndroid Build Coastguard Worker
294*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickResolveMethodType,
295*795d594fSAndroid Build Coastguard Worker instruction_,
296*795d594fSAndroid Build Coastguard Worker instruction_->GetDexPc(),
297*795d594fSAndroid Build Coastguard Worker this);
298*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
299*795d594fSAndroid Build Coastguard Worker
300*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction_->GetType();
301*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
302*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker
GetDescription() const307*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "LoadMethodTypeSlowPathARM64"; }
308*795d594fSAndroid Build Coastguard Worker
309*795d594fSAndroid Build Coastguard Worker private:
310*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(LoadMethodTypeSlowPathARM64);
311*795d594fSAndroid Build Coastguard Worker };
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker
314*795d594fSAndroid Build Coastguard Worker class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
315*795d594fSAndroid Build Coastguard Worker public:
LoadClassSlowPathARM64(HLoadClass * cls,HInstruction * at)316*795d594fSAndroid Build Coastguard Worker LoadClassSlowPathARM64(HLoadClass* cls, HInstruction* at)
317*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(at), cls_(cls) {
318*795d594fSAndroid Build Coastguard Worker DCHECK(at->IsLoadClass() || at->IsClinitCheck());
319*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
320*795d594fSAndroid Build Coastguard Worker }
321*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)322*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
323*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
324*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
325*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = instruction_->GetDexPc();
326*795d594fSAndroid Build Coastguard Worker bool must_resolve_type = instruction_->IsLoadClass() && cls_->MustResolveTypeOnSlowPath();
327*795d594fSAndroid Build Coastguard Worker bool must_do_clinit = instruction_->IsClinitCheck() || cls_->MustGenerateClinitCheck();
328*795d594fSAndroid Build Coastguard Worker
329*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
330*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
331*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
334*795d594fSAndroid Build Coastguard Worker if (must_resolve_type) {
335*795d594fSAndroid Build Coastguard Worker DCHECK(IsSameDexFile(cls_->GetDexFile(), arm64_codegen->GetGraph()->GetDexFile()) ||
336*795d594fSAndroid Build Coastguard Worker arm64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) ||
337*795d594fSAndroid Build Coastguard Worker ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(),
338*795d594fSAndroid Build Coastguard Worker &cls_->GetDexFile()));
339*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index = cls_->GetTypeIndex();
340*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0).W(), type_index.index_);
341*795d594fSAndroid Build Coastguard Worker if (cls_->NeedsAccessCheck()) {
342*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickResolveTypeAndVerifyAccess, void*, uint32_t>();
343*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickResolveTypeAndVerifyAccess, instruction_, dex_pc, this);
344*795d594fSAndroid Build Coastguard Worker } else {
345*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickResolveType, void*, uint32_t>();
346*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickResolveType, instruction_, dex_pc, this);
347*795d594fSAndroid Build Coastguard Worker }
348*795d594fSAndroid Build Coastguard Worker // If we also must_do_clinit, the resolved type is now in the correct register.
349*795d594fSAndroid Build Coastguard Worker } else {
350*795d594fSAndroid Build Coastguard Worker DCHECK(must_do_clinit);
351*795d594fSAndroid Build Coastguard Worker Location source = instruction_->IsLoadClass() ? out : locations->InAt(0);
352*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(LocationFrom(calling_convention.GetRegisterAt(0)),
353*795d594fSAndroid Build Coastguard Worker source,
354*795d594fSAndroid Build Coastguard Worker cls_->GetType());
355*795d594fSAndroid Build Coastguard Worker }
356*795d594fSAndroid Build Coastguard Worker if (must_do_clinit) {
357*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickInitializeStaticStorage, instruction_, dex_pc, this);
358*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, mirror::Class*>();
359*795d594fSAndroid Build Coastguard Worker }
360*795d594fSAndroid Build Coastguard Worker
361*795d594fSAndroid Build Coastguard Worker // Move the class to the desired location.
362*795d594fSAndroid Build Coastguard Worker if (out.IsValid()) {
363*795d594fSAndroid Build Coastguard Worker DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
364*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction_->GetType();
365*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
366*795d594fSAndroid Build Coastguard Worker }
367*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
368*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
369*795d594fSAndroid Build Coastguard Worker }
370*795d594fSAndroid Build Coastguard Worker
GetDescription() const371*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "LoadClassSlowPathARM64"; }
372*795d594fSAndroid Build Coastguard Worker
373*795d594fSAndroid Build Coastguard Worker private:
374*795d594fSAndroid Build Coastguard Worker // The class this slow path will load.
375*795d594fSAndroid Build Coastguard Worker HLoadClass* const cls_;
376*795d594fSAndroid Build Coastguard Worker
377*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
378*795d594fSAndroid Build Coastguard Worker };
379*795d594fSAndroid Build Coastguard Worker
380*795d594fSAndroid Build Coastguard Worker class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
381*795d594fSAndroid Build Coastguard Worker public:
LoadStringSlowPathARM64(HLoadString * instruction)382*795d594fSAndroid Build Coastguard Worker explicit LoadStringSlowPathARM64(HLoadString* instruction)
383*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction) {}
384*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)385*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
386*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
387*795d594fSAndroid Build Coastguard Worker DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
388*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
389*795d594fSAndroid Build Coastguard Worker
390*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
391*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
392*795d594fSAndroid Build Coastguard Worker
393*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
394*795d594fSAndroid Build Coastguard Worker const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
395*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0).W(), string_index.index_);
396*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
397*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
398*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction_->GetType();
399*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
400*795d594fSAndroid Build Coastguard Worker
401*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
402*795d594fSAndroid Build Coastguard Worker
403*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker
GetDescription() const406*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "LoadStringSlowPathARM64"; }
407*795d594fSAndroid Build Coastguard Worker
408*795d594fSAndroid Build Coastguard Worker private:
409*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
410*795d594fSAndroid Build Coastguard Worker };
411*795d594fSAndroid Build Coastguard Worker
412*795d594fSAndroid Build Coastguard Worker class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
413*795d594fSAndroid Build Coastguard Worker public:
NullCheckSlowPathARM64(HNullCheck * instr)414*795d594fSAndroid Build Coastguard Worker explicit NullCheckSlowPathARM64(HNullCheck* instr) : SlowPathCodeARM64(instr) {}
415*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)416*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
417*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
418*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
419*795d594fSAndroid Build Coastguard Worker if (instruction_->CanThrowIntoCatchBlock()) {
420*795d594fSAndroid Build Coastguard Worker // Live registers will be restored in the catch block if caught.
421*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, instruction_->GetLocations());
422*795d594fSAndroid Build Coastguard Worker }
423*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickThrowNullPointer,
424*795d594fSAndroid Build Coastguard Worker instruction_,
425*795d594fSAndroid Build Coastguard Worker instruction_->GetDexPc(),
426*795d594fSAndroid Build Coastguard Worker this);
427*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
428*795d594fSAndroid Build Coastguard Worker }
429*795d594fSAndroid Build Coastguard Worker
IsFatal() const430*795d594fSAndroid Build Coastguard Worker bool IsFatal() const override { return true; }
431*795d594fSAndroid Build Coastguard Worker
GetDescription() const432*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "NullCheckSlowPathARM64"; }
433*795d594fSAndroid Build Coastguard Worker
434*795d594fSAndroid Build Coastguard Worker private:
435*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
436*795d594fSAndroid Build Coastguard Worker };
437*795d594fSAndroid Build Coastguard Worker
438*795d594fSAndroid Build Coastguard Worker class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
439*795d594fSAndroid Build Coastguard Worker public:
SuspendCheckSlowPathARM64(HSuspendCheck * instruction,HBasicBlock * successor)440*795d594fSAndroid Build Coastguard Worker SuspendCheckSlowPathARM64(HSuspendCheck* instruction, HBasicBlock* successor)
441*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction), successor_(successor) {}
442*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)443*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
444*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
445*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
446*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
447*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations); // Only saves live vector regs for SIMD.
448*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
449*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickTestSuspend, void, void>();
450*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations); // Only restores live vector regs for SIMD.
451*795d594fSAndroid Build Coastguard Worker if (successor_ == nullptr) {
452*795d594fSAndroid Build Coastguard Worker __ B(GetReturnLabel());
453*795d594fSAndroid Build Coastguard Worker } else {
454*795d594fSAndroid Build Coastguard Worker __ B(arm64_codegen->GetLabelOf(successor_));
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker }
457*795d594fSAndroid Build Coastguard Worker
GetReturnLabel()458*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* GetReturnLabel() {
459*795d594fSAndroid Build Coastguard Worker DCHECK(successor_ == nullptr);
460*795d594fSAndroid Build Coastguard Worker return &return_label_;
461*795d594fSAndroid Build Coastguard Worker }
462*795d594fSAndroid Build Coastguard Worker
GetSuccessor() const463*795d594fSAndroid Build Coastguard Worker HBasicBlock* GetSuccessor() const {
464*795d594fSAndroid Build Coastguard Worker return successor_;
465*795d594fSAndroid Build Coastguard Worker }
466*795d594fSAndroid Build Coastguard Worker
GetDescription() const467*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "SuspendCheckSlowPathARM64"; }
468*795d594fSAndroid Build Coastguard Worker
469*795d594fSAndroid Build Coastguard Worker private:
470*795d594fSAndroid Build Coastguard Worker // If not null, the block to branch to after the suspend check.
471*795d594fSAndroid Build Coastguard Worker HBasicBlock* const successor_;
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker // If `successor_` is null, the label to branch to after the suspend check.
474*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_label_;
475*795d594fSAndroid Build Coastguard Worker
476*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
477*795d594fSAndroid Build Coastguard Worker };
478*795d594fSAndroid Build Coastguard Worker
479*795d594fSAndroid Build Coastguard Worker class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
480*795d594fSAndroid Build Coastguard Worker public:
TypeCheckSlowPathARM64(HInstruction * instruction,bool is_fatal)481*795d594fSAndroid Build Coastguard Worker TypeCheckSlowPathARM64(HInstruction* instruction, bool is_fatal)
482*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction), is_fatal_(is_fatal) {}
483*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)484*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
485*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
486*795d594fSAndroid Build Coastguard Worker
487*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsCheckCast()
488*795d594fSAndroid Build Coastguard Worker || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
489*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
490*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = instruction_->GetDexPc();
491*795d594fSAndroid Build Coastguard Worker
492*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
493*795d594fSAndroid Build Coastguard Worker
494*795d594fSAndroid Build Coastguard Worker if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
495*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
496*795d594fSAndroid Build Coastguard Worker }
497*795d594fSAndroid Build Coastguard Worker
498*795d594fSAndroid Build Coastguard Worker // We're moving two locations to locations that could overlap, so we need a parallel
499*795d594fSAndroid Build Coastguard Worker // move resolver.
500*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
501*795d594fSAndroid Build Coastguard Worker codegen->EmitParallelMoves(locations->InAt(0),
502*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(0)),
503*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference,
504*795d594fSAndroid Build Coastguard Worker locations->InAt(1),
505*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(1)),
506*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference);
507*795d594fSAndroid Build Coastguard Worker if (instruction_->IsInstanceOf()) {
508*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
509*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
510*795d594fSAndroid Build Coastguard Worker DataType::Type ret_type = instruction_->GetType();
511*795d594fSAndroid Build Coastguard Worker Location ret_loc = calling_convention.GetReturnLocation(ret_type);
512*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
513*795d594fSAndroid Build Coastguard Worker } else {
514*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsCheckCast());
515*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
516*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
517*795d594fSAndroid Build Coastguard Worker }
518*795d594fSAndroid Build Coastguard Worker
519*795d594fSAndroid Build Coastguard Worker if (!is_fatal_) {
520*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
521*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker }
524*795d594fSAndroid Build Coastguard Worker
GetDescription() const525*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "TypeCheckSlowPathARM64"; }
IsFatal() const526*795d594fSAndroid Build Coastguard Worker bool IsFatal() const override { return is_fatal_; }
527*795d594fSAndroid Build Coastguard Worker
528*795d594fSAndroid Build Coastguard Worker private:
529*795d594fSAndroid Build Coastguard Worker const bool is_fatal_;
530*795d594fSAndroid Build Coastguard Worker
531*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
532*795d594fSAndroid Build Coastguard Worker };
533*795d594fSAndroid Build Coastguard Worker
534*795d594fSAndroid Build Coastguard Worker class DeoptimizationSlowPathARM64 : public SlowPathCodeARM64 {
535*795d594fSAndroid Build Coastguard Worker public:
DeoptimizationSlowPathARM64(HDeoptimize * instruction)536*795d594fSAndroid Build Coastguard Worker explicit DeoptimizationSlowPathARM64(HDeoptimize* instruction)
537*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction) {}
538*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)539*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
540*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
541*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
542*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
543*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
544*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
545*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0),
546*795d594fSAndroid Build Coastguard Worker static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
547*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
548*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker
GetDescription() const551*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "DeoptimizationSlowPathARM64"; }
552*795d594fSAndroid Build Coastguard Worker
553*795d594fSAndroid Build Coastguard Worker private:
554*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM64);
555*795d594fSAndroid Build Coastguard Worker };
556*795d594fSAndroid Build Coastguard Worker
557*795d594fSAndroid Build Coastguard Worker class ArraySetSlowPathARM64 : public SlowPathCodeARM64 {
558*795d594fSAndroid Build Coastguard Worker public:
ArraySetSlowPathARM64(HInstruction * instruction)559*795d594fSAndroid Build Coastguard Worker explicit ArraySetSlowPathARM64(HInstruction* instruction) : SlowPathCodeARM64(instruction) {}
560*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)561*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
562*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
563*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
564*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
565*795d594fSAndroid Build Coastguard Worker
566*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
567*795d594fSAndroid Build Coastguard Worker HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
568*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(
569*795d594fSAndroid Build Coastguard Worker locations->InAt(0),
570*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(0)),
571*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference,
572*795d594fSAndroid Build Coastguard Worker nullptr);
573*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(
574*795d594fSAndroid Build Coastguard Worker locations->InAt(1),
575*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(1)),
576*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32,
577*795d594fSAndroid Build Coastguard Worker nullptr);
578*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(
579*795d594fSAndroid Build Coastguard Worker locations->InAt(2),
580*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(2)),
581*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference,
582*795d594fSAndroid Build Coastguard Worker nullptr);
583*795d594fSAndroid Build Coastguard Worker codegen->GetMoveResolver()->EmitNativeCode(¶llel_move);
584*795d594fSAndroid Build Coastguard Worker
585*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
586*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
587*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
588*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
589*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker
GetDescription() const592*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "ArraySetSlowPathARM64"; }
593*795d594fSAndroid Build Coastguard Worker
594*795d594fSAndroid Build Coastguard Worker private:
595*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM64);
596*795d594fSAndroid Build Coastguard Worker };
597*795d594fSAndroid Build Coastguard Worker
EmitTable(CodeGeneratorARM64 * codegen)598*795d594fSAndroid Build Coastguard Worker void JumpTableARM64::EmitTable(CodeGeneratorARM64* codegen) {
599*795d594fSAndroid Build Coastguard Worker uint32_t num_entries = switch_instr_->GetNumEntries();
600*795d594fSAndroid Build Coastguard Worker DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold);
601*795d594fSAndroid Build Coastguard Worker
602*795d594fSAndroid Build Coastguard Worker // We are about to use the assembler to place literals directly. Make sure we have enough
603*795d594fSAndroid Build Coastguard Worker // underlying code buffer and we have generated the jump table with right size.
604*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope scope(codegen->GetVIXLAssembler(),
605*795d594fSAndroid Build Coastguard Worker num_entries * sizeof(int32_t),
606*795d594fSAndroid Build Coastguard Worker CodeBufferCheckScope::kExactSize);
607*795d594fSAndroid Build Coastguard Worker codegen->GetVIXLAssembler()->bind(&table_start_);
608*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < num_entries; i++) {
609*795d594fSAndroid Build Coastguard Worker codegen->GetVIXLAssembler()->place(jump_targets_[i].get());
610*795d594fSAndroid Build Coastguard Worker }
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker
FixTable(CodeGeneratorARM64 * codegen)613*795d594fSAndroid Build Coastguard Worker void JumpTableARM64::FixTable(CodeGeneratorARM64* codegen) {
614*795d594fSAndroid Build Coastguard Worker uint32_t num_entries = switch_instr_->GetNumEntries();
615*795d594fSAndroid Build Coastguard Worker DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold);
616*795d594fSAndroid Build Coastguard Worker
617*795d594fSAndroid Build Coastguard Worker const ArenaVector<HBasicBlock*>& successors = switch_instr_->GetBlock()->GetSuccessors();
618*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < num_entries; i++) {
619*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* target_label = codegen->GetLabelOf(successors[i]);
620*795d594fSAndroid Build Coastguard Worker DCHECK(target_label->IsBound());
621*795d594fSAndroid Build Coastguard Worker ptrdiff_t jump_offset = target_label->GetLocation() - table_start_.GetLocation();
622*795d594fSAndroid Build Coastguard Worker DCHECK_GT(jump_offset, std::numeric_limits<int32_t>::min());
623*795d594fSAndroid Build Coastguard Worker DCHECK_LE(jump_offset, std::numeric_limits<int32_t>::max());
624*795d594fSAndroid Build Coastguard Worker jump_targets_[i].get()->UpdateValue(jump_offset, codegen->GetVIXLAssembler());
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker }
627*795d594fSAndroid Build Coastguard Worker
628*795d594fSAndroid Build Coastguard Worker // Slow path generating a read barrier for a heap reference.
629*795d594fSAndroid Build Coastguard Worker class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 {
630*795d594fSAndroid Build Coastguard Worker public:
ReadBarrierForHeapReferenceSlowPathARM64(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)631*795d594fSAndroid Build Coastguard Worker ReadBarrierForHeapReferenceSlowPathARM64(HInstruction* instruction,
632*795d594fSAndroid Build Coastguard Worker Location out,
633*795d594fSAndroid Build Coastguard Worker Location ref,
634*795d594fSAndroid Build Coastguard Worker Location obj,
635*795d594fSAndroid Build Coastguard Worker uint32_t offset,
636*795d594fSAndroid Build Coastguard Worker Location index)
637*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction),
638*795d594fSAndroid Build Coastguard Worker out_(out),
639*795d594fSAndroid Build Coastguard Worker ref_(ref),
640*795d594fSAndroid Build Coastguard Worker obj_(obj),
641*795d594fSAndroid Build Coastguard Worker offset_(offset),
642*795d594fSAndroid Build Coastguard Worker index_(index) {
643*795d594fSAndroid Build Coastguard Worker // If `obj` is equal to `out` or `ref`, it means the initial object
644*795d594fSAndroid Build Coastguard Worker // has been overwritten by (or after) the heap object reference load
645*795d594fSAndroid Build Coastguard Worker // to be instrumented, e.g.:
646*795d594fSAndroid Build Coastguard Worker //
647*795d594fSAndroid Build Coastguard Worker // __ Ldr(out, HeapOperand(out, class_offset);
648*795d594fSAndroid Build Coastguard Worker // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
649*795d594fSAndroid Build Coastguard Worker //
650*795d594fSAndroid Build Coastguard Worker // In that case, we have lost the information about the original
651*795d594fSAndroid Build Coastguard Worker // object, and the emitted read barrier cannot work properly.
652*795d594fSAndroid Build Coastguard Worker DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
653*795d594fSAndroid Build Coastguard Worker DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)656*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
657*795d594fSAndroid Build Coastguard Worker DCHECK(codegen->EmitReadBarrier());
658*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
659*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
660*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Type::kReference;
661*795d594fSAndroid Build Coastguard Worker DCHECK(locations->CanCall());
662*795d594fSAndroid Build Coastguard Worker DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
663*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsInstanceFieldGet() ||
664*795d594fSAndroid Build Coastguard Worker instruction_->IsStaticFieldGet() ||
665*795d594fSAndroid Build Coastguard Worker instruction_->IsArrayGet() ||
666*795d594fSAndroid Build Coastguard Worker instruction_->IsInstanceOf() ||
667*795d594fSAndroid Build Coastguard Worker instruction_->IsCheckCast() ||
668*795d594fSAndroid Build Coastguard Worker (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
669*795d594fSAndroid Build Coastguard Worker << "Unexpected instruction in read barrier for heap reference slow path: "
670*795d594fSAndroid Build Coastguard Worker << instruction_->DebugName();
671*795d594fSAndroid Build Coastguard Worker // The read barrier instrumentation of object ArrayGet
672*795d594fSAndroid Build Coastguard Worker // instructions does not support the HIntermediateAddress
673*795d594fSAndroid Build Coastguard Worker // instruction.
674*795d594fSAndroid Build Coastguard Worker DCHECK(!(instruction_->IsArrayGet() &&
675*795d594fSAndroid Build Coastguard Worker instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
676*795d594fSAndroid Build Coastguard Worker
677*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
678*795d594fSAndroid Build Coastguard Worker
679*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
680*795d594fSAndroid Build Coastguard Worker
681*795d594fSAndroid Build Coastguard Worker // We may have to change the index's value, but as `index_` is a
682*795d594fSAndroid Build Coastguard Worker // constant member (like other "inputs" of this slow path),
683*795d594fSAndroid Build Coastguard Worker // introduce a copy of it, `index`.
684*795d594fSAndroid Build Coastguard Worker Location index = index_;
685*795d594fSAndroid Build Coastguard Worker if (index_.IsValid()) {
686*795d594fSAndroid Build Coastguard Worker // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
687*795d594fSAndroid Build Coastguard Worker if (instruction_->IsArrayGet()) {
688*795d594fSAndroid Build Coastguard Worker // Compute the actual memory offset and store it in `index`.
689*795d594fSAndroid Build Coastguard Worker Register index_reg = RegisterFrom(index_, DataType::Type::kInt32);
690*795d594fSAndroid Build Coastguard Worker DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_.reg()));
691*795d594fSAndroid Build Coastguard Worker if (codegen->IsCoreCalleeSaveRegister(index_.reg())) {
692*795d594fSAndroid Build Coastguard Worker // We are about to change the value of `index_reg` (see the
693*795d594fSAndroid Build Coastguard Worker // calls to vixl::MacroAssembler::Lsl and
694*795d594fSAndroid Build Coastguard Worker // vixl::MacroAssembler::Mov below), but it has
695*795d594fSAndroid Build Coastguard Worker // not been saved by the previous call to
696*795d594fSAndroid Build Coastguard Worker // art::SlowPathCode::SaveLiveRegisters, as it is a
697*795d594fSAndroid Build Coastguard Worker // callee-save register --
698*795d594fSAndroid Build Coastguard Worker // art::SlowPathCode::SaveLiveRegisters does not consider
699*795d594fSAndroid Build Coastguard Worker // callee-save registers, as it has been designed with the
700*795d594fSAndroid Build Coastguard Worker // assumption that callee-save registers are supposed to be
701*795d594fSAndroid Build Coastguard Worker // handled by the called function. So, as a callee-save
702*795d594fSAndroid Build Coastguard Worker // register, `index_reg` _would_ eventually be saved onto
703*795d594fSAndroid Build Coastguard Worker // the stack, but it would be too late: we would have
704*795d594fSAndroid Build Coastguard Worker // changed its value earlier. Therefore, we manually save
705*795d594fSAndroid Build Coastguard Worker // it here into another freely available register,
706*795d594fSAndroid Build Coastguard Worker // `free_reg`, chosen of course among the caller-save
707*795d594fSAndroid Build Coastguard Worker // registers (as a callee-save `free_reg` register would
708*795d594fSAndroid Build Coastguard Worker // exhibit the same problem).
709*795d594fSAndroid Build Coastguard Worker //
710*795d594fSAndroid Build Coastguard Worker // Note we could have requested a temporary register from
711*795d594fSAndroid Build Coastguard Worker // the register allocator instead; but we prefer not to, as
712*795d594fSAndroid Build Coastguard Worker // this is a slow path, and we know we can find a
713*795d594fSAndroid Build Coastguard Worker // caller-save register that is available.
714*795d594fSAndroid Build Coastguard Worker Register free_reg = FindAvailableCallerSaveRegister(codegen);
715*795d594fSAndroid Build Coastguard Worker __ Mov(free_reg.W(), index_reg);
716*795d594fSAndroid Build Coastguard Worker index_reg = free_reg;
717*795d594fSAndroid Build Coastguard Worker index = LocationFrom(index_reg);
718*795d594fSAndroid Build Coastguard Worker } else {
719*795d594fSAndroid Build Coastguard Worker // The initial register stored in `index_` has already been
720*795d594fSAndroid Build Coastguard Worker // saved in the call to art::SlowPathCode::SaveLiveRegisters
721*795d594fSAndroid Build Coastguard Worker // (as it is not a callee-save register), so we can freely
722*795d594fSAndroid Build Coastguard Worker // use it.
723*795d594fSAndroid Build Coastguard Worker }
724*795d594fSAndroid Build Coastguard Worker // Shifting the index value contained in `index_reg` by the scale
725*795d594fSAndroid Build Coastguard Worker // factor (2) cannot overflow in practice, as the runtime is
726*795d594fSAndroid Build Coastguard Worker // unable to allocate object arrays with a size larger than
727*795d594fSAndroid Build Coastguard Worker // 2^26 - 1 (that is, 2^28 - 4 bytes).
728*795d594fSAndroid Build Coastguard Worker __ Lsl(index_reg, index_reg, DataType::SizeShift(type));
729*795d594fSAndroid Build Coastguard Worker static_assert(
730*795d594fSAndroid Build Coastguard Worker sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
731*795d594fSAndroid Build Coastguard Worker "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
732*795d594fSAndroid Build Coastguard Worker __ Add(index_reg, index_reg, Operand(offset_));
733*795d594fSAndroid Build Coastguard Worker } else {
734*795d594fSAndroid Build Coastguard Worker // In the case of the following intrinsics `index_` is not shifted by a scale factor of 2
735*795d594fSAndroid Build Coastguard Worker // (as in the case of ArrayGet), as it is actually an offset to an object field within an
736*795d594fSAndroid Build Coastguard Worker // object.
737*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
738*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->GetLocations()->Intrinsified());
739*795d594fSAndroid Build Coastguard Worker HInvoke* invoke = instruction_->AsInvoke();
740*795d594fSAndroid Build Coastguard Worker DCHECK(IsUnsafeGetReference(invoke) ||
741*795d594fSAndroid Build Coastguard Worker IsVarHandleGet(invoke) ||
742*795d594fSAndroid Build Coastguard Worker IsUnsafeCASReference(invoke) ||
743*795d594fSAndroid Build Coastguard Worker IsVarHandleCASFamily(invoke)) << invoke->GetIntrinsic();
744*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(offset_, 0u);
745*795d594fSAndroid Build Coastguard Worker DCHECK(index_.IsRegister());
746*795d594fSAndroid Build Coastguard Worker }
747*795d594fSAndroid Build Coastguard Worker }
748*795d594fSAndroid Build Coastguard Worker
749*795d594fSAndroid Build Coastguard Worker // We're moving two or three locations to locations that could
750*795d594fSAndroid Build Coastguard Worker // overlap, so we need a parallel move resolver.
751*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
752*795d594fSAndroid Build Coastguard Worker HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
753*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(ref_,
754*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(0)),
755*795d594fSAndroid Build Coastguard Worker type,
756*795d594fSAndroid Build Coastguard Worker nullptr);
757*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(obj_,
758*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(1)),
759*795d594fSAndroid Build Coastguard Worker type,
760*795d594fSAndroid Build Coastguard Worker nullptr);
761*795d594fSAndroid Build Coastguard Worker if (index.IsValid()) {
762*795d594fSAndroid Build Coastguard Worker parallel_move.AddMove(index,
763*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(2)),
764*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32,
765*795d594fSAndroid Build Coastguard Worker nullptr);
766*795d594fSAndroid Build Coastguard Worker codegen->GetMoveResolver()->EmitNativeCode(¶llel_move);
767*795d594fSAndroid Build Coastguard Worker } else {
768*795d594fSAndroid Build Coastguard Worker codegen->GetMoveResolver()->EmitNativeCode(¶llel_move);
769*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveConstant(LocationFrom(calling_convention.GetRegisterAt(2)), offset_);
770*795d594fSAndroid Build Coastguard Worker }
771*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
772*795d594fSAndroid Build Coastguard Worker instruction_,
773*795d594fSAndroid Build Coastguard Worker instruction_->GetDexPc(),
774*795d594fSAndroid Build Coastguard Worker this);
775*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<
776*795d594fSAndroid Build Coastguard Worker kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
777*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(out_, calling_convention.GetReturnLocation(type), type);
778*795d594fSAndroid Build Coastguard Worker
779*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
780*795d594fSAndroid Build Coastguard Worker
781*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker
GetDescription() const784*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "ReadBarrierForHeapReferenceSlowPathARM64"; }
785*795d594fSAndroid Build Coastguard Worker
786*795d594fSAndroid Build Coastguard Worker private:
FindAvailableCallerSaveRegister(CodeGenerator * codegen)787*795d594fSAndroid Build Coastguard Worker Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
788*795d594fSAndroid Build Coastguard Worker size_t ref = static_cast<int>(XRegisterFrom(ref_).GetCode());
789*795d594fSAndroid Build Coastguard Worker size_t obj = static_cast<int>(XRegisterFrom(obj_).GetCode());
790*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
791*795d594fSAndroid Build Coastguard Worker if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
792*795d594fSAndroid Build Coastguard Worker return Register(VIXLRegCodeFromART(i), kXRegSize);
793*795d594fSAndroid Build Coastguard Worker }
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker // We shall never fail to find a free caller-save register, as
796*795d594fSAndroid Build Coastguard Worker // there are more than two core caller-save registers on ARM64
797*795d594fSAndroid Build Coastguard Worker // (meaning it is possible to find one which is different from
798*795d594fSAndroid Build Coastguard Worker // `ref` and `obj`).
799*795d594fSAndroid Build Coastguard Worker DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
800*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Could not find a free register";
801*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
802*795d594fSAndroid Build Coastguard Worker }
803*795d594fSAndroid Build Coastguard Worker
804*795d594fSAndroid Build Coastguard Worker const Location out_;
805*795d594fSAndroid Build Coastguard Worker const Location ref_;
806*795d594fSAndroid Build Coastguard Worker const Location obj_;
807*795d594fSAndroid Build Coastguard Worker const uint32_t offset_;
808*795d594fSAndroid Build Coastguard Worker // An additional location containing an index to an array.
809*795d594fSAndroid Build Coastguard Worker // Only used for HArrayGet and the UnsafeGetObject &
810*795d594fSAndroid Build Coastguard Worker // UnsafeGetObjectVolatile intrinsics.
811*795d594fSAndroid Build Coastguard Worker const Location index_;
812*795d594fSAndroid Build Coastguard Worker
813*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM64);
814*795d594fSAndroid Build Coastguard Worker };
815*795d594fSAndroid Build Coastguard Worker
816*795d594fSAndroid Build Coastguard Worker // Slow path generating a read barrier for a GC root.
817*795d594fSAndroid Build Coastguard Worker class ReadBarrierForRootSlowPathARM64 : public SlowPathCodeARM64 {
818*795d594fSAndroid Build Coastguard Worker public:
ReadBarrierForRootSlowPathARM64(HInstruction * instruction,Location out,Location root)819*795d594fSAndroid Build Coastguard Worker ReadBarrierForRootSlowPathARM64(HInstruction* instruction, Location out, Location root)
820*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction), out_(out), root_(root) {
821*795d594fSAndroid Build Coastguard Worker }
822*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)823*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
824*795d594fSAndroid Build Coastguard Worker DCHECK(codegen->EmitReadBarrier());
825*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
826*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Type::kReference;
827*795d594fSAndroid Build Coastguard Worker DCHECK(locations->CanCall());
828*795d594fSAndroid Build Coastguard Worker DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
829*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsLoadClass() ||
830*795d594fSAndroid Build Coastguard Worker instruction_->IsLoadString() ||
831*795d594fSAndroid Build Coastguard Worker (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
832*795d594fSAndroid Build Coastguard Worker << "Unexpected instruction in read barrier for GC root slow path: "
833*795d594fSAndroid Build Coastguard Worker << instruction_->DebugName();
834*795d594fSAndroid Build Coastguard Worker
835*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
836*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
837*795d594fSAndroid Build Coastguard Worker
838*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
839*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
840*795d594fSAndroid Build Coastguard Worker // The argument of the ReadBarrierForRootSlow is not a managed
841*795d594fSAndroid Build Coastguard Worker // reference (`mirror::Object*`), but a `GcRoot<mirror::Object>*`;
842*795d594fSAndroid Build Coastguard Worker // thus we need a 64-bit move here, and we cannot use
843*795d594fSAndroid Build Coastguard Worker //
844*795d594fSAndroid Build Coastguard Worker // arm64_codegen->MoveLocation(
845*795d594fSAndroid Build Coastguard Worker // LocationFrom(calling_convention.GetRegisterAt(0)),
846*795d594fSAndroid Build Coastguard Worker // root_,
847*795d594fSAndroid Build Coastguard Worker // type);
848*795d594fSAndroid Build Coastguard Worker //
849*795d594fSAndroid Build Coastguard Worker // which would emit a 32-bit move, as `type` is a (32-bit wide)
850*795d594fSAndroid Build Coastguard Worker // reference type (`DataType::Type::kReference`).
851*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0), XRegisterFrom(out_));
852*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
853*795d594fSAndroid Build Coastguard Worker instruction_,
854*795d594fSAndroid Build Coastguard Worker instruction_->GetDexPc(),
855*795d594fSAndroid Build Coastguard Worker this);
856*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
857*795d594fSAndroid Build Coastguard Worker arm64_codegen->MoveLocation(out_, calling_convention.GetReturnLocation(type), type);
858*795d594fSAndroid Build Coastguard Worker
859*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
860*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
861*795d594fSAndroid Build Coastguard Worker }
862*795d594fSAndroid Build Coastguard Worker
GetDescription() const863*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "ReadBarrierForRootSlowPathARM64"; }
864*795d594fSAndroid Build Coastguard Worker
865*795d594fSAndroid Build Coastguard Worker private:
866*795d594fSAndroid Build Coastguard Worker const Location out_;
867*795d594fSAndroid Build Coastguard Worker const Location root_;
868*795d594fSAndroid Build Coastguard Worker
869*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM64);
870*795d594fSAndroid Build Coastguard Worker };
871*795d594fSAndroid Build Coastguard Worker
872*795d594fSAndroid Build Coastguard Worker class TracingMethodEntryExitHooksSlowPathARM64 : public SlowPathCodeARM64 {
873*795d594fSAndroid Build Coastguard Worker public:
TracingMethodEntryExitHooksSlowPathARM64(bool is_method_entry)874*795d594fSAndroid Build Coastguard Worker explicit TracingMethodEntryExitHooksSlowPathARM64(bool is_method_entry)
875*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(/* instruction= */ nullptr), is_method_entry_(is_method_entry) {}
876*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)877*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
878*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum entry_point =
879*795d594fSAndroid Build Coastguard Worker (is_method_entry_) ? kQuickRecordEntryTraceEvent : kQuickRecordExitTraceEvent;
880*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label call;
881*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
882*795d594fSAndroid Build Coastguard Worker uint32_t entrypoint_offset = GetThreadOffset<kArm64PointerSize>(entry_point).Int32Value();
883*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(tr, entrypoint_offset));
884*795d594fSAndroid Build Coastguard Worker __ Blr(lr);
885*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
886*795d594fSAndroid Build Coastguard Worker }
887*795d594fSAndroid Build Coastguard Worker
GetDescription() const888*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override {
889*795d594fSAndroid Build Coastguard Worker return "TracingMethodEntryExitHooksSlowPath";
890*795d594fSAndroid Build Coastguard Worker }
891*795d594fSAndroid Build Coastguard Worker
892*795d594fSAndroid Build Coastguard Worker private:
893*795d594fSAndroid Build Coastguard Worker const bool is_method_entry_;
894*795d594fSAndroid Build Coastguard Worker
895*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(TracingMethodEntryExitHooksSlowPathARM64);
896*795d594fSAndroid Build Coastguard Worker };
897*795d594fSAndroid Build Coastguard Worker
898*795d594fSAndroid Build Coastguard Worker class MethodEntryExitHooksSlowPathARM64 : public SlowPathCodeARM64 {
899*795d594fSAndroid Build Coastguard Worker public:
MethodEntryExitHooksSlowPathARM64(HInstruction * instruction)900*795d594fSAndroid Build Coastguard Worker explicit MethodEntryExitHooksSlowPathARM64(HInstruction* instruction)
901*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(instruction) {}
902*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)903*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
904*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
905*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum entry_point =
906*795d594fSAndroid Build Coastguard Worker (instruction_->IsMethodEntryHook()) ? kQuickMethodEntryHook : kQuickMethodExitHook;
907*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
908*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
909*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, locations);
910*795d594fSAndroid Build Coastguard Worker if (instruction_->IsMethodExitHook()) {
911*795d594fSAndroid Build Coastguard Worker __ Mov(vixl::aarch64::x4, arm64_codegen->GetFrameSize());
912*795d594fSAndroid Build Coastguard Worker }
913*795d594fSAndroid Build Coastguard Worker arm64_codegen->InvokeRuntime(entry_point, instruction_, instruction_->GetDexPc(), this);
914*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, locations);
915*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
916*795d594fSAndroid Build Coastguard Worker }
917*795d594fSAndroid Build Coastguard Worker
GetDescription() const918*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override {
919*795d594fSAndroid Build Coastguard Worker return "MethodEntryExitHooksSlowPath";
920*795d594fSAndroid Build Coastguard Worker }
921*795d594fSAndroid Build Coastguard Worker
922*795d594fSAndroid Build Coastguard Worker private:
923*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(MethodEntryExitHooksSlowPathARM64);
924*795d594fSAndroid Build Coastguard Worker };
925*795d594fSAndroid Build Coastguard Worker
926*795d594fSAndroid Build Coastguard Worker class CompileOptimizedSlowPathARM64 : public SlowPathCodeARM64 {
927*795d594fSAndroid Build Coastguard Worker public:
CompileOptimizedSlowPathARM64(HSuspendCheck * check,Register profiling_info)928*795d594fSAndroid Build Coastguard Worker CompileOptimizedSlowPathARM64(HSuspendCheck* check, Register profiling_info)
929*795d594fSAndroid Build Coastguard Worker : SlowPathCodeARM64(check),
930*795d594fSAndroid Build Coastguard Worker profiling_info_(profiling_info) {}
931*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)932*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
933*795d594fSAndroid Build Coastguard Worker uint32_t entrypoint_offset =
934*795d594fSAndroid Build Coastguard Worker GetThreadOffset<kArm64PointerSize>(kQuickCompileOptimized).Int32Value();
935*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
936*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
937*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler());
938*795d594fSAndroid Build Coastguard Worker Register counter = temps.AcquireW();
939*795d594fSAndroid Build Coastguard Worker __ Mov(counter, ProfilingInfo::GetOptimizeThreshold());
940*795d594fSAndroid Build Coastguard Worker __ Strh(counter,
941*795d594fSAndroid Build Coastguard Worker MemOperand(profiling_info_, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()));
942*795d594fSAndroid Build Coastguard Worker if (instruction_ != nullptr) {
943*795d594fSAndroid Build Coastguard Worker // Only saves live vector regs for SIMD.
944*795d594fSAndroid Build Coastguard Worker SaveLiveRegisters(codegen, instruction_->GetLocations());
945*795d594fSAndroid Build Coastguard Worker }
946*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(tr, entrypoint_offset));
947*795d594fSAndroid Build Coastguard Worker // Note: we don't record the call here (and therefore don't generate a stack
948*795d594fSAndroid Build Coastguard Worker // map), as the entrypoint should never be suspended.
949*795d594fSAndroid Build Coastguard Worker __ Blr(lr);
950*795d594fSAndroid Build Coastguard Worker if (instruction_ != nullptr) {
951*795d594fSAndroid Build Coastguard Worker // Only restores live vector regs for SIMD.
952*795d594fSAndroid Build Coastguard Worker RestoreLiveRegisters(codegen, instruction_->GetLocations());
953*795d594fSAndroid Build Coastguard Worker }
954*795d594fSAndroid Build Coastguard Worker __ B(GetExitLabel());
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker
GetDescription() const957*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override {
958*795d594fSAndroid Build Coastguard Worker return "CompileOptimizedSlowPath";
959*795d594fSAndroid Build Coastguard Worker }
960*795d594fSAndroid Build Coastguard Worker
961*795d594fSAndroid Build Coastguard Worker private:
962*795d594fSAndroid Build Coastguard Worker // The register where the profiling info is stored when entering the slow
963*795d594fSAndroid Build Coastguard Worker // path.
964*795d594fSAndroid Build Coastguard Worker Register profiling_info_;
965*795d594fSAndroid Build Coastguard Worker
966*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(CompileOptimizedSlowPathARM64);
967*795d594fSAndroid Build Coastguard Worker };
968*795d594fSAndroid Build Coastguard Worker
969*795d594fSAndroid Build Coastguard Worker #undef __
970*795d594fSAndroid Build Coastguard Worker
GetNextLocation(DataType::Type type)971*795d594fSAndroid Build Coastguard Worker Location InvokeDexCallingConventionVisitorARM64::GetNextLocation(DataType::Type type) {
972*795d594fSAndroid Build Coastguard Worker Location next_location;
973*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kVoid) {
974*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable type " << type;
975*795d594fSAndroid Build Coastguard Worker }
976*795d594fSAndroid Build Coastguard Worker
977*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type) &&
978*795d594fSAndroid Build Coastguard Worker (float_index_ < calling_convention.GetNumberOfFpuRegisters())) {
979*795d594fSAndroid Build Coastguard Worker next_location = LocationFrom(calling_convention.GetFpuRegisterAt(float_index_++));
980*795d594fSAndroid Build Coastguard Worker } else if (!DataType::IsFloatingPointType(type) &&
981*795d594fSAndroid Build Coastguard Worker (gp_index_ < calling_convention.GetNumberOfRegisters())) {
982*795d594fSAndroid Build Coastguard Worker next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
983*795d594fSAndroid Build Coastguard Worker } else {
984*795d594fSAndroid Build Coastguard Worker size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
985*795d594fSAndroid Build Coastguard Worker next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
986*795d594fSAndroid Build Coastguard Worker : Location::StackSlot(stack_offset);
987*795d594fSAndroid Build Coastguard Worker }
988*795d594fSAndroid Build Coastguard Worker
989*795d594fSAndroid Build Coastguard Worker // Space on the stack is reserved for all arguments.
990*795d594fSAndroid Build Coastguard Worker stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
991*795d594fSAndroid Build Coastguard Worker return next_location;
992*795d594fSAndroid Build Coastguard Worker }
993*795d594fSAndroid Build Coastguard Worker
GetMethodLocation() const994*795d594fSAndroid Build Coastguard Worker Location InvokeDexCallingConventionVisitorARM64::GetMethodLocation() const {
995*795d594fSAndroid Build Coastguard Worker return LocationFrom(kArtMethodRegister);
996*795d594fSAndroid Build Coastguard Worker }
997*795d594fSAndroid Build Coastguard Worker
GetNextLocation(DataType::Type type)998*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorARM64::GetNextLocation(DataType::Type type) {
999*795d594fSAndroid Build Coastguard Worker DCHECK_NE(type, DataType::Type::kReference);
1000*795d594fSAndroid Build Coastguard Worker
1001*795d594fSAndroid Build Coastguard Worker Location location = Location::NoLocation();
1002*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type)) {
1003*795d594fSAndroid Build Coastguard Worker if (fpr_index_ < kParameterFPRegistersLength) {
1004*795d594fSAndroid Build Coastguard Worker location = LocationFrom(kParameterFPRegisters[fpr_index_]);
1005*795d594fSAndroid Build Coastguard Worker ++fpr_index_;
1006*795d594fSAndroid Build Coastguard Worker }
1007*795d594fSAndroid Build Coastguard Worker } else {
1008*795d594fSAndroid Build Coastguard Worker // Native ABI uses the same registers as managed, except that the method register x0
1009*795d594fSAndroid Build Coastguard Worker // is a normal argument.
1010*795d594fSAndroid Build Coastguard Worker if (gpr_index_ < 1u + kParameterCoreRegistersLength) {
1011*795d594fSAndroid Build Coastguard Worker location = LocationFrom(gpr_index_ == 0u ? x0 : kParameterCoreRegisters[gpr_index_ - 1u]);
1012*795d594fSAndroid Build Coastguard Worker ++gpr_index_;
1013*795d594fSAndroid Build Coastguard Worker }
1014*795d594fSAndroid Build Coastguard Worker }
1015*795d594fSAndroid Build Coastguard Worker if (location.IsInvalid()) {
1016*795d594fSAndroid Build Coastguard Worker if (DataType::Is64BitType(type)) {
1017*795d594fSAndroid Build Coastguard Worker location = Location::DoubleStackSlot(stack_offset_);
1018*795d594fSAndroid Build Coastguard Worker } else {
1019*795d594fSAndroid Build Coastguard Worker location = Location::StackSlot(stack_offset_);
1020*795d594fSAndroid Build Coastguard Worker }
1021*795d594fSAndroid Build Coastguard Worker stack_offset_ += kFramePointerSize;
1022*795d594fSAndroid Build Coastguard Worker
1023*795d594fSAndroid Build Coastguard Worker if (for_register_allocation_) {
1024*795d594fSAndroid Build Coastguard Worker location = Location::Any();
1025*795d594fSAndroid Build Coastguard Worker }
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker return location;
1028*795d594fSAndroid Build Coastguard Worker }
1029*795d594fSAndroid Build Coastguard Worker
GetReturnLocation(DataType::Type type) const1030*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorARM64::GetReturnLocation(DataType::Type type) const {
1031*795d594fSAndroid Build Coastguard Worker // We perform conversion to the managed ABI return register after the call if needed.
1032*795d594fSAndroid Build Coastguard Worker InvokeDexCallingConventionVisitorARM64 dex_calling_convention;
1033*795d594fSAndroid Build Coastguard Worker return dex_calling_convention.GetReturnLocation(type);
1034*795d594fSAndroid Build Coastguard Worker }
1035*795d594fSAndroid Build Coastguard Worker
GetMethodLocation() const1036*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorARM64::GetMethodLocation() const {
1037*795d594fSAndroid Build Coastguard Worker // Pass the method in the hidden argument x15.
1038*795d594fSAndroid Build Coastguard Worker return Location::RegisterLocation(x15.GetCode());
1039*795d594fSAndroid Build Coastguard Worker }
1040*795d594fSAndroid Build Coastguard Worker
1041*795d594fSAndroid Build Coastguard Worker namespace detail {
1042*795d594fSAndroid Build Coastguard Worker
1043*795d594fSAndroid Build Coastguard Worker // Mark which intrinsics we don't have handcrafted code for.
1044*795d594fSAndroid Build Coastguard Worker template <Intrinsics T>
1045*795d594fSAndroid Build Coastguard Worker struct IsUnimplemented {
1046*795d594fSAndroid Build Coastguard Worker bool is_unimplemented = false;
1047*795d594fSAndroid Build Coastguard Worker };
1048*795d594fSAndroid Build Coastguard Worker
1049*795d594fSAndroid Build Coastguard Worker #define TRUE_OVERRIDE(Name) \
1050*795d594fSAndroid Build Coastguard Worker template <> \
1051*795d594fSAndroid Build Coastguard Worker struct IsUnimplemented<Intrinsics::k##Name> { \
1052*795d594fSAndroid Build Coastguard Worker bool is_unimplemented = true; \
1053*795d594fSAndroid Build Coastguard Worker };
1054*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED_INTRINSIC_LIST_ARM64(TRUE_OVERRIDE)
1055*795d594fSAndroid Build Coastguard Worker #undef TRUE_OVERRIDE
1056*795d594fSAndroid Build Coastguard Worker
1057*795d594fSAndroid Build Coastguard Worker static constexpr bool kIsIntrinsicUnimplemented[] = {
1058*795d594fSAndroid Build Coastguard Worker false, // kNone
1059*795d594fSAndroid Build Coastguard Worker #define IS_UNIMPLEMENTED(Intrinsic, ...) \
1060*795d594fSAndroid Build Coastguard Worker IsUnimplemented<Intrinsics::k##Intrinsic>().is_unimplemented,
1061*795d594fSAndroid Build Coastguard Worker ART_INTRINSICS_LIST(IS_UNIMPLEMENTED)
1062*795d594fSAndroid Build Coastguard Worker #undef IS_UNIMPLEMENTED
1063*795d594fSAndroid Build Coastguard Worker };
1064*795d594fSAndroid Build Coastguard Worker
1065*795d594fSAndroid Build Coastguard Worker } // namespace detail
1066*795d594fSAndroid Build Coastguard Worker
CodeGeneratorARM64(HGraph * graph,const CompilerOptions & compiler_options,OptimizingCompilerStats * stats)1067*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph,
1068*795d594fSAndroid Build Coastguard Worker const CompilerOptions& compiler_options,
1069*795d594fSAndroid Build Coastguard Worker OptimizingCompilerStats* stats)
1070*795d594fSAndroid Build Coastguard Worker : CodeGenerator(graph,
1071*795d594fSAndroid Build Coastguard Worker kNumberOfAllocatableRegisters,
1072*795d594fSAndroid Build Coastguard Worker kNumberOfAllocatableFPRegisters,
1073*795d594fSAndroid Build Coastguard Worker kNumberOfAllocatableRegisterPairs,
1074*795d594fSAndroid Build Coastguard Worker callee_saved_core_registers.GetList(),
1075*795d594fSAndroid Build Coastguard Worker callee_saved_fp_registers.GetList(),
1076*795d594fSAndroid Build Coastguard Worker compiler_options,
1077*795d594fSAndroid Build Coastguard Worker stats,
1078*795d594fSAndroid Build Coastguard Worker ArrayRef<const bool>(detail::kIsIntrinsicUnimplemented)),
1079*795d594fSAndroid Build Coastguard Worker block_labels_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1080*795d594fSAndroid Build Coastguard Worker jump_tables_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1081*795d594fSAndroid Build Coastguard Worker location_builder_neon_(graph, this),
1082*795d594fSAndroid Build Coastguard Worker instruction_visitor_neon_(graph, this),
1083*795d594fSAndroid Build Coastguard Worker location_builder_sve_(graph, this),
1084*795d594fSAndroid Build Coastguard Worker instruction_visitor_sve_(graph, this),
1085*795d594fSAndroid Build Coastguard Worker move_resolver_(graph->GetAllocator(), this),
1086*795d594fSAndroid Build Coastguard Worker assembler_(graph->GetAllocator(),
1087*795d594fSAndroid Build Coastguard Worker compiler_options.GetInstructionSetFeatures()->AsArm64InstructionSetFeatures()),
1088*795d594fSAndroid Build Coastguard Worker boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1089*795d594fSAndroid Build Coastguard Worker app_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1090*795d594fSAndroid Build Coastguard Worker method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1091*795d594fSAndroid Build Coastguard Worker boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1092*795d594fSAndroid Build Coastguard Worker app_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1093*795d594fSAndroid Build Coastguard Worker type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1094*795d594fSAndroid Build Coastguard Worker public_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1095*795d594fSAndroid Build Coastguard Worker package_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1096*795d594fSAndroid Build Coastguard Worker boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1097*795d594fSAndroid Build Coastguard Worker string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1098*795d594fSAndroid Build Coastguard Worker method_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1099*795d594fSAndroid Build Coastguard Worker boot_image_jni_entrypoint_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1100*795d594fSAndroid Build Coastguard Worker boot_image_other_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1101*795d594fSAndroid Build Coastguard Worker call_entrypoint_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1102*795d594fSAndroid Build Coastguard Worker baker_read_barrier_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1103*795d594fSAndroid Build Coastguard Worker jit_patches_(&assembler_, graph->GetAllocator()),
1104*795d594fSAndroid Build Coastguard Worker jit_baker_read_barrier_slow_paths_(std::less<uint32_t>(),
1105*795d594fSAndroid Build Coastguard Worker graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
1106*795d594fSAndroid Build Coastguard Worker // Save the link register (containing the return address) to mimic Quick.
1107*795d594fSAndroid Build Coastguard Worker AddAllocatedRegister(LocationFrom(lr));
1108*795d594fSAndroid Build Coastguard Worker
1109*795d594fSAndroid Build Coastguard Worker bool use_sve = ShouldUseSVE();
1110*795d594fSAndroid Build Coastguard Worker if (use_sve) {
1111*795d594fSAndroid Build Coastguard Worker location_builder_ = &location_builder_sve_;
1112*795d594fSAndroid Build Coastguard Worker instruction_visitor_ = &instruction_visitor_sve_;
1113*795d594fSAndroid Build Coastguard Worker } else {
1114*795d594fSAndroid Build Coastguard Worker location_builder_ = &location_builder_neon_;
1115*795d594fSAndroid Build Coastguard Worker instruction_visitor_ = &instruction_visitor_neon_;
1116*795d594fSAndroid Build Coastguard Worker }
1117*795d594fSAndroid Build Coastguard Worker }
1118*795d594fSAndroid Build Coastguard Worker
ShouldUseSVE() const1119*795d594fSAndroid Build Coastguard Worker bool CodeGeneratorARM64::ShouldUseSVE() const {
1120*795d594fSAndroid Build Coastguard Worker return GetInstructionSetFeatures().HasSVE();
1121*795d594fSAndroid Build Coastguard Worker }
1122*795d594fSAndroid Build Coastguard Worker
GetSIMDRegisterWidth() const1123*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorARM64::GetSIMDRegisterWidth() const {
1124*795d594fSAndroid Build Coastguard Worker return SupportsPredicatedSIMD()
1125*795d594fSAndroid Build Coastguard Worker ? GetInstructionSetFeatures().GetSVEVectorLength() / kBitsPerByte
1126*795d594fSAndroid Build Coastguard Worker : vixl::aarch64::kQRegSizeInBytes;
1127*795d594fSAndroid Build Coastguard Worker }
1128*795d594fSAndroid Build Coastguard Worker
1129*795d594fSAndroid Build Coastguard Worker #define __ GetVIXLAssembler()->
1130*795d594fSAndroid Build Coastguard Worker
FixJumpTables()1131*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::FixJumpTables() {
1132*795d594fSAndroid Build Coastguard Worker for (auto&& jump_table : jump_tables_) {
1133*795d594fSAndroid Build Coastguard Worker jump_table->FixTable(this);
1134*795d594fSAndroid Build Coastguard Worker }
1135*795d594fSAndroid Build Coastguard Worker }
1136*795d594fSAndroid Build Coastguard Worker
Finalize()1137*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::Finalize() {
1138*795d594fSAndroid Build Coastguard Worker FixJumpTables();
1139*795d594fSAndroid Build Coastguard Worker
1140*795d594fSAndroid Build Coastguard Worker // Emit JIT baker read barrier slow paths.
1141*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsJitCompiler() || jit_baker_read_barrier_slow_paths_.empty());
1142*795d594fSAndroid Build Coastguard Worker for (auto& entry : jit_baker_read_barrier_slow_paths_) {
1143*795d594fSAndroid Build Coastguard Worker uint32_t encoded_data = entry.first;
1144*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* slow_path_entry = &entry.second.label;
1145*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path_entry);
1146*795d594fSAndroid Build Coastguard Worker CompileBakerReadBarrierThunk(*GetAssembler(), encoded_data, /* debug_name= */ nullptr);
1147*795d594fSAndroid Build Coastguard Worker }
1148*795d594fSAndroid Build Coastguard Worker
1149*795d594fSAndroid Build Coastguard Worker // Ensure we emit the literal pool.
1150*795d594fSAndroid Build Coastguard Worker __ FinalizeCode();
1151*795d594fSAndroid Build Coastguard Worker
1152*795d594fSAndroid Build Coastguard Worker CodeGenerator::Finalize();
1153*795d594fSAndroid Build Coastguard Worker
1154*795d594fSAndroid Build Coastguard Worker // Verify Baker read barrier linker patches.
1155*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1156*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> code(GetCode());
1157*795d594fSAndroid Build Coastguard Worker for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
1158*795d594fSAndroid Build Coastguard Worker DCHECK(info.label.IsBound());
1159*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset = info.label.GetLocation();
1160*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(literal_offset, 4u);
1161*795d594fSAndroid Build Coastguard Worker
1162*795d594fSAndroid Build Coastguard Worker auto GetInsn = [&code](uint32_t offset) {
1163*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 4u);
1164*795d594fSAndroid Build Coastguard Worker return
1165*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(code[offset + 0]) << 0) +
1166*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(code[offset + 1]) << 8) +
1167*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(code[offset + 2]) << 16)+
1168*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(code[offset + 3]) << 24);
1169*795d594fSAndroid Build Coastguard Worker };
1170*795d594fSAndroid Build Coastguard Worker
1171*795d594fSAndroid Build Coastguard Worker const uint32_t encoded_data = info.custom_data;
1172*795d594fSAndroid Build Coastguard Worker BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data);
1173*795d594fSAndroid Build Coastguard Worker // Check that the next instruction matches the expected LDR.
1174*795d594fSAndroid Build Coastguard Worker switch (kind) {
1175*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kField:
1176*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kAcquire: {
1177*795d594fSAndroid Build Coastguard Worker DCHECK_GE(code.size() - literal_offset, 8u);
1178*795d594fSAndroid Build Coastguard Worker uint32_t next_insn = GetInsn(literal_offset + 4u);
1179*795d594fSAndroid Build Coastguard Worker CheckValidReg(next_insn & 0x1fu); // Check destination register.
1180*795d594fSAndroid Build Coastguard Worker const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data);
1181*795d594fSAndroid Build Coastguard Worker if (kind == BakerReadBarrierKind::kField) {
1182*795d594fSAndroid Build Coastguard Worker // LDR (immediate) with correct base_reg.
1183*795d594fSAndroid Build Coastguard Worker CHECK_EQ(next_insn & 0xffc003e0u, 0xb9400000u | (base_reg << 5));
1184*795d594fSAndroid Build Coastguard Worker } else {
1185*795d594fSAndroid Build Coastguard Worker DCHECK(kind == BakerReadBarrierKind::kAcquire);
1186*795d594fSAndroid Build Coastguard Worker // LDAR with correct base_reg.
1187*795d594fSAndroid Build Coastguard Worker CHECK_EQ(next_insn & 0xffffffe0u, 0x88dffc00u | (base_reg << 5));
1188*795d594fSAndroid Build Coastguard Worker }
1189*795d594fSAndroid Build Coastguard Worker break;
1190*795d594fSAndroid Build Coastguard Worker }
1191*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kArray: {
1192*795d594fSAndroid Build Coastguard Worker DCHECK_GE(code.size() - literal_offset, 8u);
1193*795d594fSAndroid Build Coastguard Worker uint32_t next_insn = GetInsn(literal_offset + 4u);
1194*795d594fSAndroid Build Coastguard Worker // LDR (register) with the correct base_reg, size=10 (32-bit), option=011 (extend = LSL),
1195*795d594fSAndroid Build Coastguard Worker // and S=1 (shift amount = 2 for 32-bit version), i.e. LDR Wt, [Xn, Xm, LSL #2].
1196*795d594fSAndroid Build Coastguard Worker CheckValidReg(next_insn & 0x1fu); // Check destination register.
1197*795d594fSAndroid Build Coastguard Worker const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data);
1198*795d594fSAndroid Build Coastguard Worker CHECK_EQ(next_insn & 0xffe0ffe0u, 0xb8607800u | (base_reg << 5));
1199*795d594fSAndroid Build Coastguard Worker CheckValidReg((next_insn >> 16) & 0x1f); // Check index register
1200*795d594fSAndroid Build Coastguard Worker break;
1201*795d594fSAndroid Build Coastguard Worker }
1202*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kGcRoot: {
1203*795d594fSAndroid Build Coastguard Worker DCHECK_GE(literal_offset, 4u);
1204*795d594fSAndroid Build Coastguard Worker uint32_t prev_insn = GetInsn(literal_offset - 4u);
1205*795d594fSAndroid Build Coastguard Worker const uint32_t root_reg = BakerReadBarrierFirstRegField::Decode(encoded_data);
1206*795d594fSAndroid Build Coastguard Worker // Usually LDR (immediate) with correct root_reg but
1207*795d594fSAndroid Build Coastguard Worker // we may have a "MOV marked, old_value" for intrinsic CAS.
1208*795d594fSAndroid Build Coastguard Worker if ((prev_insn & 0xffe0ffff) != (0x2a0003e0 | root_reg)) { // MOV?
1209*795d594fSAndroid Build Coastguard Worker CHECK_EQ(prev_insn & 0xffc0001fu, 0xb9400000u | root_reg); // LDR?
1210*795d594fSAndroid Build Coastguard Worker }
1211*795d594fSAndroid Build Coastguard Worker break;
1212*795d594fSAndroid Build Coastguard Worker }
1213*795d594fSAndroid Build Coastguard Worker default:
1214*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected kind: " << static_cast<uint32_t>(kind);
1215*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1216*795d594fSAndroid Build Coastguard Worker }
1217*795d594fSAndroid Build Coastguard Worker }
1218*795d594fSAndroid Build Coastguard Worker }
1219*795d594fSAndroid Build Coastguard Worker }
1220*795d594fSAndroid Build Coastguard Worker
PrepareForEmitNativeCode()1221*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverARM64::PrepareForEmitNativeCode() {
1222*795d594fSAndroid Build Coastguard Worker // Note: There are 6 kinds of moves:
1223*795d594fSAndroid Build Coastguard Worker // 1. constant -> GPR/FPR (non-cycle)
1224*795d594fSAndroid Build Coastguard Worker // 2. constant -> stack (non-cycle)
1225*795d594fSAndroid Build Coastguard Worker // 3. GPR/FPR -> GPR/FPR
1226*795d594fSAndroid Build Coastguard Worker // 4. GPR/FPR -> stack
1227*795d594fSAndroid Build Coastguard Worker // 5. stack -> GPR/FPR
1228*795d594fSAndroid Build Coastguard Worker // 6. stack -> stack (non-cycle)
1229*795d594fSAndroid Build Coastguard Worker // Case 1, 2 and 6 should never be included in a dependency cycle on ARM64. For case 3, 4, and 5
1230*795d594fSAndroid Build Coastguard Worker // VIXL uses at most 1 GPR. VIXL has 2 GPR and 1 FPR temps, and there should be no intersecting
1231*795d594fSAndroid Build Coastguard Worker // cycles on ARM64, so we always have 1 GPR and 1 FPR available VIXL temps to resolve the
1232*795d594fSAndroid Build Coastguard Worker // dependency.
1233*795d594fSAndroid Build Coastguard Worker vixl_temps_.Open(GetVIXLAssembler());
1234*795d594fSAndroid Build Coastguard Worker }
1235*795d594fSAndroid Build Coastguard Worker
FinishEmitNativeCode()1236*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverARM64::FinishEmitNativeCode() {
1237*795d594fSAndroid Build Coastguard Worker vixl_temps_.Close();
1238*795d594fSAndroid Build Coastguard Worker }
1239*795d594fSAndroid Build Coastguard Worker
AllocateScratchLocationFor(Location::Kind kind)1240*795d594fSAndroid Build Coastguard Worker Location ParallelMoveResolverARM64::AllocateScratchLocationFor(Location::Kind kind) {
1241*795d594fSAndroid Build Coastguard Worker DCHECK(kind == Location::kRegister || kind == Location::kFpuRegister
1242*795d594fSAndroid Build Coastguard Worker || kind == Location::kStackSlot || kind == Location::kDoubleStackSlot
1243*795d594fSAndroid Build Coastguard Worker || kind == Location::kSIMDStackSlot);
1244*795d594fSAndroid Build Coastguard Worker kind = (kind == Location::kFpuRegister || kind == Location::kSIMDStackSlot)
1245*795d594fSAndroid Build Coastguard Worker ? Location::kFpuRegister
1246*795d594fSAndroid Build Coastguard Worker : Location::kRegister;
1247*795d594fSAndroid Build Coastguard Worker Location scratch = GetScratchLocation(kind);
1248*795d594fSAndroid Build Coastguard Worker if (!scratch.Equals(Location::NoLocation())) {
1249*795d594fSAndroid Build Coastguard Worker return scratch;
1250*795d594fSAndroid Build Coastguard Worker }
1251*795d594fSAndroid Build Coastguard Worker // Allocate from VIXL temp registers.
1252*795d594fSAndroid Build Coastguard Worker if (kind == Location::kRegister) {
1253*795d594fSAndroid Build Coastguard Worker scratch = LocationFrom(vixl_temps_.AcquireX());
1254*795d594fSAndroid Build Coastguard Worker } else {
1255*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kind, Location::kFpuRegister);
1256*795d594fSAndroid Build Coastguard Worker scratch = codegen_->GetGraph()->HasSIMD()
1257*795d594fSAndroid Build Coastguard Worker ? codegen_->GetInstructionCodeGeneratorArm64()->AllocateSIMDScratchLocation(&vixl_temps_)
1258*795d594fSAndroid Build Coastguard Worker : LocationFrom(vixl_temps_.AcquireD());
1259*795d594fSAndroid Build Coastguard Worker }
1260*795d594fSAndroid Build Coastguard Worker AddScratchLocation(scratch);
1261*795d594fSAndroid Build Coastguard Worker return scratch;
1262*795d594fSAndroid Build Coastguard Worker }
1263*795d594fSAndroid Build Coastguard Worker
FreeScratchLocation(Location loc)1264*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverARM64::FreeScratchLocation(Location loc) {
1265*795d594fSAndroid Build Coastguard Worker if (loc.IsRegister()) {
1266*795d594fSAndroid Build Coastguard Worker vixl_temps_.Release(XRegisterFrom(loc));
1267*795d594fSAndroid Build Coastguard Worker } else {
1268*795d594fSAndroid Build Coastguard Worker DCHECK(loc.IsFpuRegister());
1269*795d594fSAndroid Build Coastguard Worker if (codegen_->GetGraph()->HasSIMD()) {
1270*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionCodeGeneratorArm64()->FreeSIMDScratchLocation(loc, &vixl_temps_);
1271*795d594fSAndroid Build Coastguard Worker } else {
1272*795d594fSAndroid Build Coastguard Worker vixl_temps_.Release(DRegisterFrom(loc));
1273*795d594fSAndroid Build Coastguard Worker }
1274*795d594fSAndroid Build Coastguard Worker }
1275*795d594fSAndroid Build Coastguard Worker RemoveScratchLocation(loc);
1276*795d594fSAndroid Build Coastguard Worker }
1277*795d594fSAndroid Build Coastguard Worker
EmitMove(size_t index)1278*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverARM64::EmitMove(size_t index) {
1279*795d594fSAndroid Build Coastguard Worker MoveOperands* move = moves_[index];
1280*795d594fSAndroid Build Coastguard Worker codegen_->MoveLocation(move->GetDestination(), move->GetSource(), DataType::Type::kVoid);
1281*795d594fSAndroid Build Coastguard Worker }
1282*795d594fSAndroid Build Coastguard Worker
VisitMethodExitHook(HMethodExitHook * method_hook)1283*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMethodExitHook(HMethodExitHook* method_hook) {
1284*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator())
1285*795d594fSAndroid Build Coastguard Worker LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1286*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = method_hook->InputAt(0)->GetType();
1287*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, ARM64ReturnLocation(return_type));
1288*795d594fSAndroid Build Coastguard Worker }
1289*795d594fSAndroid Build Coastguard Worker
GenerateMethodEntryExitHook(HInstruction * instruction)1290*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateMethodEntryExitHook(HInstruction* instruction) {
1291*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
1292*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1293*795d594fSAndroid Build Coastguard Worker Register addr = temps.AcquireX();
1294*795d594fSAndroid Build Coastguard Worker Register curr_entry = temps.AcquireX();
1295*795d594fSAndroid Build Coastguard Worker Register value = curr_entry.W();
1296*795d594fSAndroid Build Coastguard Worker
1297*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
1298*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) MethodEntryExitHooksSlowPathARM64(instruction);
1299*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
1300*795d594fSAndroid Build Coastguard Worker
1301*795d594fSAndroid Build Coastguard Worker if (instruction->IsMethodExitHook()) {
1302*795d594fSAndroid Build Coastguard Worker // Check if we are required to check if the caller needs a deoptimization. Strictly speaking it
1303*795d594fSAndroid Build Coastguard Worker // would be sufficient to check if CheckCallerForDeopt bit is set. Though it is faster to check
1304*795d594fSAndroid Build Coastguard Worker // if it is just non-zero. kCHA bit isn't used in debuggable runtimes as cha optimization is
1305*795d594fSAndroid Build Coastguard Worker // disabled in debuggable runtime. The other bit is used when this method itself requires a
1306*795d594fSAndroid Build Coastguard Worker // deoptimization due to redefinition. So it is safe to just check for non-zero value here.
1307*795d594fSAndroid Build Coastguard Worker __ Ldr(value, MemOperand(sp, codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
1308*795d594fSAndroid Build Coastguard Worker __ Cbnz(value, slow_path->GetEntryLabel());
1309*795d594fSAndroid Build Coastguard Worker }
1310*795d594fSAndroid Build Coastguard Worker
1311*795d594fSAndroid Build Coastguard Worker uint64_t address = reinterpret_cast64<uint64_t>(Runtime::Current()->GetInstrumentation());
1312*795d594fSAndroid Build Coastguard Worker MemberOffset offset = instruction->IsMethodExitHook() ?
1313*795d594fSAndroid Build Coastguard Worker instrumentation::Instrumentation::HaveMethodExitListenersOffset() :
1314*795d594fSAndroid Build Coastguard Worker instrumentation::Instrumentation::HaveMethodEntryListenersOffset();
1315*795d594fSAndroid Build Coastguard Worker __ Mov(addr, address + offset.Int32Value());
1316*795d594fSAndroid Build Coastguard Worker __ Ldrb(value, MemOperand(addr, 0));
1317*795d594fSAndroid Build Coastguard Worker __ Cmp(value, Operand(instrumentation::Instrumentation::kFastTraceListeners));
1318*795d594fSAndroid Build Coastguard Worker // Check if there are any method entry / exit listeners. If no, continue.
1319*795d594fSAndroid Build Coastguard Worker __ B(lt, slow_path->GetExitLabel());
1320*795d594fSAndroid Build Coastguard Worker // Check if there are any slow (jvmti / trace with thread cpu time) method entry / exit listeners.
1321*795d594fSAndroid Build Coastguard Worker // If yes, just take the slow path.
1322*795d594fSAndroid Build Coastguard Worker __ B(gt, slow_path->GetEntryLabel());
1323*795d594fSAndroid Build Coastguard Worker
1324*795d594fSAndroid Build Coastguard Worker Register init_entry = addr;
1325*795d594fSAndroid Build Coastguard Worker // Check if there is place in the buffer to store a new entry, if no, take slow path.
1326*795d594fSAndroid Build Coastguard Worker uint32_t trace_buffer_curr_entry_offset =
1327*795d594fSAndroid Build Coastguard Worker Thread::TraceBufferCurrPtrOffset<kArm64PointerSize>().Int32Value();
1328*795d594fSAndroid Build Coastguard Worker __ Ldr(curr_entry, MemOperand(tr, trace_buffer_curr_entry_offset));
1329*795d594fSAndroid Build Coastguard Worker __ Sub(curr_entry, curr_entry, kNumEntriesForWallClock * sizeof(void*));
1330*795d594fSAndroid Build Coastguard Worker __ Ldr(init_entry, MemOperand(tr, Thread::TraceBufferPtrOffset<kArm64PointerSize>().SizeValue()));
1331*795d594fSAndroid Build Coastguard Worker __ Cmp(curr_entry, init_entry);
1332*795d594fSAndroid Build Coastguard Worker __ B(lt, slow_path->GetEntryLabel());
1333*795d594fSAndroid Build Coastguard Worker
1334*795d594fSAndroid Build Coastguard Worker // Update the index in the `Thread`.
1335*795d594fSAndroid Build Coastguard Worker __ Str(curr_entry, MemOperand(tr, trace_buffer_curr_entry_offset));
1336*795d594fSAndroid Build Coastguard Worker
1337*795d594fSAndroid Build Coastguard Worker Register tmp = init_entry;
1338*795d594fSAndroid Build Coastguard Worker // Record method pointer and trace action.
1339*795d594fSAndroid Build Coastguard Worker __ Ldr(tmp, MemOperand(sp, 0));
1340*795d594fSAndroid Build Coastguard Worker // Use last two bits to encode trace method action. For MethodEntry it is 0
1341*795d594fSAndroid Build Coastguard Worker // so no need to set the bits since they are 0 already.
1342*795d594fSAndroid Build Coastguard Worker if (instruction->IsMethodExitHook()) {
1343*795d594fSAndroid Build Coastguard Worker DCHECK_GE(ArtMethod::Alignment(kRuntimePointerSize), static_cast<size_t>(4));
1344*795d594fSAndroid Build Coastguard Worker static_assert(enum_cast<int32_t>(TraceAction::kTraceMethodEnter) == 0);
1345*795d594fSAndroid Build Coastguard Worker static_assert(enum_cast<int32_t>(TraceAction::kTraceMethodExit) == 1);
1346*795d594fSAndroid Build Coastguard Worker __ Orr(tmp, tmp, Operand(enum_cast<int32_t>(TraceAction::kTraceMethodExit)));
1347*795d594fSAndroid Build Coastguard Worker }
1348*795d594fSAndroid Build Coastguard Worker __ Str(tmp, MemOperand(curr_entry, kMethodOffsetInBytes));
1349*795d594fSAndroid Build Coastguard Worker // Record the timestamp.
1350*795d594fSAndroid Build Coastguard Worker __ Mrs(tmp, (SystemRegister)SYS_CNTVCT_EL0);
1351*795d594fSAndroid Build Coastguard Worker __ Str(tmp, MemOperand(curr_entry, kTimestampOffsetInBytes));
1352*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
1353*795d594fSAndroid Build Coastguard Worker }
1354*795d594fSAndroid Build Coastguard Worker
VisitMethodExitHook(HMethodExitHook * instruction)1355*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMethodExitHook(HMethodExitHook* instruction) {
1356*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1357*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->RequiresCurrentMethod());
1358*795d594fSAndroid Build Coastguard Worker GenerateMethodEntryExitHook(instruction);
1359*795d594fSAndroid Build Coastguard Worker }
1360*795d594fSAndroid Build Coastguard Worker
VisitMethodEntryHook(HMethodEntryHook * method_hook)1361*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMethodEntryHook(HMethodEntryHook* method_hook) {
1362*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1363*795d594fSAndroid Build Coastguard Worker }
1364*795d594fSAndroid Build Coastguard Worker
VisitMethodEntryHook(HMethodEntryHook * instruction)1365*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMethodEntryHook(HMethodEntryHook* instruction) {
1366*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1367*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->RequiresCurrentMethod());
1368*795d594fSAndroid Build Coastguard Worker GenerateMethodEntryExitHook(instruction);
1369*795d594fSAndroid Build Coastguard Worker }
1370*795d594fSAndroid Build Coastguard Worker
MaybeRecordTraceEvent(bool is_method_entry)1371*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeRecordTraceEvent(bool is_method_entry) {
1372*795d594fSAndroid Build Coastguard Worker if (!art_flags::always_enable_profile_code()) {
1373*795d594fSAndroid Build Coastguard Worker return;
1374*795d594fSAndroid Build Coastguard Worker }
1375*795d594fSAndroid Build Coastguard Worker
1376*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
1377*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1378*795d594fSAndroid Build Coastguard Worker Register addr = temps.AcquireX();
1379*795d594fSAndroid Build Coastguard Worker CHECK(addr.Is(vixl::aarch64::x16));
1380*795d594fSAndroid Build Coastguard Worker
1381*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
1382*795d594fSAndroid Build Coastguard Worker new (GetScopedAllocator()) TracingMethodEntryExitHooksSlowPathARM64(is_method_entry);
1383*795d594fSAndroid Build Coastguard Worker AddSlowPath(slow_path);
1384*795d594fSAndroid Build Coastguard Worker
1385*795d594fSAndroid Build Coastguard Worker __ Ldr(addr, MemOperand(tr, Thread::TraceBufferPtrOffset<kArm64PointerSize>().SizeValue()));
1386*795d594fSAndroid Build Coastguard Worker __ Cbnz(addr, slow_path->GetEntryLabel());
1387*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
1388*795d594fSAndroid Build Coastguard Worker }
1389*795d594fSAndroid Build Coastguard Worker
MaybeIncrementHotness(HSuspendCheck * suspend_check,bool is_frame_entry)1390*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry) {
1391*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
1392*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().CountHotnessInCompiledCode()) {
1393*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1394*795d594fSAndroid Build Coastguard Worker Register counter = temps.AcquireX();
1395*795d594fSAndroid Build Coastguard Worker Register method = is_frame_entry ? kArtMethodRegister : temps.AcquireX();
1396*795d594fSAndroid Build Coastguard Worker if (!is_frame_entry) {
1397*795d594fSAndroid Build Coastguard Worker __ Ldr(method, MemOperand(sp, 0));
1398*795d594fSAndroid Build Coastguard Worker }
1399*795d594fSAndroid Build Coastguard Worker __ Ldrh(counter, MemOperand(method, ArtMethod::HotnessCountOffset().Int32Value()));
1400*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
1401*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, interpreter::kNterpHotnessValue);
1402*795d594fSAndroid Build Coastguard Worker __ Cbz(counter, &done);
1403*795d594fSAndroid Build Coastguard Worker __ Add(counter, counter, -1);
1404*795d594fSAndroid Build Coastguard Worker __ Strh(counter, MemOperand(method, ArtMethod::HotnessCountOffset().Int32Value()));
1405*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
1406*795d594fSAndroid Build Coastguard Worker }
1407*795d594fSAndroid Build Coastguard Worker
1408*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsCompilingBaseline() &&
1409*795d594fSAndroid Build Coastguard Worker GetGraph()->IsUsefulOptimizing() &&
1410*795d594fSAndroid Build Coastguard Worker !Runtime::Current()->IsAotCompiler()) {
1411*795d594fSAndroid Build Coastguard Worker ProfilingInfo* info = GetGraph()->GetProfilingInfo();
1412*795d594fSAndroid Build Coastguard Worker DCHECK(info != nullptr);
1413*795d594fSAndroid Build Coastguard Worker DCHECK(!HasEmptyFrame());
1414*795d594fSAndroid Build Coastguard Worker uint64_t address = reinterpret_cast64<uint64_t>(info);
1415*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1416*795d594fSAndroid Build Coastguard Worker Register counter = temps.AcquireW();
1417*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = new (GetScopedAllocator()) CompileOptimizedSlowPathARM64(
1418*795d594fSAndroid Build Coastguard Worker suspend_check, /* profiling_info= */ lr);
1419*795d594fSAndroid Build Coastguard Worker AddSlowPath(slow_path);
1420*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, jit_patches_.DeduplicateUint64Literal(address));
1421*795d594fSAndroid Build Coastguard Worker __ Ldrh(counter, MemOperand(lr, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()));
1422*795d594fSAndroid Build Coastguard Worker __ Cbz(counter, slow_path->GetEntryLabel());
1423*795d594fSAndroid Build Coastguard Worker __ Add(counter, counter, -1);
1424*795d594fSAndroid Build Coastguard Worker __ Strh(counter, MemOperand(lr, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()));
1425*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
1426*795d594fSAndroid Build Coastguard Worker }
1427*795d594fSAndroid Build Coastguard Worker }
1428*795d594fSAndroid Build Coastguard Worker
GenerateFrameEntry()1429*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateFrameEntry() {
1430*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
1431*795d594fSAndroid Build Coastguard Worker
1432*795d594fSAndroid Build Coastguard Worker // Check if we need to generate the clinit check. We will jump to the
1433*795d594fSAndroid Build Coastguard Worker // resolution stub if the class is not initialized and the executing thread is
1434*795d594fSAndroid Build Coastguard Worker // not the thread initializing it.
1435*795d594fSAndroid Build Coastguard Worker // We do this before constructing the frame to get the correct stack trace if
1436*795d594fSAndroid Build Coastguard Worker // an exception is thrown.
1437*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().ShouldCompileWithClinitCheck(GetGraph()->GetArtMethod())) {
1438*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1439*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label resolution;
1440*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label memory_barrier;
1441*795d594fSAndroid Build Coastguard Worker
1442*795d594fSAndroid Build Coastguard Worker Register temp1 = temps.AcquireW();
1443*795d594fSAndroid Build Coastguard Worker Register temp2 = temps.AcquireW();
1444*795d594fSAndroid Build Coastguard Worker
1445*795d594fSAndroid Build Coastguard Worker // Check if we're visibly initialized.
1446*795d594fSAndroid Build Coastguard Worker
1447*795d594fSAndroid Build Coastguard Worker // We don't emit a read barrier here to save on code size. We rely on the
1448*795d594fSAndroid Build Coastguard Worker // resolution trampoline to do a suspend check before re-entering this code.
1449*795d594fSAndroid Build Coastguard Worker __ Ldr(temp1, MemOperand(kArtMethodRegister, ArtMethod::DeclaringClassOffset().Int32Value()));
1450*795d594fSAndroid Build Coastguard Worker __ Ldrb(temp2, HeapOperand(temp1, kClassStatusByteOffset));
1451*795d594fSAndroid Build Coastguard Worker __ Cmp(temp2, kShiftedVisiblyInitializedValue);
1452*795d594fSAndroid Build Coastguard Worker __ B(hs, &frame_entry_label_);
1453*795d594fSAndroid Build Coastguard Worker
1454*795d594fSAndroid Build Coastguard Worker // Check if we're initialized and jump to code that does a memory barrier if
1455*795d594fSAndroid Build Coastguard Worker // so.
1456*795d594fSAndroid Build Coastguard Worker __ Cmp(temp2, kShiftedInitializedValue);
1457*795d594fSAndroid Build Coastguard Worker __ B(hs, &memory_barrier);
1458*795d594fSAndroid Build Coastguard Worker
1459*795d594fSAndroid Build Coastguard Worker // Check if we're initializing and the thread initializing is the one
1460*795d594fSAndroid Build Coastguard Worker // executing the code.
1461*795d594fSAndroid Build Coastguard Worker __ Cmp(temp2, kShiftedInitializingValue);
1462*795d594fSAndroid Build Coastguard Worker __ B(lo, &resolution);
1463*795d594fSAndroid Build Coastguard Worker
1464*795d594fSAndroid Build Coastguard Worker __ Ldr(temp1, HeapOperand(temp1, mirror::Class::ClinitThreadIdOffset().Int32Value()));
1465*795d594fSAndroid Build Coastguard Worker __ Ldr(temp2, MemOperand(tr, Thread::TidOffset<kArm64PointerSize>().Int32Value()));
1466*795d594fSAndroid Build Coastguard Worker __ Cmp(temp1, temp2);
1467*795d594fSAndroid Build Coastguard Worker __ B(eq, &frame_entry_label_);
1468*795d594fSAndroid Build Coastguard Worker __ Bind(&resolution);
1469*795d594fSAndroid Build Coastguard Worker
1470*795d594fSAndroid Build Coastguard Worker // Jump to the resolution stub.
1471*795d594fSAndroid Build Coastguard Worker ThreadOffset64 entrypoint_offset =
1472*795d594fSAndroid Build Coastguard Worker GetThreadOffset<kArm64PointerSize>(kQuickQuickResolutionTrampoline);
1473*795d594fSAndroid Build Coastguard Worker __ Ldr(temp1.X(), MemOperand(tr, entrypoint_offset.Int32Value()));
1474*795d594fSAndroid Build Coastguard Worker __ Br(temp1.X());
1475*795d594fSAndroid Build Coastguard Worker
1476*795d594fSAndroid Build Coastguard Worker __ Bind(&memory_barrier);
1477*795d594fSAndroid Build Coastguard Worker GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1478*795d594fSAndroid Build Coastguard Worker }
1479*795d594fSAndroid Build Coastguard Worker __ Bind(&frame_entry_label_);
1480*795d594fSAndroid Build Coastguard Worker
1481*795d594fSAndroid Build Coastguard Worker bool do_overflow_check =
1482*795d594fSAndroid Build Coastguard Worker FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm64) || !IsLeafMethod();
1483*795d594fSAndroid Build Coastguard Worker if (do_overflow_check) {
1484*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1485*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireX();
1486*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
1487*795d594fSAndroid Build Coastguard Worker __ Sub(temp, sp, static_cast<int32_t>(GetStackOverflowReservedBytes(InstructionSet::kArm64)));
1488*795d594fSAndroid Build Coastguard Worker {
1489*795d594fSAndroid Build Coastguard Worker // Ensure that between load and RecordPcInfo there are no pools emitted.
1490*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(),
1491*795d594fSAndroid Build Coastguard Worker kInstructionSize,
1492*795d594fSAndroid Build Coastguard Worker CodeBufferCheckScope::kExactSize);
1493*795d594fSAndroid Build Coastguard Worker __ ldr(wzr, MemOperand(temp, 0));
1494*795d594fSAndroid Build Coastguard Worker RecordPcInfo(nullptr, 0);
1495*795d594fSAndroid Build Coastguard Worker }
1496*795d594fSAndroid Build Coastguard Worker }
1497*795d594fSAndroid Build Coastguard Worker
1498*795d594fSAndroid Build Coastguard Worker if (!HasEmptyFrame()) {
1499*795d594fSAndroid Build Coastguard Worker // Make sure the frame size isn't unreasonably large.
1500*795d594fSAndroid Build Coastguard Worker DCHECK_LE(GetFrameSize(), GetMaximumFrameSize());
1501*795d594fSAndroid Build Coastguard Worker
1502*795d594fSAndroid Build Coastguard Worker // Stack layout:
1503*795d594fSAndroid Build Coastguard Worker // sp[frame_size - 8] : lr.
1504*795d594fSAndroid Build Coastguard Worker // ... : other preserved core registers.
1505*795d594fSAndroid Build Coastguard Worker // ... : other preserved fp registers.
1506*795d594fSAndroid Build Coastguard Worker // ... : reserved frame space.
1507*795d594fSAndroid Build Coastguard Worker // sp[0] : current method.
1508*795d594fSAndroid Build Coastguard Worker int32_t frame_size = dchecked_integral_cast<int32_t>(GetFrameSize());
1509*795d594fSAndroid Build Coastguard Worker uint32_t core_spills_offset = frame_size - GetCoreSpillSize();
1510*795d594fSAndroid Build Coastguard Worker CPURegList preserved_core_registers = GetFramePreservedCoreRegisters();
1511*795d594fSAndroid Build Coastguard Worker DCHECK(!preserved_core_registers.IsEmpty());
1512*795d594fSAndroid Build Coastguard Worker uint32_t fp_spills_offset = frame_size - FrameEntrySpillSize();
1513*795d594fSAndroid Build Coastguard Worker CPURegList preserved_fp_registers = GetFramePreservedFPRegisters();
1514*795d594fSAndroid Build Coastguard Worker
1515*795d594fSAndroid Build Coastguard Worker // Save the current method if we need it, or if using STP reduces code
1516*795d594fSAndroid Build Coastguard Worker // size. Note that we do not do this in HCurrentMethod, as the
1517*795d594fSAndroid Build Coastguard Worker // instruction might have been removed in the SSA graph.
1518*795d594fSAndroid Build Coastguard Worker CPURegister lowest_spill;
1519*795d594fSAndroid Build Coastguard Worker if (core_spills_offset == kXRegSizeInBytes) {
1520*795d594fSAndroid Build Coastguard Worker // If there is no gap between the method and the lowest core spill, use
1521*795d594fSAndroid Build Coastguard Worker // aligned STP pre-index to store both. Max difference is 512. We do
1522*795d594fSAndroid Build Coastguard Worker // that to reduce code size even if we do not have to save the method.
1523*795d594fSAndroid Build Coastguard Worker DCHECK_LE(frame_size, 512); // 32 core registers are only 256 bytes.
1524*795d594fSAndroid Build Coastguard Worker lowest_spill = preserved_core_registers.PopLowestIndex();
1525*795d594fSAndroid Build Coastguard Worker __ Stp(kArtMethodRegister, lowest_spill, MemOperand(sp, -frame_size, PreIndex));
1526*795d594fSAndroid Build Coastguard Worker } else if (RequiresCurrentMethod()) {
1527*795d594fSAndroid Build Coastguard Worker __ Str(kArtMethodRegister, MemOperand(sp, -frame_size, PreIndex));
1528*795d594fSAndroid Build Coastguard Worker } else {
1529*795d594fSAndroid Build Coastguard Worker __ Claim(frame_size);
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().AdjustCFAOffset(frame_size);
1532*795d594fSAndroid Build Coastguard Worker if (lowest_spill.IsValid()) {
1533*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().RelOffset(DWARFReg(lowest_spill), core_spills_offset);
1534*795d594fSAndroid Build Coastguard Worker core_spills_offset += kXRegSizeInBytes;
1535*795d594fSAndroid Build Coastguard Worker }
1536*795d594fSAndroid Build Coastguard Worker GetAssembler()->SpillRegisters(preserved_core_registers, core_spills_offset);
1537*795d594fSAndroid Build Coastguard Worker GetAssembler()->SpillRegisters(preserved_fp_registers, fp_spills_offset);
1538*795d594fSAndroid Build Coastguard Worker
1539*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasShouldDeoptimizeFlag()) {
1540*795d594fSAndroid Build Coastguard Worker // Initialize should_deoptimize flag to 0.
1541*795d594fSAndroid Build Coastguard Worker Register wzr = Register(VIXLRegCodeFromART(WZR), kWRegSize);
1542*795d594fSAndroid Build Coastguard Worker __ Str(wzr, MemOperand(sp, GetStackOffsetOfShouldDeoptimizeFlag()));
1543*795d594fSAndroid Build Coastguard Worker }
1544*795d594fSAndroid Build Coastguard Worker
1545*795d594fSAndroid Build Coastguard Worker MaybeRecordTraceEvent(/* is_method_entry= */ true);
1546*795d594fSAndroid Build Coastguard Worker }
1547*795d594fSAndroid Build Coastguard Worker MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true);
1548*795d594fSAndroid Build Coastguard Worker MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
1549*795d594fSAndroid Build Coastguard Worker }
1550*795d594fSAndroid Build Coastguard Worker
GenerateFrameExit()1551*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateFrameExit() {
1552*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().RememberState();
1553*795d594fSAndroid Build Coastguard Worker if (!HasEmptyFrame()) {
1554*795d594fSAndroid Build Coastguard Worker MaybeRecordTraceEvent(/* is_method_entry= */ false);
1555*795d594fSAndroid Build Coastguard Worker
1556*795d594fSAndroid Build Coastguard Worker int32_t frame_size = dchecked_integral_cast<int32_t>(GetFrameSize());
1557*795d594fSAndroid Build Coastguard Worker uint32_t core_spills_offset = frame_size - GetCoreSpillSize();
1558*795d594fSAndroid Build Coastguard Worker CPURegList preserved_core_registers = GetFramePreservedCoreRegisters();
1559*795d594fSAndroid Build Coastguard Worker DCHECK(!preserved_core_registers.IsEmpty());
1560*795d594fSAndroid Build Coastguard Worker uint32_t fp_spills_offset = frame_size - FrameEntrySpillSize();
1561*795d594fSAndroid Build Coastguard Worker CPURegList preserved_fp_registers = GetFramePreservedFPRegisters();
1562*795d594fSAndroid Build Coastguard Worker
1563*795d594fSAndroid Build Coastguard Worker CPURegister lowest_spill;
1564*795d594fSAndroid Build Coastguard Worker if (core_spills_offset == kXRegSizeInBytes) {
1565*795d594fSAndroid Build Coastguard Worker // If there is no gap between the method and the lowest core spill, use
1566*795d594fSAndroid Build Coastguard Worker // aligned LDP pre-index to pop both. Max difference is 504. We do
1567*795d594fSAndroid Build Coastguard Worker // that to reduce code size even though the loaded method is unused.
1568*795d594fSAndroid Build Coastguard Worker DCHECK_LE(frame_size, 504); // 32 core registers are only 256 bytes.
1569*795d594fSAndroid Build Coastguard Worker lowest_spill = preserved_core_registers.PopLowestIndex();
1570*795d594fSAndroid Build Coastguard Worker core_spills_offset += kXRegSizeInBytes;
1571*795d594fSAndroid Build Coastguard Worker }
1572*795d594fSAndroid Build Coastguard Worker GetAssembler()->UnspillRegisters(preserved_fp_registers, fp_spills_offset);
1573*795d594fSAndroid Build Coastguard Worker GetAssembler()->UnspillRegisters(preserved_core_registers, core_spills_offset);
1574*795d594fSAndroid Build Coastguard Worker if (lowest_spill.IsValid()) {
1575*795d594fSAndroid Build Coastguard Worker __ Ldp(xzr, lowest_spill, MemOperand(sp, frame_size, PostIndex));
1576*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().Restore(DWARFReg(lowest_spill));
1577*795d594fSAndroid Build Coastguard Worker } else {
1578*795d594fSAndroid Build Coastguard Worker __ Drop(frame_size);
1579*795d594fSAndroid Build Coastguard Worker }
1580*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().AdjustCFAOffset(-frame_size);
1581*795d594fSAndroid Build Coastguard Worker }
1582*795d594fSAndroid Build Coastguard Worker __ Ret();
1583*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().RestoreState();
1584*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
1585*795d594fSAndroid Build Coastguard Worker }
1586*795d594fSAndroid Build Coastguard Worker
GetFramePreservedCoreRegisters() const1587*795d594fSAndroid Build Coastguard Worker CPURegList CodeGeneratorARM64::GetFramePreservedCoreRegisters() const {
1588*795d594fSAndroid Build Coastguard Worker DCHECK(ArtVixlRegCodeCoherentForRegSet(core_spill_mask_, GetNumberOfCoreRegisters(), 0, 0));
1589*795d594fSAndroid Build Coastguard Worker return CPURegList(CPURegister::kRegister, kXRegSize,
1590*795d594fSAndroid Build Coastguard Worker core_spill_mask_);
1591*795d594fSAndroid Build Coastguard Worker }
1592*795d594fSAndroid Build Coastguard Worker
GetFramePreservedFPRegisters() const1593*795d594fSAndroid Build Coastguard Worker CPURegList CodeGeneratorARM64::GetFramePreservedFPRegisters() const {
1594*795d594fSAndroid Build Coastguard Worker DCHECK(ArtVixlRegCodeCoherentForRegSet(0, 0, fpu_spill_mask_,
1595*795d594fSAndroid Build Coastguard Worker GetNumberOfFloatingPointRegisters()));
1596*795d594fSAndroid Build Coastguard Worker return CPURegList(CPURegister::kVRegister, kDRegSize,
1597*795d594fSAndroid Build Coastguard Worker fpu_spill_mask_);
1598*795d594fSAndroid Build Coastguard Worker }
1599*795d594fSAndroid Build Coastguard Worker
Bind(HBasicBlock * block)1600*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::Bind(HBasicBlock* block) {
1601*795d594fSAndroid Build Coastguard Worker __ Bind(GetLabelOf(block));
1602*795d594fSAndroid Build Coastguard Worker }
1603*795d594fSAndroid Build Coastguard Worker
MoveConstant(Location location,int32_t value)1604*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MoveConstant(Location location, int32_t value) {
1605*795d594fSAndroid Build Coastguard Worker DCHECK(location.IsRegister());
1606*795d594fSAndroid Build Coastguard Worker __ Mov(RegisterFrom(location, DataType::Type::kInt32), value);
1607*795d594fSAndroid Build Coastguard Worker }
1608*795d594fSAndroid Build Coastguard Worker
AddLocationAsTemp(Location location,LocationSummary * locations)1609*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1610*795d594fSAndroid Build Coastguard Worker if (location.IsRegister()) {
1611*795d594fSAndroid Build Coastguard Worker locations->AddTemp(location);
1612*795d594fSAndroid Build Coastguard Worker } else {
1613*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1614*795d594fSAndroid Build Coastguard Worker }
1615*795d594fSAndroid Build Coastguard Worker }
1616*795d594fSAndroid Build Coastguard Worker
MaybeMarkGCCard(Register object,Register value,bool emit_null_check)1617*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeMarkGCCard(Register object, Register value, bool emit_null_check) {
1618*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
1619*795d594fSAndroid Build Coastguard Worker if (emit_null_check) {
1620*795d594fSAndroid Build Coastguard Worker __ Cbz(value, &done);
1621*795d594fSAndroid Build Coastguard Worker }
1622*795d594fSAndroid Build Coastguard Worker MarkGCCard(object);
1623*795d594fSAndroid Build Coastguard Worker if (emit_null_check) {
1624*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
1625*795d594fSAndroid Build Coastguard Worker }
1626*795d594fSAndroid Build Coastguard Worker }
1627*795d594fSAndroid Build Coastguard Worker
MarkGCCard(Register object)1628*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MarkGCCard(Register object) {
1629*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
1630*795d594fSAndroid Build Coastguard Worker Register card = temps.AcquireX();
1631*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
1632*795d594fSAndroid Build Coastguard Worker // Load the address of the card table into `card`.
1633*795d594fSAndroid Build Coastguard Worker __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64PointerSize>().Int32Value()));
1634*795d594fSAndroid Build Coastguard Worker // Calculate the offset (in the card table) of the card corresponding to `object`.
1635*795d594fSAndroid Build Coastguard Worker __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1636*795d594fSAndroid Build Coastguard Worker // Write the `art::gc::accounting::CardTable::kCardDirty` value into the
1637*795d594fSAndroid Build Coastguard Worker // `object`'s card.
1638*795d594fSAndroid Build Coastguard Worker //
1639*795d594fSAndroid Build Coastguard Worker // Register `card` contains the address of the card table. Note that the card
1640*795d594fSAndroid Build Coastguard Worker // table's base is biased during its creation so that it always starts at an
1641*795d594fSAndroid Build Coastguard Worker // address whose least-significant byte is equal to `kCardDirty` (see
1642*795d594fSAndroid Build Coastguard Worker // art::gc::accounting::CardTable::Create). Therefore the STRB instruction
1643*795d594fSAndroid Build Coastguard Worker // below writes the `kCardDirty` (byte) value into the `object`'s card
1644*795d594fSAndroid Build Coastguard Worker // (located at `card + object >> kCardShift`).
1645*795d594fSAndroid Build Coastguard Worker //
1646*795d594fSAndroid Build Coastguard Worker // This dual use of the value in register `card` (1. to calculate the location
1647*795d594fSAndroid Build Coastguard Worker // of the card to mark; and 2. to load the `kCardDirty` value) saves a load
1648*795d594fSAndroid Build Coastguard Worker // (no need to explicitly load `kCardDirty` as an immediate value).
1649*795d594fSAndroid Build Coastguard Worker __ Strb(card, MemOperand(card, temp.X()));
1650*795d594fSAndroid Build Coastguard Worker }
1651*795d594fSAndroid Build Coastguard Worker
CheckGCCardIsValid(Register object)1652*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::CheckGCCardIsValid(Register object) {
1653*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
1654*795d594fSAndroid Build Coastguard Worker Register card = temps.AcquireX();
1655*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
1656*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
1657*795d594fSAndroid Build Coastguard Worker // Load the address of the card table into `card`.
1658*795d594fSAndroid Build Coastguard Worker __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64PointerSize>().Int32Value()));
1659*795d594fSAndroid Build Coastguard Worker // Calculate the offset (in the card table) of the card corresponding to `object`.
1660*795d594fSAndroid Build Coastguard Worker __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1661*795d594fSAndroid Build Coastguard Worker // assert (!clean || !self->is_gc_marking)
1662*795d594fSAndroid Build Coastguard Worker __ Ldrb(temp, MemOperand(card, temp.X()));
1663*795d594fSAndroid Build Coastguard Worker static_assert(gc::accounting::CardTable::kCardClean == 0);
1664*795d594fSAndroid Build Coastguard Worker __ Cbnz(temp, &done);
1665*795d594fSAndroid Build Coastguard Worker __ Cbz(mr, &done);
1666*795d594fSAndroid Build Coastguard Worker __ Unreachable();
1667*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
1668*795d594fSAndroid Build Coastguard Worker }
1669*795d594fSAndroid Build Coastguard Worker
SetupBlockedRegisters() const1670*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::SetupBlockedRegisters() const {
1671*795d594fSAndroid Build Coastguard Worker // Blocked core registers:
1672*795d594fSAndroid Build Coastguard Worker // lr : Runtime reserved.
1673*795d594fSAndroid Build Coastguard Worker // tr : Runtime reserved.
1674*795d594fSAndroid Build Coastguard Worker // mr : Runtime reserved.
1675*795d594fSAndroid Build Coastguard Worker // ip1 : VIXL core temp.
1676*795d594fSAndroid Build Coastguard Worker // ip0 : VIXL core temp.
1677*795d594fSAndroid Build Coastguard Worker // x18 : Platform register.
1678*795d594fSAndroid Build Coastguard Worker //
1679*795d594fSAndroid Build Coastguard Worker // Blocked fp registers:
1680*795d594fSAndroid Build Coastguard Worker // d31 : VIXL fp temp.
1681*795d594fSAndroid Build Coastguard Worker CPURegList reserved_core_registers = vixl_reserved_core_registers;
1682*795d594fSAndroid Build Coastguard Worker reserved_core_registers.Combine(runtime_reserved_core_registers);
1683*795d594fSAndroid Build Coastguard Worker while (!reserved_core_registers.IsEmpty()) {
1684*795d594fSAndroid Build Coastguard Worker blocked_core_registers_[reserved_core_registers.PopLowestIndex().GetCode()] = true;
1685*795d594fSAndroid Build Coastguard Worker }
1686*795d594fSAndroid Build Coastguard Worker blocked_core_registers_[X18] = true;
1687*795d594fSAndroid Build Coastguard Worker
1688*795d594fSAndroid Build Coastguard Worker CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
1689*795d594fSAndroid Build Coastguard Worker while (!reserved_fp_registers.IsEmpty()) {
1690*795d594fSAndroid Build Coastguard Worker blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().GetCode()] = true;
1691*795d594fSAndroid Build Coastguard Worker }
1692*795d594fSAndroid Build Coastguard Worker
1693*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsDebuggable()) {
1694*795d594fSAndroid Build Coastguard Worker // Stubs do not save callee-save floating point registers. If the graph
1695*795d594fSAndroid Build Coastguard Worker // is debuggable, we need to deal with these registers differently. For
1696*795d594fSAndroid Build Coastguard Worker // now, just block them.
1697*795d594fSAndroid Build Coastguard Worker CPURegList reserved_fp_registers_debuggable = callee_saved_fp_registers;
1698*795d594fSAndroid Build Coastguard Worker while (!reserved_fp_registers_debuggable.IsEmpty()) {
1699*795d594fSAndroid Build Coastguard Worker blocked_fpu_registers_[reserved_fp_registers_debuggable.PopLowestIndex().GetCode()] = true;
1700*795d594fSAndroid Build Coastguard Worker }
1701*795d594fSAndroid Build Coastguard Worker }
1702*795d594fSAndroid Build Coastguard Worker }
1703*795d594fSAndroid Build Coastguard Worker
SaveCoreRegister(size_t stack_index,uint32_t reg_id)1704*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1705*795d594fSAndroid Build Coastguard Worker Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
1706*795d594fSAndroid Build Coastguard Worker __ Str(reg, MemOperand(sp, stack_index));
1707*795d594fSAndroid Build Coastguard Worker return kArm64WordSize;
1708*795d594fSAndroid Build Coastguard Worker }
1709*795d594fSAndroid Build Coastguard Worker
RestoreCoreRegister(size_t stack_index,uint32_t reg_id)1710*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1711*795d594fSAndroid Build Coastguard Worker Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
1712*795d594fSAndroid Build Coastguard Worker __ Ldr(reg, MemOperand(sp, stack_index));
1713*795d594fSAndroid Build Coastguard Worker return kArm64WordSize;
1714*795d594fSAndroid Build Coastguard Worker }
1715*795d594fSAndroid Build Coastguard Worker
SaveFloatingPointRegister(size_t stack_index,uint32_t reg_id)1716*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorARM64::SaveFloatingPointRegister([[maybe_unused]] size_t stack_index,
1717*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] uint32_t reg_id) {
1718*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "FP registers shouldn't be saved/restored individually, "
1719*795d594fSAndroid Build Coastguard Worker << "use SaveRestoreLiveRegistersHelper";
1720*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1721*795d594fSAndroid Build Coastguard Worker }
1722*795d594fSAndroid Build Coastguard Worker
RestoreFloatingPointRegister(size_t stack_index,uint32_t reg_id)1723*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorARM64::RestoreFloatingPointRegister([[maybe_unused]] size_t stack_index,
1724*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] uint32_t reg_id) {
1725*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "FP registers shouldn't be saved/restored individually, "
1726*795d594fSAndroid Build Coastguard Worker << "use SaveRestoreLiveRegistersHelper";
1727*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1728*795d594fSAndroid Build Coastguard Worker }
1729*795d594fSAndroid Build Coastguard Worker
DumpCoreRegister(std::ostream & stream,int reg) const1730*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
1731*795d594fSAndroid Build Coastguard Worker stream << XRegister(reg);
1732*795d594fSAndroid Build Coastguard Worker }
1733*795d594fSAndroid Build Coastguard Worker
DumpFloatingPointRegister(std::ostream & stream,int reg) const1734*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
1735*795d594fSAndroid Build Coastguard Worker stream << DRegister(reg);
1736*795d594fSAndroid Build Coastguard Worker }
1737*795d594fSAndroid Build Coastguard Worker
GetInstructionSetFeatures() const1738*795d594fSAndroid Build Coastguard Worker const Arm64InstructionSetFeatures& CodeGeneratorARM64::GetInstructionSetFeatures() const {
1739*795d594fSAndroid Build Coastguard Worker return *GetCompilerOptions().GetInstructionSetFeatures()->AsArm64InstructionSetFeatures();
1740*795d594fSAndroid Build Coastguard Worker }
1741*795d594fSAndroid Build Coastguard Worker
MoveConstant(CPURegister destination,HConstant * constant)1742*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
1743*795d594fSAndroid Build Coastguard Worker if (constant->IsIntConstant()) {
1744*795d594fSAndroid Build Coastguard Worker __ Mov(Register(destination), constant->AsIntConstant()->GetValue());
1745*795d594fSAndroid Build Coastguard Worker } else if (constant->IsLongConstant()) {
1746*795d594fSAndroid Build Coastguard Worker __ Mov(Register(destination), constant->AsLongConstant()->GetValue());
1747*795d594fSAndroid Build Coastguard Worker } else if (constant->IsNullConstant()) {
1748*795d594fSAndroid Build Coastguard Worker __ Mov(Register(destination), 0);
1749*795d594fSAndroid Build Coastguard Worker } else if (constant->IsFloatConstant()) {
1750*795d594fSAndroid Build Coastguard Worker __ Fmov(VRegister(destination), constant->AsFloatConstant()->GetValue());
1751*795d594fSAndroid Build Coastguard Worker } else {
1752*795d594fSAndroid Build Coastguard Worker DCHECK(constant->IsDoubleConstant());
1753*795d594fSAndroid Build Coastguard Worker __ Fmov(VRegister(destination), constant->AsDoubleConstant()->GetValue());
1754*795d594fSAndroid Build Coastguard Worker }
1755*795d594fSAndroid Build Coastguard Worker }
1756*795d594fSAndroid Build Coastguard Worker
1757*795d594fSAndroid Build Coastguard Worker
CoherentConstantAndType(Location constant,DataType::Type type)1758*795d594fSAndroid Build Coastguard Worker static bool CoherentConstantAndType(Location constant, DataType::Type type) {
1759*795d594fSAndroid Build Coastguard Worker DCHECK(constant.IsConstant());
1760*795d594fSAndroid Build Coastguard Worker HConstant* cst = constant.GetConstant();
1761*795d594fSAndroid Build Coastguard Worker return (cst->IsIntConstant() && type == DataType::Type::kInt32) ||
1762*795d594fSAndroid Build Coastguard Worker // Null is mapped to a core W register, which we associate with kPrimInt.
1763*795d594fSAndroid Build Coastguard Worker (cst->IsNullConstant() && type == DataType::Type::kInt32) ||
1764*795d594fSAndroid Build Coastguard Worker (cst->IsLongConstant() && type == DataType::Type::kInt64) ||
1765*795d594fSAndroid Build Coastguard Worker (cst->IsFloatConstant() && type == DataType::Type::kFloat32) ||
1766*795d594fSAndroid Build Coastguard Worker (cst->IsDoubleConstant() && type == DataType::Type::kFloat64);
1767*795d594fSAndroid Build Coastguard Worker }
1768*795d594fSAndroid Build Coastguard Worker
1769*795d594fSAndroid Build Coastguard Worker // Allocate a scratch register from the VIXL pool, querying first
1770*795d594fSAndroid Build Coastguard Worker // the floating-point register pool, and then the core register
1771*795d594fSAndroid Build Coastguard Worker // pool. This is essentially a reimplementation of
1772*795d594fSAndroid Build Coastguard Worker // vixl::aarch64::UseScratchRegisterScope::AcquireCPURegisterOfSize
1773*795d594fSAndroid Build Coastguard Worker // using a different allocation strategy.
AcquireFPOrCoreCPURegisterOfSize(vixl::aarch64::MacroAssembler * masm,vixl::aarch64::UseScratchRegisterScope * temps,int size_in_bits)1774*795d594fSAndroid Build Coastguard Worker static CPURegister AcquireFPOrCoreCPURegisterOfSize(vixl::aarch64::MacroAssembler* masm,
1775*795d594fSAndroid Build Coastguard Worker vixl::aarch64::UseScratchRegisterScope* temps,
1776*795d594fSAndroid Build Coastguard Worker int size_in_bits) {
1777*795d594fSAndroid Build Coastguard Worker return masm->GetScratchVRegisterList()->IsEmpty()
1778*795d594fSAndroid Build Coastguard Worker ? CPURegister(temps->AcquireRegisterOfSize(size_in_bits))
1779*795d594fSAndroid Build Coastguard Worker : CPURegister(temps->AcquireVRegisterOfSize(size_in_bits));
1780*795d594fSAndroid Build Coastguard Worker }
1781*795d594fSAndroid Build Coastguard Worker
MoveLocation(Location destination,Location source,DataType::Type dst_type)1782*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MoveLocation(Location destination,
1783*795d594fSAndroid Build Coastguard Worker Location source,
1784*795d594fSAndroid Build Coastguard Worker DataType::Type dst_type) {
1785*795d594fSAndroid Build Coastguard Worker if (source.Equals(destination)) {
1786*795d594fSAndroid Build Coastguard Worker return;
1787*795d594fSAndroid Build Coastguard Worker }
1788*795d594fSAndroid Build Coastguard Worker
1789*795d594fSAndroid Build Coastguard Worker // A valid move can always be inferred from the destination and source
1790*795d594fSAndroid Build Coastguard Worker // locations. When moving from and to a register, the argument type can be
1791*795d594fSAndroid Build Coastguard Worker // used to generate 32bit instead of 64bit moves. In debug mode we also
1792*795d594fSAndroid Build Coastguard Worker // checks the coherency of the locations and the type.
1793*795d594fSAndroid Build Coastguard Worker bool unspecified_type = (dst_type == DataType::Type::kVoid);
1794*795d594fSAndroid Build Coastguard Worker
1795*795d594fSAndroid Build Coastguard Worker if (destination.IsRegister() || destination.IsFpuRegister()) {
1796*795d594fSAndroid Build Coastguard Worker if (unspecified_type) {
1797*795d594fSAndroid Build Coastguard Worker HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
1798*795d594fSAndroid Build Coastguard Worker if (source.IsStackSlot() ||
1799*795d594fSAndroid Build Coastguard Worker (src_cst != nullptr && (src_cst->IsIntConstant()
1800*795d594fSAndroid Build Coastguard Worker || src_cst->IsFloatConstant()
1801*795d594fSAndroid Build Coastguard Worker || src_cst->IsNullConstant()))) {
1802*795d594fSAndroid Build Coastguard Worker // For stack slots and 32bit constants, a 64bit type is appropriate.
1803*795d594fSAndroid Build Coastguard Worker dst_type = destination.IsRegister() ? DataType::Type::kInt32 : DataType::Type::kFloat32;
1804*795d594fSAndroid Build Coastguard Worker } else {
1805*795d594fSAndroid Build Coastguard Worker // If the source is a double stack slot or a 64bit constant, a 64bit
1806*795d594fSAndroid Build Coastguard Worker // type is appropriate. Else the source is a register, and since the
1807*795d594fSAndroid Build Coastguard Worker // type has not been specified, we chose a 64bit type to force a 64bit
1808*795d594fSAndroid Build Coastguard Worker // move.
1809*795d594fSAndroid Build Coastguard Worker dst_type = destination.IsRegister() ? DataType::Type::kInt64 : DataType::Type::kFloat64;
1810*795d594fSAndroid Build Coastguard Worker }
1811*795d594fSAndroid Build Coastguard Worker }
1812*795d594fSAndroid Build Coastguard Worker DCHECK((destination.IsFpuRegister() && DataType::IsFloatingPointType(dst_type)) ||
1813*795d594fSAndroid Build Coastguard Worker (destination.IsRegister() && !DataType::IsFloatingPointType(dst_type)));
1814*795d594fSAndroid Build Coastguard Worker CPURegister dst = CPURegisterFrom(destination, dst_type);
1815*795d594fSAndroid Build Coastguard Worker if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
1816*795d594fSAndroid Build Coastguard Worker DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
1817*795d594fSAndroid Build Coastguard Worker __ Ldr(dst, StackOperandFrom(source));
1818*795d594fSAndroid Build Coastguard Worker } else if (source.IsSIMDStackSlot()) {
1819*795d594fSAndroid Build Coastguard Worker GetInstructionCodeGeneratorArm64()->LoadSIMDRegFromStack(destination, source);
1820*795d594fSAndroid Build Coastguard Worker } else if (source.IsConstant()) {
1821*795d594fSAndroid Build Coastguard Worker DCHECK(CoherentConstantAndType(source, dst_type));
1822*795d594fSAndroid Build Coastguard Worker MoveConstant(dst, source.GetConstant());
1823*795d594fSAndroid Build Coastguard Worker } else if (source.IsRegister()) {
1824*795d594fSAndroid Build Coastguard Worker if (destination.IsRegister()) {
1825*795d594fSAndroid Build Coastguard Worker __ Mov(Register(dst), RegisterFrom(source, dst_type));
1826*795d594fSAndroid Build Coastguard Worker } else {
1827*795d594fSAndroid Build Coastguard Worker DCHECK(destination.IsFpuRegister());
1828*795d594fSAndroid Build Coastguard Worker DataType::Type source_type = DataType::Is64BitType(dst_type)
1829*795d594fSAndroid Build Coastguard Worker ? DataType::Type::kInt64
1830*795d594fSAndroid Build Coastguard Worker : DataType::Type::kInt32;
1831*795d594fSAndroid Build Coastguard Worker __ Fmov(FPRegisterFrom(destination, dst_type), RegisterFrom(source, source_type));
1832*795d594fSAndroid Build Coastguard Worker }
1833*795d594fSAndroid Build Coastguard Worker } else {
1834*795d594fSAndroid Build Coastguard Worker DCHECK(source.IsFpuRegister());
1835*795d594fSAndroid Build Coastguard Worker if (destination.IsRegister()) {
1836*795d594fSAndroid Build Coastguard Worker DataType::Type source_type = DataType::Is64BitType(dst_type)
1837*795d594fSAndroid Build Coastguard Worker ? DataType::Type::kFloat64
1838*795d594fSAndroid Build Coastguard Worker : DataType::Type::kFloat32;
1839*795d594fSAndroid Build Coastguard Worker __ Fmov(RegisterFrom(destination, dst_type), FPRegisterFrom(source, source_type));
1840*795d594fSAndroid Build Coastguard Worker } else {
1841*795d594fSAndroid Build Coastguard Worker DCHECK(destination.IsFpuRegister());
1842*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasSIMD()) {
1843*795d594fSAndroid Build Coastguard Worker GetInstructionCodeGeneratorArm64()->MoveSIMDRegToSIMDReg(destination, source);
1844*795d594fSAndroid Build Coastguard Worker } else {
1845*795d594fSAndroid Build Coastguard Worker __ Fmov(VRegister(dst), FPRegisterFrom(source, dst_type));
1846*795d594fSAndroid Build Coastguard Worker }
1847*795d594fSAndroid Build Coastguard Worker }
1848*795d594fSAndroid Build Coastguard Worker }
1849*795d594fSAndroid Build Coastguard Worker } else if (destination.IsSIMDStackSlot()) {
1850*795d594fSAndroid Build Coastguard Worker GetInstructionCodeGeneratorArm64()->MoveToSIMDStackSlot(destination, source);
1851*795d594fSAndroid Build Coastguard Worker } else { // The destination is not a register. It must be a stack slot.
1852*795d594fSAndroid Build Coastguard Worker DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
1853*795d594fSAndroid Build Coastguard Worker if (source.IsRegister() || source.IsFpuRegister()) {
1854*795d594fSAndroid Build Coastguard Worker if (unspecified_type) {
1855*795d594fSAndroid Build Coastguard Worker if (source.IsRegister()) {
1856*795d594fSAndroid Build Coastguard Worker dst_type = destination.IsStackSlot() ? DataType::Type::kInt32 : DataType::Type::kInt64;
1857*795d594fSAndroid Build Coastguard Worker } else {
1858*795d594fSAndroid Build Coastguard Worker dst_type =
1859*795d594fSAndroid Build Coastguard Worker destination.IsStackSlot() ? DataType::Type::kFloat32 : DataType::Type::kFloat64;
1860*795d594fSAndroid Build Coastguard Worker }
1861*795d594fSAndroid Build Coastguard Worker }
1862*795d594fSAndroid Build Coastguard Worker DCHECK((destination.IsDoubleStackSlot() == DataType::Is64BitType(dst_type)) &&
1863*795d594fSAndroid Build Coastguard Worker (source.IsFpuRegister() == DataType::IsFloatingPointType(dst_type)));
1864*795d594fSAndroid Build Coastguard Worker __ Str(CPURegisterFrom(source, dst_type), StackOperandFrom(destination));
1865*795d594fSAndroid Build Coastguard Worker } else if (source.IsConstant()) {
1866*795d594fSAndroid Build Coastguard Worker DCHECK(unspecified_type || CoherentConstantAndType(source, dst_type))
1867*795d594fSAndroid Build Coastguard Worker << source << " " << dst_type;
1868*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
1869*795d594fSAndroid Build Coastguard Worker HConstant* src_cst = source.GetConstant();
1870*795d594fSAndroid Build Coastguard Worker CPURegister temp;
1871*795d594fSAndroid Build Coastguard Worker if (src_cst->IsZeroBitPattern()) {
1872*795d594fSAndroid Build Coastguard Worker temp = (src_cst->IsLongConstant() || src_cst->IsDoubleConstant())
1873*795d594fSAndroid Build Coastguard Worker ? Register(xzr)
1874*795d594fSAndroid Build Coastguard Worker : Register(wzr);
1875*795d594fSAndroid Build Coastguard Worker } else {
1876*795d594fSAndroid Build Coastguard Worker if (src_cst->IsIntConstant()) {
1877*795d594fSAndroid Build Coastguard Worker temp = temps.AcquireW();
1878*795d594fSAndroid Build Coastguard Worker } else if (src_cst->IsLongConstant()) {
1879*795d594fSAndroid Build Coastguard Worker temp = temps.AcquireX();
1880*795d594fSAndroid Build Coastguard Worker } else if (src_cst->IsFloatConstant()) {
1881*795d594fSAndroid Build Coastguard Worker temp = temps.AcquireS();
1882*795d594fSAndroid Build Coastguard Worker } else {
1883*795d594fSAndroid Build Coastguard Worker DCHECK(src_cst->IsDoubleConstant());
1884*795d594fSAndroid Build Coastguard Worker temp = temps.AcquireD();
1885*795d594fSAndroid Build Coastguard Worker }
1886*795d594fSAndroid Build Coastguard Worker MoveConstant(temp, src_cst);
1887*795d594fSAndroid Build Coastguard Worker }
1888*795d594fSAndroid Build Coastguard Worker __ Str(temp, StackOperandFrom(destination));
1889*795d594fSAndroid Build Coastguard Worker } else {
1890*795d594fSAndroid Build Coastguard Worker DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
1891*795d594fSAndroid Build Coastguard Worker DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
1892*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
1893*795d594fSAndroid Build Coastguard Worker // Use any scratch register (a core or a floating-point one)
1894*795d594fSAndroid Build Coastguard Worker // from VIXL scratch register pools as a temporary.
1895*795d594fSAndroid Build Coastguard Worker //
1896*795d594fSAndroid Build Coastguard Worker // We used to only use the FP scratch register pool, but in some
1897*795d594fSAndroid Build Coastguard Worker // rare cases the only register from this pool (D31) would
1898*795d594fSAndroid Build Coastguard Worker // already be used (e.g. within a ParallelMove instruction, when
1899*795d594fSAndroid Build Coastguard Worker // a move is blocked by a another move requiring a scratch FP
1900*795d594fSAndroid Build Coastguard Worker // register, which would reserve D31). To prevent this issue, we
1901*795d594fSAndroid Build Coastguard Worker // ask for a scratch register of any type (core or FP).
1902*795d594fSAndroid Build Coastguard Worker //
1903*795d594fSAndroid Build Coastguard Worker // Also, we start by asking for a FP scratch register first, as the
1904*795d594fSAndroid Build Coastguard Worker // demand of scratch core registers is higher. This is why we
1905*795d594fSAndroid Build Coastguard Worker // use AcquireFPOrCoreCPURegisterOfSize instead of
1906*795d594fSAndroid Build Coastguard Worker // UseScratchRegisterScope::AcquireCPURegisterOfSize, which
1907*795d594fSAndroid Build Coastguard Worker // allocates core scratch registers first.
1908*795d594fSAndroid Build Coastguard Worker CPURegister temp = AcquireFPOrCoreCPURegisterOfSize(
1909*795d594fSAndroid Build Coastguard Worker GetVIXLAssembler(),
1910*795d594fSAndroid Build Coastguard Worker &temps,
1911*795d594fSAndroid Build Coastguard Worker (destination.IsDoubleStackSlot() ? kXRegSize : kWRegSize));
1912*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, StackOperandFrom(source));
1913*795d594fSAndroid Build Coastguard Worker __ Str(temp, StackOperandFrom(destination));
1914*795d594fSAndroid Build Coastguard Worker }
1915*795d594fSAndroid Build Coastguard Worker }
1916*795d594fSAndroid Build Coastguard Worker }
1917*795d594fSAndroid Build Coastguard Worker
Load(DataType::Type type,CPURegister dst,const MemOperand & src)1918*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::Load(DataType::Type type,
1919*795d594fSAndroid Build Coastguard Worker CPURegister dst,
1920*795d594fSAndroid Build Coastguard Worker const MemOperand& src) {
1921*795d594fSAndroid Build Coastguard Worker switch (type) {
1922*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
1923*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
1924*795d594fSAndroid Build Coastguard Worker __ Ldrb(Register(dst), src);
1925*795d594fSAndroid Build Coastguard Worker break;
1926*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
1927*795d594fSAndroid Build Coastguard Worker __ Ldrsb(Register(dst), src);
1928*795d594fSAndroid Build Coastguard Worker break;
1929*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
1930*795d594fSAndroid Build Coastguard Worker __ Ldrh(Register(dst), src);
1931*795d594fSAndroid Build Coastguard Worker break;
1932*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
1933*795d594fSAndroid Build Coastguard Worker __ Ldrsh(Register(dst), src);
1934*795d594fSAndroid Build Coastguard Worker break;
1935*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1936*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
1937*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1938*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
1939*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
1940*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
1941*795d594fSAndroid Build Coastguard Worker __ Ldr(dst, src);
1942*795d594fSAndroid Build Coastguard Worker break;
1943*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
1944*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
1945*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
1946*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable type " << type;
1947*795d594fSAndroid Build Coastguard Worker }
1948*795d594fSAndroid Build Coastguard Worker }
1949*795d594fSAndroid Build Coastguard Worker
LoadAcquire(HInstruction * instruction,DataType::Type type,CPURegister dst,const MemOperand & src,bool needs_null_check)1950*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
1951*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1952*795d594fSAndroid Build Coastguard Worker CPURegister dst,
1953*795d594fSAndroid Build Coastguard Worker const MemOperand& src,
1954*795d594fSAndroid Build Coastguard Worker bool needs_null_check) {
1955*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
1956*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
1957*795d594fSAndroid Build Coastguard Worker Register temp_base = temps.AcquireX();
1958*795d594fSAndroid Build Coastguard Worker
1959*795d594fSAndroid Build Coastguard Worker DCHECK(!src.IsPreIndex());
1960*795d594fSAndroid Build Coastguard Worker DCHECK(!src.IsPostIndex());
1961*795d594fSAndroid Build Coastguard Worker
1962*795d594fSAndroid Build Coastguard Worker // TODO(vixl): Let the MacroAssembler handle MemOperand.
1963*795d594fSAndroid Build Coastguard Worker __ Add(temp_base, src.GetBaseRegister(), OperandFromMemOperand(src));
1964*795d594fSAndroid Build Coastguard Worker {
1965*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
1966*795d594fSAndroid Build Coastguard Worker MemOperand base = MemOperand(temp_base);
1967*795d594fSAndroid Build Coastguard Worker switch (type) {
1968*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
1969*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
1970*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
1971*795d594fSAndroid Build Coastguard Worker {
1972*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
1973*795d594fSAndroid Build Coastguard Worker __ ldarb(Register(dst), base);
1974*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
1975*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
1976*795d594fSAndroid Build Coastguard Worker }
1977*795d594fSAndroid Build Coastguard Worker }
1978*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt8) {
1979*795d594fSAndroid Build Coastguard Worker __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
1980*795d594fSAndroid Build Coastguard Worker }
1981*795d594fSAndroid Build Coastguard Worker break;
1982*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
1983*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
1984*795d594fSAndroid Build Coastguard Worker {
1985*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
1986*795d594fSAndroid Build Coastguard Worker __ ldarh(Register(dst), base);
1987*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
1988*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
1989*795d594fSAndroid Build Coastguard Worker }
1990*795d594fSAndroid Build Coastguard Worker }
1991*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt16) {
1992*795d594fSAndroid Build Coastguard Worker __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
1993*795d594fSAndroid Build Coastguard Worker }
1994*795d594fSAndroid Build Coastguard Worker break;
1995*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1996*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
1997*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1998*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
1999*795d594fSAndroid Build Coastguard Worker {
2000*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2001*795d594fSAndroid Build Coastguard Worker __ ldar(Register(dst), base);
2002*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2003*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2004*795d594fSAndroid Build Coastguard Worker }
2005*795d594fSAndroid Build Coastguard Worker }
2006*795d594fSAndroid Build Coastguard Worker break;
2007*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2008*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
2009*795d594fSAndroid Build Coastguard Worker DCHECK(dst.IsFPRegister());
2010*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(dst.Is64Bits(), DataType::Is64BitType(type));
2011*795d594fSAndroid Build Coastguard Worker
2012*795d594fSAndroid Build Coastguard Worker Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
2013*795d594fSAndroid Build Coastguard Worker {
2014*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2015*795d594fSAndroid Build Coastguard Worker __ ldar(temp, base);
2016*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2017*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2018*795d594fSAndroid Build Coastguard Worker }
2019*795d594fSAndroid Build Coastguard Worker }
2020*795d594fSAndroid Build Coastguard Worker __ Fmov(VRegister(dst), temp);
2021*795d594fSAndroid Build Coastguard Worker break;
2022*795d594fSAndroid Build Coastguard Worker }
2023*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
2024*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
2025*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
2026*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable type " << type;
2027*795d594fSAndroid Build Coastguard Worker }
2028*795d594fSAndroid Build Coastguard Worker }
2029*795d594fSAndroid Build Coastguard Worker }
2030*795d594fSAndroid Build Coastguard Worker
Store(DataType::Type type,CPURegister src,const MemOperand & dst)2031*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::Store(DataType::Type type,
2032*795d594fSAndroid Build Coastguard Worker CPURegister src,
2033*795d594fSAndroid Build Coastguard Worker const MemOperand& dst) {
2034*795d594fSAndroid Build Coastguard Worker switch (type) {
2035*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
2036*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
2037*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
2038*795d594fSAndroid Build Coastguard Worker __ Strb(Register(src), dst);
2039*795d594fSAndroid Build Coastguard Worker break;
2040*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
2041*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
2042*795d594fSAndroid Build Coastguard Worker __ Strh(Register(src), dst);
2043*795d594fSAndroid Build Coastguard Worker break;
2044*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2045*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
2046*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
2047*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2048*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
2049*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
2050*795d594fSAndroid Build Coastguard Worker __ Str(src, dst);
2051*795d594fSAndroid Build Coastguard Worker break;
2052*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
2053*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
2054*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
2055*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable type " << type;
2056*795d594fSAndroid Build Coastguard Worker }
2057*795d594fSAndroid Build Coastguard Worker }
2058*795d594fSAndroid Build Coastguard Worker
StoreRelease(HInstruction * instruction,DataType::Type type,CPURegister src,const MemOperand & dst,bool needs_null_check)2059*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::StoreRelease(HInstruction* instruction,
2060*795d594fSAndroid Build Coastguard Worker DataType::Type type,
2061*795d594fSAndroid Build Coastguard Worker CPURegister src,
2062*795d594fSAndroid Build Coastguard Worker const MemOperand& dst,
2063*795d594fSAndroid Build Coastguard Worker bool needs_null_check) {
2064*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
2065*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
2066*795d594fSAndroid Build Coastguard Worker Register temp_base = temps.AcquireX();
2067*795d594fSAndroid Build Coastguard Worker
2068*795d594fSAndroid Build Coastguard Worker DCHECK(!dst.IsPreIndex());
2069*795d594fSAndroid Build Coastguard Worker DCHECK(!dst.IsPostIndex());
2070*795d594fSAndroid Build Coastguard Worker
2071*795d594fSAndroid Build Coastguard Worker // TODO(vixl): Let the MacroAssembler handle this.
2072*795d594fSAndroid Build Coastguard Worker Operand op = OperandFromMemOperand(dst);
2073*795d594fSAndroid Build Coastguard Worker __ Add(temp_base, dst.GetBaseRegister(), op);
2074*795d594fSAndroid Build Coastguard Worker MemOperand base = MemOperand(temp_base);
2075*795d594fSAndroid Build Coastguard Worker // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
2076*795d594fSAndroid Build Coastguard Worker switch (type) {
2077*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
2078*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
2079*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
2080*795d594fSAndroid Build Coastguard Worker {
2081*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2082*795d594fSAndroid Build Coastguard Worker __ stlrb(Register(src), base);
2083*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2084*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2085*795d594fSAndroid Build Coastguard Worker }
2086*795d594fSAndroid Build Coastguard Worker }
2087*795d594fSAndroid Build Coastguard Worker break;
2088*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
2089*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
2090*795d594fSAndroid Build Coastguard Worker {
2091*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2092*795d594fSAndroid Build Coastguard Worker __ stlrh(Register(src), base);
2093*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2094*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2095*795d594fSAndroid Build Coastguard Worker }
2096*795d594fSAndroid Build Coastguard Worker }
2097*795d594fSAndroid Build Coastguard Worker break;
2098*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2099*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
2100*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
2101*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
2102*795d594fSAndroid Build Coastguard Worker {
2103*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2104*795d594fSAndroid Build Coastguard Worker __ stlr(Register(src), base);
2105*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2106*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2107*795d594fSAndroid Build Coastguard Worker }
2108*795d594fSAndroid Build Coastguard Worker }
2109*795d594fSAndroid Build Coastguard Worker break;
2110*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2111*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
2112*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(src.Is64Bits(), DataType::Is64BitType(type));
2113*795d594fSAndroid Build Coastguard Worker Register temp_src;
2114*795d594fSAndroid Build Coastguard Worker if (src.IsZero()) {
2115*795d594fSAndroid Build Coastguard Worker // The zero register is used to avoid synthesizing zero constants.
2116*795d594fSAndroid Build Coastguard Worker temp_src = Register(src);
2117*795d594fSAndroid Build Coastguard Worker } else {
2118*795d594fSAndroid Build Coastguard Worker DCHECK(src.IsFPRegister());
2119*795d594fSAndroid Build Coastguard Worker temp_src = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
2120*795d594fSAndroid Build Coastguard Worker __ Fmov(temp_src, VRegister(src));
2121*795d594fSAndroid Build Coastguard Worker }
2122*795d594fSAndroid Build Coastguard Worker {
2123*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2124*795d594fSAndroid Build Coastguard Worker __ stlr(temp_src, base);
2125*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
2126*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
2127*795d594fSAndroid Build Coastguard Worker }
2128*795d594fSAndroid Build Coastguard Worker }
2129*795d594fSAndroid Build Coastguard Worker break;
2130*795d594fSAndroid Build Coastguard Worker }
2131*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
2132*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
2133*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
2134*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable type " << type;
2135*795d594fSAndroid Build Coastguard Worker }
2136*795d594fSAndroid Build Coastguard Worker }
2137*795d594fSAndroid Build Coastguard Worker
InvokeRuntime(QuickEntrypointEnum entrypoint,HInstruction * instruction,uint32_t dex_pc,SlowPathCode * slow_path)2138*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::InvokeRuntime(QuickEntrypointEnum entrypoint,
2139*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
2140*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc,
2141*795d594fSAndroid Build Coastguard Worker SlowPathCode* slow_path) {
2142*795d594fSAndroid Build Coastguard Worker ValidateInvokeRuntime(entrypoint, instruction, slow_path);
2143*795d594fSAndroid Build Coastguard Worker
2144*795d594fSAndroid Build Coastguard Worker ThreadOffset64 entrypoint_offset = GetThreadOffset<kArm64PointerSize>(entrypoint);
2145*795d594fSAndroid Build Coastguard Worker // Reduce code size for AOT by using shared trampolines for slow path runtime calls across the
2146*795d594fSAndroid Build Coastguard Worker // entire oat file. This adds an extra branch and we do not want to slow down the main path.
2147*795d594fSAndroid Build Coastguard Worker // For JIT, thunk sharing is per-method, so the gains would be smaller or even negative.
2148*795d594fSAndroid Build Coastguard Worker if (slow_path == nullptr || GetCompilerOptions().IsJitCompiler()) {
2149*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(tr, entrypoint_offset.Int32Value()));
2150*795d594fSAndroid Build Coastguard Worker // Ensure the pc position is recorded immediately after the `blr` instruction.
2151*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, CodeBufferCheckScope::kExactSize);
2152*795d594fSAndroid Build Coastguard Worker __ blr(lr);
2153*795d594fSAndroid Build Coastguard Worker if (EntrypointRequiresStackMap(entrypoint)) {
2154*795d594fSAndroid Build Coastguard Worker RecordPcInfo(instruction, dex_pc, slow_path);
2155*795d594fSAndroid Build Coastguard Worker }
2156*795d594fSAndroid Build Coastguard Worker } else {
2157*795d594fSAndroid Build Coastguard Worker // Ensure the pc position is recorded immediately after the `bl` instruction.
2158*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, CodeBufferCheckScope::kExactSize);
2159*795d594fSAndroid Build Coastguard Worker EmitEntrypointThunkCall(entrypoint_offset);
2160*795d594fSAndroid Build Coastguard Worker if (EntrypointRequiresStackMap(entrypoint)) {
2161*795d594fSAndroid Build Coastguard Worker RecordPcInfo(instruction, dex_pc, slow_path);
2162*795d594fSAndroid Build Coastguard Worker }
2163*795d594fSAndroid Build Coastguard Worker }
2164*795d594fSAndroid Build Coastguard Worker }
2165*795d594fSAndroid Build Coastguard Worker
InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,HInstruction * instruction,SlowPathCode * slow_path)2166*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2167*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
2168*795d594fSAndroid Build Coastguard Worker SlowPathCode* slow_path) {
2169*795d594fSAndroid Build Coastguard Worker ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
2170*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(tr, entry_point_offset));
2171*795d594fSAndroid Build Coastguard Worker __ Blr(lr);
2172*795d594fSAndroid Build Coastguard Worker }
2173*795d594fSAndroid Build Coastguard Worker
GenerateClassInitializationCheck(SlowPathCodeARM64 * slow_path,Register class_reg)2174*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
2175*795d594fSAndroid Build Coastguard Worker Register class_reg) {
2176*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
2177*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW();
2178*795d594fSAndroid Build Coastguard Worker
2179*795d594fSAndroid Build Coastguard Worker // CMP (immediate) is limited to imm12 or imm12<<12, so we would need to materialize
2180*795d594fSAndroid Build Coastguard Worker // the constant 0xf0000000 for comparison with the full 32-bit field. To reduce the code
2181*795d594fSAndroid Build Coastguard Worker // size, load only the high byte of the field and compare with 0xf0.
2182*795d594fSAndroid Build Coastguard Worker // Note: The same code size could be achieved with LDR+MNV(asr #24)+CBNZ but benchmarks
2183*795d594fSAndroid Build Coastguard Worker // show that this pattern is slower (tested on little cores).
2184*795d594fSAndroid Build Coastguard Worker __ Ldrb(temp, HeapOperand(class_reg, kClassStatusByteOffset));
2185*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, kShiftedVisiblyInitializedValue);
2186*795d594fSAndroid Build Coastguard Worker __ B(lo, slow_path->GetEntryLabel());
2187*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
2188*795d594fSAndroid Build Coastguard Worker }
2189*795d594fSAndroid Build Coastguard Worker
GenerateBitstringTypeCheckCompare(HTypeCheckInstruction * check,vixl::aarch64::Register temp)2190*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateBitstringTypeCheckCompare(
2191*795d594fSAndroid Build Coastguard Worker HTypeCheckInstruction* check, vixl::aarch64::Register temp) {
2192*795d594fSAndroid Build Coastguard Worker uint32_t path_to_root = check->GetBitstringPathToRoot();
2193*795d594fSAndroid Build Coastguard Worker uint32_t mask = check->GetBitstringMask();
2194*795d594fSAndroid Build Coastguard Worker DCHECK(IsPowerOfTwo(mask + 1));
2195*795d594fSAndroid Build Coastguard Worker size_t mask_bits = WhichPowerOf2(mask + 1);
2196*795d594fSAndroid Build Coastguard Worker
2197*795d594fSAndroid Build Coastguard Worker if (mask_bits == 16u) {
2198*795d594fSAndroid Build Coastguard Worker // Load only the bitstring part of the status word.
2199*795d594fSAndroid Build Coastguard Worker __ Ldrh(temp, HeapOperand(temp, mirror::Class::StatusOffset()));
2200*795d594fSAndroid Build Coastguard Worker } else {
2201*795d594fSAndroid Build Coastguard Worker // /* uint32_t */ temp = temp->status_
2202*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(temp, mirror::Class::StatusOffset()));
2203*795d594fSAndroid Build Coastguard Worker // Extract the bitstring bits.
2204*795d594fSAndroid Build Coastguard Worker __ Ubfx(temp, temp, 0, mask_bits);
2205*795d594fSAndroid Build Coastguard Worker }
2206*795d594fSAndroid Build Coastguard Worker // Compare the bitstring bits to `path_to_root`.
2207*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, path_to_root);
2208*795d594fSAndroid Build Coastguard Worker }
2209*795d594fSAndroid Build Coastguard Worker
GenerateMemoryBarrier(MemBarrierKind kind)2210*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateMemoryBarrier(MemBarrierKind kind) {
2211*795d594fSAndroid Build Coastguard Worker BarrierType type = BarrierAll;
2212*795d594fSAndroid Build Coastguard Worker
2213*795d594fSAndroid Build Coastguard Worker switch (kind) {
2214*795d594fSAndroid Build Coastguard Worker case MemBarrierKind::kAnyAny:
2215*795d594fSAndroid Build Coastguard Worker case MemBarrierKind::kAnyStore: {
2216*795d594fSAndroid Build Coastguard Worker type = BarrierAll;
2217*795d594fSAndroid Build Coastguard Worker break;
2218*795d594fSAndroid Build Coastguard Worker }
2219*795d594fSAndroid Build Coastguard Worker case MemBarrierKind::kLoadAny: {
2220*795d594fSAndroid Build Coastguard Worker type = BarrierReads;
2221*795d594fSAndroid Build Coastguard Worker break;
2222*795d594fSAndroid Build Coastguard Worker }
2223*795d594fSAndroid Build Coastguard Worker case MemBarrierKind::kStoreStore: {
2224*795d594fSAndroid Build Coastguard Worker type = BarrierWrites;
2225*795d594fSAndroid Build Coastguard Worker break;
2226*795d594fSAndroid Build Coastguard Worker }
2227*795d594fSAndroid Build Coastguard Worker default:
2228*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected memory barrier " << kind;
2229*795d594fSAndroid Build Coastguard Worker }
2230*795d594fSAndroid Build Coastguard Worker __ Dmb(InnerShareable, type);
2231*795d594fSAndroid Build Coastguard Worker }
2232*795d594fSAndroid Build Coastguard Worker
CanUseImplicitSuspendCheck() const2233*795d594fSAndroid Build Coastguard Worker bool CodeGeneratorARM64::CanUseImplicitSuspendCheck() const {
2234*795d594fSAndroid Build Coastguard Worker // Use implicit suspend checks if requested in compiler options unless there are SIMD
2235*795d594fSAndroid Build Coastguard Worker // instructions in the graph. The implicit suspend check saves all FP registers as
2236*795d594fSAndroid Build Coastguard Worker // 64-bit (in line with the calling convention) but SIMD instructions can use 128-bit
2237*795d594fSAndroid Build Coastguard Worker // registers, so they need to be saved in an explicit slow path.
2238*795d594fSAndroid Build Coastguard Worker return GetCompilerOptions().GetImplicitSuspendChecks() && !GetGraph()->HasSIMD();
2239*795d594fSAndroid Build Coastguard Worker }
2240*795d594fSAndroid Build Coastguard Worker
GenerateSuspendCheck(HSuspendCheck * instruction,HBasicBlock * successor)2241*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
2242*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor) {
2243*795d594fSAndroid Build Coastguard Worker if (instruction->IsNoOp()) {
2244*795d594fSAndroid Build Coastguard Worker if (successor != nullptr) {
2245*795d594fSAndroid Build Coastguard Worker __ B(codegen_->GetLabelOf(successor));
2246*795d594fSAndroid Build Coastguard Worker }
2247*795d594fSAndroid Build Coastguard Worker return;
2248*795d594fSAndroid Build Coastguard Worker }
2249*795d594fSAndroid Build Coastguard Worker
2250*795d594fSAndroid Build Coastguard Worker if (codegen_->CanUseImplicitSuspendCheck()) {
2251*795d594fSAndroid Build Coastguard Worker __ Ldr(kImplicitSuspendCheckRegister, MemOperand(kImplicitSuspendCheckRegister));
2252*795d594fSAndroid Build Coastguard Worker codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2253*795d594fSAndroid Build Coastguard Worker if (successor != nullptr) {
2254*795d594fSAndroid Build Coastguard Worker __ B(codegen_->GetLabelOf(successor));
2255*795d594fSAndroid Build Coastguard Worker }
2256*795d594fSAndroid Build Coastguard Worker return;
2257*795d594fSAndroid Build Coastguard Worker }
2258*795d594fSAndroid Build Coastguard Worker
2259*795d594fSAndroid Build Coastguard Worker SuspendCheckSlowPathARM64* slow_path =
2260*795d594fSAndroid Build Coastguard Worker down_cast<SuspendCheckSlowPathARM64*>(instruction->GetSlowPath());
2261*795d594fSAndroid Build Coastguard Worker if (slow_path == nullptr) {
2262*795d594fSAndroid Build Coastguard Worker slow_path =
2263*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathARM64(instruction, successor);
2264*795d594fSAndroid Build Coastguard Worker instruction->SetSlowPath(slow_path);
2265*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
2266*795d594fSAndroid Build Coastguard Worker if (successor != nullptr) {
2267*795d594fSAndroid Build Coastguard Worker DCHECK(successor->IsLoopHeader());
2268*795d594fSAndroid Build Coastguard Worker }
2269*795d594fSAndroid Build Coastguard Worker } else {
2270*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(slow_path->GetSuccessor(), successor);
2271*795d594fSAndroid Build Coastguard Worker }
2272*795d594fSAndroid Build Coastguard Worker
2273*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
2274*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW();
2275*795d594fSAndroid Build Coastguard Worker
2276*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64PointerSize>().SizeValue()));
2277*795d594fSAndroid Build Coastguard Worker __ Tst(temp, Thread::SuspendOrCheckpointRequestFlags());
2278*795d594fSAndroid Build Coastguard Worker if (successor == nullptr) {
2279*795d594fSAndroid Build Coastguard Worker __ B(ne, slow_path->GetEntryLabel());
2280*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetReturnLabel());
2281*795d594fSAndroid Build Coastguard Worker } else {
2282*795d594fSAndroid Build Coastguard Worker __ B(eq, codegen_->GetLabelOf(successor));
2283*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
2284*795d594fSAndroid Build Coastguard Worker // slow_path will return to GetLabelOf(successor).
2285*795d594fSAndroid Build Coastguard Worker }
2286*795d594fSAndroid Build Coastguard Worker }
2287*795d594fSAndroid Build Coastguard Worker
InstructionCodeGeneratorARM64(HGraph * graph,CodeGeneratorARM64 * codegen)2288*795d594fSAndroid Build Coastguard Worker InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
2289*795d594fSAndroid Build Coastguard Worker CodeGeneratorARM64* codegen)
2290*795d594fSAndroid Build Coastguard Worker : InstructionCodeGenerator(graph, codegen),
2291*795d594fSAndroid Build Coastguard Worker assembler_(codegen->GetAssembler()),
2292*795d594fSAndroid Build Coastguard Worker codegen_(codegen) {}
2293*795d594fSAndroid Build Coastguard Worker
HandleBinaryOp(HBinaryOperation * instr)2294*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
2295*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instr->InputCount(), 2U);
2296*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instr);
2297*795d594fSAndroid Build Coastguard Worker DataType::Type type = instr->GetResultType();
2298*795d594fSAndroid Build Coastguard Worker switch (type) {
2299*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2300*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
2301*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2302*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, ARM64EncodableConstantOrRegister(instr->InputAt(1), instr));
2303*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2304*795d594fSAndroid Build Coastguard Worker break;
2305*795d594fSAndroid Build Coastguard Worker
2306*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2307*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
2308*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
2309*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
2310*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2311*795d594fSAndroid Build Coastguard Worker break;
2312*795d594fSAndroid Build Coastguard Worker
2313*795d594fSAndroid Build Coastguard Worker default:
2314*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
2315*795d594fSAndroid Build Coastguard Worker }
2316*795d594fSAndroid Build Coastguard Worker }
2317*795d594fSAndroid Build Coastguard Worker
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)2318*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleFieldGet(HInstruction* instruction,
2319*795d594fSAndroid Build Coastguard Worker const FieldInfo& field_info) {
2320*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2321*795d594fSAndroid Build Coastguard Worker
2322*795d594fSAndroid Build Coastguard Worker bool object_field_get_with_read_barrier =
2323*795d594fSAndroid Build Coastguard Worker (instruction->GetType() == DataType::Type::kReference) && codegen_->EmitReadBarrier();
2324*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2325*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction,
2326*795d594fSAndroid Build Coastguard Worker object_field_get_with_read_barrier
2327*795d594fSAndroid Build Coastguard Worker ? LocationSummary::kCallOnSlowPath
2328*795d594fSAndroid Build Coastguard Worker : LocationSummary::kNoCall);
2329*795d594fSAndroid Build Coastguard Worker if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
2330*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2331*795d594fSAndroid Build Coastguard Worker // We need a temporary register for the read barrier load in
2332*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier()
2333*795d594fSAndroid Build Coastguard Worker // only if the field is volatile or the offset is too big.
2334*795d594fSAndroid Build Coastguard Worker if (field_info.IsVolatile() ||
2335*795d594fSAndroid Build Coastguard Worker field_info.GetFieldOffset().Uint32Value() >= kReferenceLoadMinFarOffset) {
2336*795d594fSAndroid Build Coastguard Worker locations->AddTemp(FixedTempLocation());
2337*795d594fSAndroid Build Coastguard Worker }
2338*795d594fSAndroid Build Coastguard Worker }
2339*795d594fSAndroid Build Coastguard Worker // Input for object receiver.
2340*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2341*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(instruction->GetType())) {
2342*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister());
2343*795d594fSAndroid Build Coastguard Worker } else {
2344*795d594fSAndroid Build Coastguard Worker // The output overlaps for an object field get for non-Baker read barriers: we do not want
2345*795d594fSAndroid Build Coastguard Worker // the load to overwrite the object's location, as we need it to emit the read barrier.
2346*795d594fSAndroid Build Coastguard Worker // Baker read barrier implementation with introspection does not have this restriction.
2347*795d594fSAndroid Build Coastguard Worker bool overlap = object_field_get_with_read_barrier && !kUseBakerReadBarrier;
2348*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(),
2349*795d594fSAndroid Build Coastguard Worker overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
2350*795d594fSAndroid Build Coastguard Worker }
2351*795d594fSAndroid Build Coastguard Worker }
2352*795d594fSAndroid Build Coastguard Worker
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)2353*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction,
2354*795d594fSAndroid Build Coastguard Worker const FieldInfo& field_info) {
2355*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2356*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
2357*795d594fSAndroid Build Coastguard Worker uint32_t receiver_input = 0;
2358*795d594fSAndroid Build Coastguard Worker Location base_loc = locations->InAt(receiver_input);
2359*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
2360*795d594fSAndroid Build Coastguard Worker uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2361*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
2362*795d594fSAndroid Build Coastguard Worker DataType::Type load_type = instruction->GetType();
2363*795d594fSAndroid Build Coastguard Worker MemOperand field =
2364*795d594fSAndroid Build Coastguard Worker HeapOperand(InputRegisterAt(instruction, receiver_input), field_info.GetFieldOffset());
2365*795d594fSAndroid Build Coastguard Worker
2366*795d594fSAndroid Build Coastguard Worker if (load_type == DataType::Type::kReference && codegen_->EmitBakerReadBarrier()) {
2367*795d594fSAndroid Build Coastguard Worker // Object FieldGet with Baker's read barrier case.
2368*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(base + offset)
2369*795d594fSAndroid Build Coastguard Worker Register base = RegisterFrom(base_loc, DataType::Type::kReference);
2370*795d594fSAndroid Build Coastguard Worker Location maybe_temp =
2371*795d594fSAndroid Build Coastguard Worker (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
2372*795d594fSAndroid Build Coastguard Worker // Note that potential implicit null checks are handled in this
2373*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier call.
2374*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(
2375*795d594fSAndroid Build Coastguard Worker instruction,
2376*795d594fSAndroid Build Coastguard Worker out,
2377*795d594fSAndroid Build Coastguard Worker base,
2378*795d594fSAndroid Build Coastguard Worker offset,
2379*795d594fSAndroid Build Coastguard Worker maybe_temp,
2380*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ true,
2381*795d594fSAndroid Build Coastguard Worker field_info.IsVolatile());
2382*795d594fSAndroid Build Coastguard Worker } else {
2383*795d594fSAndroid Build Coastguard Worker // General case.
2384*795d594fSAndroid Build Coastguard Worker if (field_info.IsVolatile()) {
2385*795d594fSAndroid Build Coastguard Worker // Note that a potential implicit null check is handled in this
2386*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::LoadAcquire call.
2387*795d594fSAndroid Build Coastguard Worker // NB: LoadAcquire will record the pc info if needed.
2388*795d594fSAndroid Build Coastguard Worker codegen_->LoadAcquire(instruction,
2389*795d594fSAndroid Build Coastguard Worker load_type,
2390*795d594fSAndroid Build Coastguard Worker OutputCPURegister(instruction),
2391*795d594fSAndroid Build Coastguard Worker field,
2392*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ true);
2393*795d594fSAndroid Build Coastguard Worker } else {
2394*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
2395*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
2396*795d594fSAndroid Build Coastguard Worker codegen_->Load(load_type, OutputCPURegister(instruction), field);
2397*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
2398*795d594fSAndroid Build Coastguard Worker }
2399*795d594fSAndroid Build Coastguard Worker if (load_type == DataType::Type::kReference) {
2400*795d594fSAndroid Build Coastguard Worker // If read barriers are enabled, emit read barriers other than
2401*795d594fSAndroid Build Coastguard Worker // Baker's using a slow path (and also unpoison the loaded
2402*795d594fSAndroid Build Coastguard Worker // reference, if heap poisoning is enabled).
2403*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
2404*795d594fSAndroid Build Coastguard Worker }
2405*795d594fSAndroid Build Coastguard Worker }
2406*795d594fSAndroid Build Coastguard Worker }
2407*795d594fSAndroid Build Coastguard Worker
HandleFieldSet(HInstruction * instruction)2408*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleFieldSet(HInstruction* instruction) {
2409*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2410*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
2411*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2412*795d594fSAndroid Build Coastguard Worker HInstruction* value = instruction->InputAt(1);
2413*795d594fSAndroid Build Coastguard Worker if (IsZeroBitPattern(value)) {
2414*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::ConstantLocation(value));
2415*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsFloatingPointType(value->GetType())) {
2416*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
2417*795d594fSAndroid Build Coastguard Worker } else {
2418*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2419*795d594fSAndroid Build Coastguard Worker }
2420*795d594fSAndroid Build Coastguard Worker }
2421*795d594fSAndroid Build Coastguard Worker
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info,bool value_can_be_null,WriteBarrierKind write_barrier_kind)2422*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
2423*795d594fSAndroid Build Coastguard Worker const FieldInfo& field_info,
2424*795d594fSAndroid Build Coastguard Worker bool value_can_be_null,
2425*795d594fSAndroid Build Coastguard Worker WriteBarrierKind write_barrier_kind) {
2426*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2427*795d594fSAndroid Build Coastguard Worker
2428*795d594fSAndroid Build Coastguard Worker Register obj = InputRegisterAt(instruction, 0);
2429*795d594fSAndroid Build Coastguard Worker CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 1);
2430*795d594fSAndroid Build Coastguard Worker CPURegister source = value;
2431*795d594fSAndroid Build Coastguard Worker Offset offset = field_info.GetFieldOffset();
2432*795d594fSAndroid Build Coastguard Worker DataType::Type field_type = field_info.GetFieldType();
2433*795d594fSAndroid Build Coastguard Worker {
2434*795d594fSAndroid Build Coastguard Worker // We use a block to end the scratch scope before the write barrier, thus
2435*795d594fSAndroid Build Coastguard Worker // freeing the temporary registers so they can be used in `MarkGCCard`.
2436*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
2437*795d594fSAndroid Build Coastguard Worker
2438*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
2439*795d594fSAndroid Build Coastguard Worker DCHECK(value.IsW());
2440*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW();
2441*795d594fSAndroid Build Coastguard Worker __ Mov(temp, value.W());
2442*795d594fSAndroid Build Coastguard Worker GetAssembler()->PoisonHeapReference(temp.W());
2443*795d594fSAndroid Build Coastguard Worker source = temp;
2444*795d594fSAndroid Build Coastguard Worker }
2445*795d594fSAndroid Build Coastguard Worker
2446*795d594fSAndroid Build Coastguard Worker if (field_info.IsVolatile()) {
2447*795d594fSAndroid Build Coastguard Worker codegen_->StoreRelease(
2448*795d594fSAndroid Build Coastguard Worker instruction, field_type, source, HeapOperand(obj, offset), /* needs_null_check= */ true);
2449*795d594fSAndroid Build Coastguard Worker } else {
2450*795d594fSAndroid Build Coastguard Worker // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
2451*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
2452*795d594fSAndroid Build Coastguard Worker codegen_->Store(field_type, source, HeapOperand(obj, offset));
2453*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
2454*795d594fSAndroid Build Coastguard Worker }
2455*795d594fSAndroid Build Coastguard Worker }
2456*795d594fSAndroid Build Coastguard Worker
2457*795d594fSAndroid Build Coastguard Worker const bool needs_write_barrier =
2458*795d594fSAndroid Build Coastguard Worker codegen_->StoreNeedsWriteBarrier(field_type, instruction->InputAt(1), write_barrier_kind);
2459*795d594fSAndroid Build Coastguard Worker
2460*795d594fSAndroid Build Coastguard Worker if (needs_write_barrier) {
2461*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(Register(value).IsZero(),
2462*795d594fSAndroid Build Coastguard Worker write_barrier_kind == WriteBarrierKind::kEmitBeingReliedOn);
2463*795d594fSAndroid Build Coastguard Worker codegen_->MaybeMarkGCCard(
2464*795d594fSAndroid Build Coastguard Worker obj,
2465*795d594fSAndroid Build Coastguard Worker Register(value),
2466*795d594fSAndroid Build Coastguard Worker value_can_be_null && write_barrier_kind == WriteBarrierKind::kEmitNotBeingReliedOn);
2467*795d594fSAndroid Build Coastguard Worker } else if (codegen_->ShouldCheckGCCard(field_type, instruction->InputAt(1), write_barrier_kind)) {
2468*795d594fSAndroid Build Coastguard Worker codegen_->CheckGCCardIsValid(obj);
2469*795d594fSAndroid Build Coastguard Worker }
2470*795d594fSAndroid Build Coastguard Worker }
2471*795d594fSAndroid Build Coastguard Worker
HandleBinaryOp(HBinaryOperation * instr)2472*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
2473*795d594fSAndroid Build Coastguard Worker DataType::Type type = instr->GetType();
2474*795d594fSAndroid Build Coastguard Worker
2475*795d594fSAndroid Build Coastguard Worker switch (type) {
2476*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2477*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
2478*795d594fSAndroid Build Coastguard Worker Register dst = OutputRegister(instr);
2479*795d594fSAndroid Build Coastguard Worker Register lhs = InputRegisterAt(instr, 0);
2480*795d594fSAndroid Build Coastguard Worker Operand rhs = InputOperandAt(instr, 1);
2481*795d594fSAndroid Build Coastguard Worker if (instr->IsAdd()) {
2482*795d594fSAndroid Build Coastguard Worker __ Add(dst, lhs, rhs);
2483*795d594fSAndroid Build Coastguard Worker } else if (instr->IsAnd()) {
2484*795d594fSAndroid Build Coastguard Worker __ And(dst, lhs, rhs);
2485*795d594fSAndroid Build Coastguard Worker } else if (instr->IsOr()) {
2486*795d594fSAndroid Build Coastguard Worker __ Orr(dst, lhs, rhs);
2487*795d594fSAndroid Build Coastguard Worker } else if (instr->IsSub()) {
2488*795d594fSAndroid Build Coastguard Worker __ Sub(dst, lhs, rhs);
2489*795d594fSAndroid Build Coastguard Worker } else if (instr->IsRol()) {
2490*795d594fSAndroid Build Coastguard Worker if (rhs.IsImmediate()) {
2491*795d594fSAndroid Build Coastguard Worker uint32_t shift = (-rhs.GetImmediate()) & (lhs.GetSizeInBits() - 1);
2492*795d594fSAndroid Build Coastguard Worker __ Ror(dst, lhs, shift);
2493*795d594fSAndroid Build Coastguard Worker } else {
2494*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
2495*795d594fSAndroid Build Coastguard Worker
2496*795d594fSAndroid Build Coastguard Worker // Ensure shift distance is in the same size register as the result. If
2497*795d594fSAndroid Build Coastguard Worker // we are rotating a long and the shift comes in a w register originally,
2498*795d594fSAndroid Build Coastguard Worker // we don't need to sxtw for use as an x since the shift distances are
2499*795d594fSAndroid Build Coastguard Worker // all & reg_bits - 1.
2500*795d594fSAndroid Build Coastguard Worker Register right = RegisterFrom(instr->GetLocations()->InAt(1), type);
2501*795d594fSAndroid Build Coastguard Worker Register negated = (type == DataType::Type::kInt32) ? temps.AcquireW() : temps.AcquireX();
2502*795d594fSAndroid Build Coastguard Worker __ Neg(negated, right);
2503*795d594fSAndroid Build Coastguard Worker __ Ror(dst, lhs, negated);
2504*795d594fSAndroid Build Coastguard Worker }
2505*795d594fSAndroid Build Coastguard Worker } else if (instr->IsRor()) {
2506*795d594fSAndroid Build Coastguard Worker if (rhs.IsImmediate()) {
2507*795d594fSAndroid Build Coastguard Worker uint32_t shift = rhs.GetImmediate() & (lhs.GetSizeInBits() - 1);
2508*795d594fSAndroid Build Coastguard Worker __ Ror(dst, lhs, shift);
2509*795d594fSAndroid Build Coastguard Worker } else {
2510*795d594fSAndroid Build Coastguard Worker // Ensure shift distance is in the same size register as the result. If
2511*795d594fSAndroid Build Coastguard Worker // we are rotating a long and the shift comes in a w register originally,
2512*795d594fSAndroid Build Coastguard Worker // we don't need to sxtw for use as an x since the shift distances are
2513*795d594fSAndroid Build Coastguard Worker // all & reg_bits - 1.
2514*795d594fSAndroid Build Coastguard Worker __ Ror(dst, lhs, RegisterFrom(instr->GetLocations()->InAt(1), type));
2515*795d594fSAndroid Build Coastguard Worker }
2516*795d594fSAndroid Build Coastguard Worker } else if (instr->IsMin() || instr->IsMax()) {
2517*795d594fSAndroid Build Coastguard Worker __ Cmp(lhs, rhs);
2518*795d594fSAndroid Build Coastguard Worker __ Csel(dst, lhs, rhs, instr->IsMin() ? lt : gt);
2519*795d594fSAndroid Build Coastguard Worker } else {
2520*795d594fSAndroid Build Coastguard Worker DCHECK(instr->IsXor());
2521*795d594fSAndroid Build Coastguard Worker __ Eor(dst, lhs, rhs);
2522*795d594fSAndroid Build Coastguard Worker }
2523*795d594fSAndroid Build Coastguard Worker break;
2524*795d594fSAndroid Build Coastguard Worker }
2525*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
2526*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
2527*795d594fSAndroid Build Coastguard Worker VRegister dst = OutputFPRegister(instr);
2528*795d594fSAndroid Build Coastguard Worker VRegister lhs = InputFPRegisterAt(instr, 0);
2529*795d594fSAndroid Build Coastguard Worker VRegister rhs = InputFPRegisterAt(instr, 1);
2530*795d594fSAndroid Build Coastguard Worker if (instr->IsAdd()) {
2531*795d594fSAndroid Build Coastguard Worker __ Fadd(dst, lhs, rhs);
2532*795d594fSAndroid Build Coastguard Worker } else if (instr->IsSub()) {
2533*795d594fSAndroid Build Coastguard Worker __ Fsub(dst, lhs, rhs);
2534*795d594fSAndroid Build Coastguard Worker } else if (instr->IsMin()) {
2535*795d594fSAndroid Build Coastguard Worker __ Fmin(dst, lhs, rhs);
2536*795d594fSAndroid Build Coastguard Worker } else if (instr->IsMax()) {
2537*795d594fSAndroid Build Coastguard Worker __ Fmax(dst, lhs, rhs);
2538*795d594fSAndroid Build Coastguard Worker } else {
2539*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected floating-point binary operation";
2540*795d594fSAndroid Build Coastguard Worker }
2541*795d594fSAndroid Build Coastguard Worker break;
2542*795d594fSAndroid Build Coastguard Worker }
2543*795d594fSAndroid Build Coastguard Worker default:
2544*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected binary operation type " << type;
2545*795d594fSAndroid Build Coastguard Worker }
2546*795d594fSAndroid Build Coastguard Worker }
2547*795d594fSAndroid Build Coastguard Worker
HandleShift(HBinaryOperation * instr)2548*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
2549*795d594fSAndroid Build Coastguard Worker DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
2550*795d594fSAndroid Build Coastguard Worker
2551*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instr);
2552*795d594fSAndroid Build Coastguard Worker DataType::Type type = instr->GetResultType();
2553*795d594fSAndroid Build Coastguard Worker switch (type) {
2554*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2555*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
2556*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2557*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2558*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2559*795d594fSAndroid Build Coastguard Worker break;
2560*795d594fSAndroid Build Coastguard Worker }
2561*795d594fSAndroid Build Coastguard Worker default:
2562*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected shift type " << type;
2563*795d594fSAndroid Build Coastguard Worker }
2564*795d594fSAndroid Build Coastguard Worker }
2565*795d594fSAndroid Build Coastguard Worker
HandleShift(HBinaryOperation * instr)2566*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
2567*795d594fSAndroid Build Coastguard Worker DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
2568*795d594fSAndroid Build Coastguard Worker
2569*795d594fSAndroid Build Coastguard Worker DataType::Type type = instr->GetType();
2570*795d594fSAndroid Build Coastguard Worker switch (type) {
2571*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
2572*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
2573*795d594fSAndroid Build Coastguard Worker Register dst = OutputRegister(instr);
2574*795d594fSAndroid Build Coastguard Worker Register lhs = InputRegisterAt(instr, 0);
2575*795d594fSAndroid Build Coastguard Worker Operand rhs = InputOperandAt(instr, 1);
2576*795d594fSAndroid Build Coastguard Worker if (rhs.IsImmediate()) {
2577*795d594fSAndroid Build Coastguard Worker uint32_t shift_value = rhs.GetImmediate() &
2578*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kInt32 ? kMaxIntShiftDistance : kMaxLongShiftDistance);
2579*795d594fSAndroid Build Coastguard Worker if (instr->IsShl()) {
2580*795d594fSAndroid Build Coastguard Worker __ Lsl(dst, lhs, shift_value);
2581*795d594fSAndroid Build Coastguard Worker } else if (instr->IsShr()) {
2582*795d594fSAndroid Build Coastguard Worker __ Asr(dst, lhs, shift_value);
2583*795d594fSAndroid Build Coastguard Worker } else {
2584*795d594fSAndroid Build Coastguard Worker __ Lsr(dst, lhs, shift_value);
2585*795d594fSAndroid Build Coastguard Worker }
2586*795d594fSAndroid Build Coastguard Worker } else {
2587*795d594fSAndroid Build Coastguard Worker Register rhs_reg = dst.IsX() ? rhs.GetRegister().X() : rhs.GetRegister().W();
2588*795d594fSAndroid Build Coastguard Worker
2589*795d594fSAndroid Build Coastguard Worker if (instr->IsShl()) {
2590*795d594fSAndroid Build Coastguard Worker __ Lsl(dst, lhs, rhs_reg);
2591*795d594fSAndroid Build Coastguard Worker } else if (instr->IsShr()) {
2592*795d594fSAndroid Build Coastguard Worker __ Asr(dst, lhs, rhs_reg);
2593*795d594fSAndroid Build Coastguard Worker } else {
2594*795d594fSAndroid Build Coastguard Worker __ Lsr(dst, lhs, rhs_reg);
2595*795d594fSAndroid Build Coastguard Worker }
2596*795d594fSAndroid Build Coastguard Worker }
2597*795d594fSAndroid Build Coastguard Worker break;
2598*795d594fSAndroid Build Coastguard Worker }
2599*795d594fSAndroid Build Coastguard Worker default:
2600*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected shift operation type " << type;
2601*795d594fSAndroid Build Coastguard Worker }
2602*795d594fSAndroid Build Coastguard Worker }
2603*795d594fSAndroid Build Coastguard Worker
VisitAdd(HAdd * instruction)2604*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
2605*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
2606*795d594fSAndroid Build Coastguard Worker }
2607*795d594fSAndroid Build Coastguard Worker
VisitAdd(HAdd * instruction)2608*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
2609*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
2610*795d594fSAndroid Build Coastguard Worker }
2611*795d594fSAndroid Build Coastguard Worker
VisitAnd(HAnd * instruction)2612*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
2613*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
2614*795d594fSAndroid Build Coastguard Worker }
2615*795d594fSAndroid Build Coastguard Worker
VisitAnd(HAnd * instruction)2616*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
2617*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
2618*795d594fSAndroid Build Coastguard Worker }
2619*795d594fSAndroid Build Coastguard Worker
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instr)2620*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instr) {
2621*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntegralType(instr->GetType())) << instr->GetType();
2622*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instr);
2623*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2624*795d594fSAndroid Build Coastguard Worker // There is no immediate variant of negated bitwise instructions in AArch64.
2625*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2626*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2627*795d594fSAndroid Build Coastguard Worker }
2628*795d594fSAndroid Build Coastguard Worker
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instr)2629*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instr) {
2630*795d594fSAndroid Build Coastguard Worker Register dst = OutputRegister(instr);
2631*795d594fSAndroid Build Coastguard Worker Register lhs = InputRegisterAt(instr, 0);
2632*795d594fSAndroid Build Coastguard Worker Register rhs = InputRegisterAt(instr, 1);
2633*795d594fSAndroid Build Coastguard Worker
2634*795d594fSAndroid Build Coastguard Worker switch (instr->GetOpKind()) {
2635*795d594fSAndroid Build Coastguard Worker case HInstruction::kAnd:
2636*795d594fSAndroid Build Coastguard Worker __ Bic(dst, lhs, rhs);
2637*795d594fSAndroid Build Coastguard Worker break;
2638*795d594fSAndroid Build Coastguard Worker case HInstruction::kOr:
2639*795d594fSAndroid Build Coastguard Worker __ Orn(dst, lhs, rhs);
2640*795d594fSAndroid Build Coastguard Worker break;
2641*795d594fSAndroid Build Coastguard Worker case HInstruction::kXor:
2642*795d594fSAndroid Build Coastguard Worker __ Eon(dst, lhs, rhs);
2643*795d594fSAndroid Build Coastguard Worker break;
2644*795d594fSAndroid Build Coastguard Worker default:
2645*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
2646*795d594fSAndroid Build Coastguard Worker }
2647*795d594fSAndroid Build Coastguard Worker }
2648*795d594fSAndroid Build Coastguard Worker
VisitDataProcWithShifterOp(HDataProcWithShifterOp * instruction)2649*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitDataProcWithShifterOp(
2650*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp* instruction) {
2651*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
2652*795d594fSAndroid Build Coastguard Worker instruction->GetType() == DataType::Type::kInt64);
2653*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2654*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
2655*795d594fSAndroid Build Coastguard Worker if (instruction->GetInstrKind() == HInstruction::kNeg) {
2656*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::ConstantLocation(instruction->InputAt(0)));
2657*795d594fSAndroid Build Coastguard Worker } else {
2658*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2659*795d594fSAndroid Build Coastguard Worker }
2660*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2661*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2662*795d594fSAndroid Build Coastguard Worker }
2663*795d594fSAndroid Build Coastguard Worker
VisitDataProcWithShifterOp(HDataProcWithShifterOp * instruction)2664*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitDataProcWithShifterOp(
2665*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp* instruction) {
2666*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
2667*795d594fSAndroid Build Coastguard Worker HInstruction::InstructionKind kind = instruction->GetInstrKind();
2668*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
2669*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
2670*795d594fSAndroid Build Coastguard Worker Register left;
2671*795d594fSAndroid Build Coastguard Worker if (kind != HInstruction::kNeg) {
2672*795d594fSAndroid Build Coastguard Worker left = InputRegisterAt(instruction, 0);
2673*795d594fSAndroid Build Coastguard Worker }
2674*795d594fSAndroid Build Coastguard Worker // If this `HDataProcWithShifterOp` was created by merging a type conversion as the
2675*795d594fSAndroid Build Coastguard Worker // shifter operand operation, the IR generating `right_reg` (input to the type
2676*795d594fSAndroid Build Coastguard Worker // conversion) can have a different type from the current instruction's type,
2677*795d594fSAndroid Build Coastguard Worker // so we manually indicate the type.
2678*795d594fSAndroid Build Coastguard Worker Register right_reg = RegisterFrom(instruction->GetLocations()->InAt(1), type);
2679*795d594fSAndroid Build Coastguard Worker Operand right_operand(0);
2680*795d594fSAndroid Build Coastguard Worker
2681*795d594fSAndroid Build Coastguard Worker HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
2682*795d594fSAndroid Build Coastguard Worker if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
2683*795d594fSAndroid Build Coastguard Worker right_operand = Operand(right_reg, helpers::ExtendFromOpKind(op_kind));
2684*795d594fSAndroid Build Coastguard Worker } else {
2685*795d594fSAndroid Build Coastguard Worker right_operand = Operand(right_reg,
2686*795d594fSAndroid Build Coastguard Worker helpers::ShiftFromOpKind(op_kind),
2687*795d594fSAndroid Build Coastguard Worker instruction->GetShiftAmount());
2688*795d594fSAndroid Build Coastguard Worker }
2689*795d594fSAndroid Build Coastguard Worker
2690*795d594fSAndroid Build Coastguard Worker // Logical binary operations do not support extension operations in the
2691*795d594fSAndroid Build Coastguard Worker // operand. Note that VIXL would still manage if it was passed by generating
2692*795d594fSAndroid Build Coastguard Worker // the extension as a separate instruction.
2693*795d594fSAndroid Build Coastguard Worker // `HNeg` also does not support extension. See comments in `ShifterOperandSupportsExtension()`.
2694*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(right_operand.IsExtendedRegister(),
2695*795d594fSAndroid Build Coastguard Worker kind != HInstruction::kAnd && kind != HInstruction::kOr &&
2696*795d594fSAndroid Build Coastguard Worker kind != HInstruction::kXor && kind != HInstruction::kNeg);
2697*795d594fSAndroid Build Coastguard Worker switch (kind) {
2698*795d594fSAndroid Build Coastguard Worker case HInstruction::kAdd:
2699*795d594fSAndroid Build Coastguard Worker __ Add(out, left, right_operand);
2700*795d594fSAndroid Build Coastguard Worker break;
2701*795d594fSAndroid Build Coastguard Worker case HInstruction::kAnd:
2702*795d594fSAndroid Build Coastguard Worker __ And(out, left, right_operand);
2703*795d594fSAndroid Build Coastguard Worker break;
2704*795d594fSAndroid Build Coastguard Worker case HInstruction::kNeg:
2705*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->InputAt(0)->AsConstant()->IsArithmeticZero());
2706*795d594fSAndroid Build Coastguard Worker __ Neg(out, right_operand);
2707*795d594fSAndroid Build Coastguard Worker break;
2708*795d594fSAndroid Build Coastguard Worker case HInstruction::kOr:
2709*795d594fSAndroid Build Coastguard Worker __ Orr(out, left, right_operand);
2710*795d594fSAndroid Build Coastguard Worker break;
2711*795d594fSAndroid Build Coastguard Worker case HInstruction::kSub:
2712*795d594fSAndroid Build Coastguard Worker __ Sub(out, left, right_operand);
2713*795d594fSAndroid Build Coastguard Worker break;
2714*795d594fSAndroid Build Coastguard Worker case HInstruction::kXor:
2715*795d594fSAndroid Build Coastguard Worker __ Eor(out, left, right_operand);
2716*795d594fSAndroid Build Coastguard Worker break;
2717*795d594fSAndroid Build Coastguard Worker default:
2718*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected operation kind: " << kind;
2719*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
2720*795d594fSAndroid Build Coastguard Worker }
2721*795d594fSAndroid Build Coastguard Worker }
2722*795d594fSAndroid Build Coastguard Worker
VisitIntermediateAddress(HIntermediateAddress * instruction)2723*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitIntermediateAddress(HIntermediateAddress* instruction) {
2724*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2725*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
2726*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2727*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->GetOffset(), instruction));
2728*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2729*795d594fSAndroid Build Coastguard Worker }
2730*795d594fSAndroid Build Coastguard Worker
VisitIntermediateAddress(HIntermediateAddress * instruction)2731*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitIntermediateAddress(HIntermediateAddress* instruction) {
2732*795d594fSAndroid Build Coastguard Worker __ Add(OutputRegister(instruction),
2733*795d594fSAndroid Build Coastguard Worker InputRegisterAt(instruction, 0),
2734*795d594fSAndroid Build Coastguard Worker Operand(InputOperandAt(instruction, 1)));
2735*795d594fSAndroid Build Coastguard Worker }
2736*795d594fSAndroid Build Coastguard Worker
VisitIntermediateAddressIndex(HIntermediateAddressIndex * instruction)2737*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitIntermediateAddressIndex(HIntermediateAddressIndex* instruction) {
2738*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2739*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
2740*795d594fSAndroid Build Coastguard Worker
2741*795d594fSAndroid Build Coastguard Worker HIntConstant* shift = instruction->GetShift()->AsIntConstant();
2742*795d594fSAndroid Build Coastguard Worker
2743*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2744*795d594fSAndroid Build Coastguard Worker // For byte case we don't need to shift the index variable so we can encode the data offset into
2745*795d594fSAndroid Build Coastguard Worker // ADD instruction. For other cases we prefer the data_offset to be in register; that will hoist
2746*795d594fSAndroid Build Coastguard Worker // data offset constant generation out of the loop and reduce the critical path length in the
2747*795d594fSAndroid Build Coastguard Worker // loop.
2748*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, shift->GetValue() == 0
2749*795d594fSAndroid Build Coastguard Worker ? Location::ConstantLocation(instruction->GetOffset())
2750*795d594fSAndroid Build Coastguard Worker : Location::RequiresRegister());
2751*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::ConstantLocation(shift));
2752*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2753*795d594fSAndroid Build Coastguard Worker }
2754*795d594fSAndroid Build Coastguard Worker
VisitIntermediateAddressIndex(HIntermediateAddressIndex * instruction)2755*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitIntermediateAddressIndex(
2756*795d594fSAndroid Build Coastguard Worker HIntermediateAddressIndex* instruction) {
2757*795d594fSAndroid Build Coastguard Worker Register index_reg = InputRegisterAt(instruction, 0);
2758*795d594fSAndroid Build Coastguard Worker uint32_t shift = Int64FromLocation(instruction->GetLocations()->InAt(2));
2759*795d594fSAndroid Build Coastguard Worker uint32_t offset = instruction->GetOffset()->AsIntConstant()->GetValue();
2760*795d594fSAndroid Build Coastguard Worker
2761*795d594fSAndroid Build Coastguard Worker if (shift == 0) {
2762*795d594fSAndroid Build Coastguard Worker __ Add(OutputRegister(instruction), index_reg, offset);
2763*795d594fSAndroid Build Coastguard Worker } else {
2764*795d594fSAndroid Build Coastguard Worker Register offset_reg = InputRegisterAt(instruction, 1);
2765*795d594fSAndroid Build Coastguard Worker __ Add(OutputRegister(instruction), offset_reg, Operand(index_reg, LSL, shift));
2766*795d594fSAndroid Build Coastguard Worker }
2767*795d594fSAndroid Build Coastguard Worker }
2768*795d594fSAndroid Build Coastguard Worker
VisitMultiplyAccumulate(HMultiplyAccumulate * instr)2769*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
2770*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2771*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instr, LocationSummary::kNoCall);
2772*795d594fSAndroid Build Coastguard Worker HInstruction* accumulator = instr->InputAt(HMultiplyAccumulate::kInputAccumulatorIndex);
2773*795d594fSAndroid Build Coastguard Worker if (instr->GetOpKind() == HInstruction::kSub &&
2774*795d594fSAndroid Build Coastguard Worker accumulator->IsConstant() &&
2775*795d594fSAndroid Build Coastguard Worker accumulator->AsConstant()->IsArithmeticZero()) {
2776*795d594fSAndroid Build Coastguard Worker // Don't allocate register for Mneg instruction.
2777*795d594fSAndroid Build Coastguard Worker } else {
2778*795d594fSAndroid Build Coastguard Worker locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
2779*795d594fSAndroid Build Coastguard Worker Location::RequiresRegister());
2780*795d594fSAndroid Build Coastguard Worker }
2781*795d594fSAndroid Build Coastguard Worker locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
2782*795d594fSAndroid Build Coastguard Worker locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
2783*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2784*795d594fSAndroid Build Coastguard Worker }
2785*795d594fSAndroid Build Coastguard Worker
VisitMultiplyAccumulate(HMultiplyAccumulate * instr)2786*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
2787*795d594fSAndroid Build Coastguard Worker Register res = OutputRegister(instr);
2788*795d594fSAndroid Build Coastguard Worker Register mul_left = InputRegisterAt(instr, HMultiplyAccumulate::kInputMulLeftIndex);
2789*795d594fSAndroid Build Coastguard Worker Register mul_right = InputRegisterAt(instr, HMultiplyAccumulate::kInputMulRightIndex);
2790*795d594fSAndroid Build Coastguard Worker
2791*795d594fSAndroid Build Coastguard Worker // Avoid emitting code that could trigger Cortex A53's erratum 835769.
2792*795d594fSAndroid Build Coastguard Worker // This fixup should be carried out for all multiply-accumulate instructions:
2793*795d594fSAndroid Build Coastguard Worker // madd, msub, smaddl, smsubl, umaddl and umsubl.
2794*795d594fSAndroid Build Coastguard Worker if (instr->GetType() == DataType::Type::kInt64 &&
2795*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionSetFeatures().NeedFixCortexA53_835769()) {
2796*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen_)->GetVIXLAssembler();
2797*795d594fSAndroid Build Coastguard Worker ptrdiff_t off = masm->GetCursorOffset();
2798*795d594fSAndroid Build Coastguard Worker if (off >= static_cast<ptrdiff_t>(kInstructionSize) &&
2799*795d594fSAndroid Build Coastguard Worker masm->GetInstructionAt(off - static_cast<ptrdiff_t>(kInstructionSize))->IsLoadOrStore()) {
2800*795d594fSAndroid Build Coastguard Worker // Make sure we emit only exactly one nop.
2801*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope scope(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
2802*795d594fSAndroid Build Coastguard Worker __ nop();
2803*795d594fSAndroid Build Coastguard Worker }
2804*795d594fSAndroid Build Coastguard Worker }
2805*795d594fSAndroid Build Coastguard Worker
2806*795d594fSAndroid Build Coastguard Worker if (instr->GetOpKind() == HInstruction::kAdd) {
2807*795d594fSAndroid Build Coastguard Worker Register accumulator = InputRegisterAt(instr, HMultiplyAccumulate::kInputAccumulatorIndex);
2808*795d594fSAndroid Build Coastguard Worker __ Madd(res, mul_left, mul_right, accumulator);
2809*795d594fSAndroid Build Coastguard Worker } else {
2810*795d594fSAndroid Build Coastguard Worker DCHECK(instr->GetOpKind() == HInstruction::kSub);
2811*795d594fSAndroid Build Coastguard Worker HInstruction* accum_instr = instr->InputAt(HMultiplyAccumulate::kInputAccumulatorIndex);
2812*795d594fSAndroid Build Coastguard Worker if (accum_instr->IsConstant() && accum_instr->AsConstant()->IsArithmeticZero()) {
2813*795d594fSAndroid Build Coastguard Worker __ Mneg(res, mul_left, mul_right);
2814*795d594fSAndroid Build Coastguard Worker } else {
2815*795d594fSAndroid Build Coastguard Worker Register accumulator = InputRegisterAt(instr, HMultiplyAccumulate::kInputAccumulatorIndex);
2816*795d594fSAndroid Build Coastguard Worker __ Msub(res, mul_left, mul_right, accumulator);
2817*795d594fSAndroid Build Coastguard Worker }
2818*795d594fSAndroid Build Coastguard Worker }
2819*795d594fSAndroid Build Coastguard Worker }
2820*795d594fSAndroid Build Coastguard Worker
VisitArrayGet(HArrayGet * instruction)2821*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
2822*795d594fSAndroid Build Coastguard Worker bool object_array_get_with_read_barrier =
2823*795d594fSAndroid Build Coastguard Worker (instruction->GetType() == DataType::Type::kReference) && codegen_->EmitReadBarrier();
2824*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2825*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction,
2826*795d594fSAndroid Build Coastguard Worker object_array_get_with_read_barrier
2827*795d594fSAndroid Build Coastguard Worker ? LocationSummary::kCallOnSlowPath
2828*795d594fSAndroid Build Coastguard Worker : LocationSummary::kNoCall);
2829*795d594fSAndroid Build Coastguard Worker if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
2830*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2831*795d594fSAndroid Build Coastguard Worker if (instruction->GetIndex()->IsConstant()) {
2832*795d594fSAndroid Build Coastguard Worker // Array loads with constant index are treated as field loads.
2833*795d594fSAndroid Build Coastguard Worker // We need a temporary register for the read barrier load in
2834*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier()
2835*795d594fSAndroid Build Coastguard Worker // only if the offset is too big.
2836*795d594fSAndroid Build Coastguard Worker uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
2837*795d594fSAndroid Build Coastguard Worker uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
2838*795d594fSAndroid Build Coastguard Worker offset += index << DataType::SizeShift(DataType::Type::kReference);
2839*795d594fSAndroid Build Coastguard Worker if (offset >= kReferenceLoadMinFarOffset) {
2840*795d594fSAndroid Build Coastguard Worker locations->AddTemp(FixedTempLocation());
2841*795d594fSAndroid Build Coastguard Worker }
2842*795d594fSAndroid Build Coastguard Worker } else if (!instruction->GetArray()->IsIntermediateAddress()) {
2843*795d594fSAndroid Build Coastguard Worker // We need a non-scratch temporary for the array data pointer in
2844*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier() for the case with no
2845*795d594fSAndroid Build Coastguard Worker // intermediate address.
2846*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
2847*795d594fSAndroid Build Coastguard Worker }
2848*795d594fSAndroid Build Coastguard Worker }
2849*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2850*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2851*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(instruction->GetType())) {
2852*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2853*795d594fSAndroid Build Coastguard Worker } else {
2854*795d594fSAndroid Build Coastguard Worker // The output overlaps for an object array get for non-Baker read barriers: we do not want
2855*795d594fSAndroid Build Coastguard Worker // the load to overwrite the object's location, as we need it to emit the read barrier.
2856*795d594fSAndroid Build Coastguard Worker // Baker read barrier implementation with introspection does not have this restriction.
2857*795d594fSAndroid Build Coastguard Worker bool overlap = object_array_get_with_read_barrier && !kUseBakerReadBarrier;
2858*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(),
2859*795d594fSAndroid Build Coastguard Worker overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
2860*795d594fSAndroid Build Coastguard Worker }
2861*795d594fSAndroid Build Coastguard Worker }
2862*795d594fSAndroid Build Coastguard Worker
VisitArrayGet(HArrayGet * instruction)2863*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
2864*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
2865*795d594fSAndroid Build Coastguard Worker Register obj = InputRegisterAt(instruction, 0);
2866*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
2867*795d594fSAndroid Build Coastguard Worker Location index = locations->InAt(1);
2868*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
2869*795d594fSAndroid Build Coastguard Worker uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
2870*795d594fSAndroid Build Coastguard Worker const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
2871*795d594fSAndroid Build Coastguard Worker instruction->IsStringCharAt();
2872*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
2873*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
2874*795d594fSAndroid Build Coastguard Worker
2875*795d594fSAndroid Build Coastguard Worker // The non-Baker read barrier instrumentation of object ArrayGet instructions
2876*795d594fSAndroid Build Coastguard Worker // does not support the HIntermediateAddress instruction.
2877*795d594fSAndroid Build Coastguard Worker DCHECK(!((type == DataType::Type::kReference) &&
2878*795d594fSAndroid Build Coastguard Worker instruction->GetArray()->IsIntermediateAddress() &&
2879*795d594fSAndroid Build Coastguard Worker codegen_->EmitNonBakerReadBarrier()));
2880*795d594fSAndroid Build Coastguard Worker
2881*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference && codegen_->EmitBakerReadBarrier()) {
2882*795d594fSAndroid Build Coastguard Worker // Object ArrayGet with Baker's read barrier case.
2883*795d594fSAndroid Build Coastguard Worker // Note that a potential implicit null check is handled in the
2884*795d594fSAndroid Build Coastguard Worker // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
2885*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
2886*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
2887*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->GetArray()->IsIntermediateAddress());
2888*795d594fSAndroid Build Coastguard Worker // Array load with a constant index can be treated as a field load.
2889*795d594fSAndroid Build Coastguard Worker offset += Int64FromLocation(index) << DataType::SizeShift(type);
2890*795d594fSAndroid Build Coastguard Worker Location maybe_temp =
2891*795d594fSAndroid Build Coastguard Worker (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
2892*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
2893*795d594fSAndroid Build Coastguard Worker out,
2894*795d594fSAndroid Build Coastguard Worker obj.W(),
2895*795d594fSAndroid Build Coastguard Worker offset,
2896*795d594fSAndroid Build Coastguard Worker maybe_temp,
2897*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ false,
2898*795d594fSAndroid Build Coastguard Worker /* use_load_acquire= */ false);
2899*795d594fSAndroid Build Coastguard Worker } else {
2900*795d594fSAndroid Build Coastguard Worker codegen_->GenerateArrayLoadWithBakerReadBarrier(
2901*795d594fSAndroid Build Coastguard Worker instruction, out, obj.W(), offset, index, /* needs_null_check= */ false);
2902*795d594fSAndroid Build Coastguard Worker }
2903*795d594fSAndroid Build Coastguard Worker } else {
2904*795d594fSAndroid Build Coastguard Worker // General case.
2905*795d594fSAndroid Build Coastguard Worker MemOperand source = HeapOperand(obj);
2906*795d594fSAndroid Build Coastguard Worker Register length;
2907*795d594fSAndroid Build Coastguard Worker if (maybe_compressed_char_at) {
2908*795d594fSAndroid Build Coastguard Worker uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2909*795d594fSAndroid Build Coastguard Worker length = temps.AcquireW();
2910*795d594fSAndroid Build Coastguard Worker {
2911*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
2912*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
2913*795d594fSAndroid Build Coastguard Worker
2914*795d594fSAndroid Build Coastguard Worker if (instruction->GetArray()->IsIntermediateAddress()) {
2915*795d594fSAndroid Build Coastguard Worker DCHECK_LT(count_offset, offset);
2916*795d594fSAndroid Build Coastguard Worker int64_t adjusted_offset =
2917*795d594fSAndroid Build Coastguard Worker static_cast<int64_t>(count_offset) - static_cast<int64_t>(offset);
2918*795d594fSAndroid Build Coastguard Worker // Note that `adjusted_offset` is negative, so this will be a LDUR.
2919*795d594fSAndroid Build Coastguard Worker __ Ldr(length, MemOperand(obj.X(), adjusted_offset));
2920*795d594fSAndroid Build Coastguard Worker } else {
2921*795d594fSAndroid Build Coastguard Worker __ Ldr(length, HeapOperand(obj, count_offset));
2922*795d594fSAndroid Build Coastguard Worker }
2923*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
2924*795d594fSAndroid Build Coastguard Worker }
2925*795d594fSAndroid Build Coastguard Worker }
2926*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
2927*795d594fSAndroid Build Coastguard Worker if (maybe_compressed_char_at) {
2928*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label uncompressed_load, done;
2929*795d594fSAndroid Build Coastguard Worker static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2930*795d594fSAndroid Build Coastguard Worker "Expecting 0=compressed, 1=uncompressed");
2931*795d594fSAndroid Build Coastguard Worker __ Tbnz(length.W(), 0, &uncompressed_load);
2932*795d594fSAndroid Build Coastguard Worker __ Ldrb(Register(OutputCPURegister(instruction)),
2933*795d594fSAndroid Build Coastguard Worker HeapOperand(obj, offset + Int64FromLocation(index)));
2934*795d594fSAndroid Build Coastguard Worker __ B(&done);
2935*795d594fSAndroid Build Coastguard Worker __ Bind(&uncompressed_load);
2936*795d594fSAndroid Build Coastguard Worker __ Ldrh(Register(OutputCPURegister(instruction)),
2937*795d594fSAndroid Build Coastguard Worker HeapOperand(obj, offset + (Int64FromLocation(index) << 1)));
2938*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
2939*795d594fSAndroid Build Coastguard Worker } else {
2940*795d594fSAndroid Build Coastguard Worker offset += Int64FromLocation(index) << DataType::SizeShift(type);
2941*795d594fSAndroid Build Coastguard Worker source = HeapOperand(obj, offset);
2942*795d594fSAndroid Build Coastguard Worker }
2943*795d594fSAndroid Build Coastguard Worker } else {
2944*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(obj);
2945*795d594fSAndroid Build Coastguard Worker if (instruction->GetArray()->IsIntermediateAddress()) {
2946*795d594fSAndroid Build Coastguard Worker // We do not need to compute the intermediate address from the array: the
2947*795d594fSAndroid Build Coastguard Worker // input instruction has done it already. See the comment in
2948*795d594fSAndroid Build Coastguard Worker // `TryExtractArrayAccessAddress()`.
2949*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
2950*795d594fSAndroid Build Coastguard Worker HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
2951*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
2952*795d594fSAndroid Build Coastguard Worker }
2953*795d594fSAndroid Build Coastguard Worker temp = obj;
2954*795d594fSAndroid Build Coastguard Worker } else {
2955*795d594fSAndroid Build Coastguard Worker __ Add(temp, obj, offset);
2956*795d594fSAndroid Build Coastguard Worker }
2957*795d594fSAndroid Build Coastguard Worker if (maybe_compressed_char_at) {
2958*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label uncompressed_load, done;
2959*795d594fSAndroid Build Coastguard Worker static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2960*795d594fSAndroid Build Coastguard Worker "Expecting 0=compressed, 1=uncompressed");
2961*795d594fSAndroid Build Coastguard Worker __ Tbnz(length.W(), 0, &uncompressed_load);
2962*795d594fSAndroid Build Coastguard Worker __ Ldrb(Register(OutputCPURegister(instruction)),
2963*795d594fSAndroid Build Coastguard Worker HeapOperand(temp, XRegisterFrom(index), LSL, 0));
2964*795d594fSAndroid Build Coastguard Worker __ B(&done);
2965*795d594fSAndroid Build Coastguard Worker __ Bind(&uncompressed_load);
2966*795d594fSAndroid Build Coastguard Worker __ Ldrh(Register(OutputCPURegister(instruction)),
2967*795d594fSAndroid Build Coastguard Worker HeapOperand(temp, XRegisterFrom(index), LSL, 1));
2968*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
2969*795d594fSAndroid Build Coastguard Worker } else {
2970*795d594fSAndroid Build Coastguard Worker source = HeapOperand(temp, XRegisterFrom(index), LSL, DataType::SizeShift(type));
2971*795d594fSAndroid Build Coastguard Worker }
2972*795d594fSAndroid Build Coastguard Worker }
2973*795d594fSAndroid Build Coastguard Worker if (!maybe_compressed_char_at) {
2974*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
2975*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
2976*795d594fSAndroid Build Coastguard Worker codegen_->Load(type, OutputCPURegister(instruction), source);
2977*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
2978*795d594fSAndroid Build Coastguard Worker }
2979*795d594fSAndroid Build Coastguard Worker
2980*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
2981*795d594fSAndroid Build Coastguard Worker static_assert(
2982*795d594fSAndroid Build Coastguard Worker sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
2983*795d594fSAndroid Build Coastguard Worker "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
2984*795d594fSAndroid Build Coastguard Worker Location obj_loc = locations->InAt(0);
2985*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
2986*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, obj_loc, offset);
2987*795d594fSAndroid Build Coastguard Worker } else {
2988*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, obj_loc, offset, index);
2989*795d594fSAndroid Build Coastguard Worker }
2990*795d594fSAndroid Build Coastguard Worker }
2991*795d594fSAndroid Build Coastguard Worker }
2992*795d594fSAndroid Build Coastguard Worker }
2993*795d594fSAndroid Build Coastguard Worker
VisitArrayLength(HArrayLength * instruction)2994*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
2995*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
2996*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
2997*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2998*795d594fSAndroid Build Coastguard Worker }
2999*795d594fSAndroid Build Coastguard Worker
VisitArrayLength(HArrayLength * instruction)3000*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
3001*795d594fSAndroid Build Coastguard Worker uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
3002*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register out = OutputRegister(instruction);
3003*795d594fSAndroid Build Coastguard Worker {
3004*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
3005*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
3006*795d594fSAndroid Build Coastguard Worker __ Ldr(out, HeapOperand(InputRegisterAt(instruction, 0), offset));
3007*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
3008*795d594fSAndroid Build Coastguard Worker }
3009*795d594fSAndroid Build Coastguard Worker // Mask out compression flag from String's array length.
3010*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression && instruction->IsStringLength()) {
3011*795d594fSAndroid Build Coastguard Worker __ Lsr(out.W(), out.W(), 1u);
3012*795d594fSAndroid Build Coastguard Worker }
3013*795d594fSAndroid Build Coastguard Worker }
3014*795d594fSAndroid Build Coastguard Worker
VisitArraySet(HArraySet * instruction)3015*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
3016*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = instruction->GetComponentType();
3017*795d594fSAndroid Build Coastguard Worker
3018*795d594fSAndroid Build Coastguard Worker bool needs_type_check = instruction->NeedsTypeCheck();
3019*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
3020*795d594fSAndroid Build Coastguard Worker instruction,
3021*795d594fSAndroid Build Coastguard Worker needs_type_check ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
3022*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3023*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetIndex()));
3024*795d594fSAndroid Build Coastguard Worker HInstruction* value = instruction->GetValue();
3025*795d594fSAndroid Build Coastguard Worker if (IsZeroBitPattern(value)) {
3026*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::ConstantLocation(value));
3027*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsFloatingPointType(value_type)) {
3028*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresFpuRegister());
3029*795d594fSAndroid Build Coastguard Worker } else {
3030*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
3031*795d594fSAndroid Build Coastguard Worker }
3032*795d594fSAndroid Build Coastguard Worker }
3033*795d594fSAndroid Build Coastguard Worker
VisitArraySet(HArraySet * instruction)3034*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
3035*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = instruction->GetComponentType();
3036*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3037*795d594fSAndroid Build Coastguard Worker bool needs_type_check = instruction->NeedsTypeCheck();
3038*795d594fSAndroid Build Coastguard Worker const WriteBarrierKind write_barrier_kind = instruction->GetWriteBarrierKind();
3039*795d594fSAndroid Build Coastguard Worker bool needs_write_barrier =
3040*795d594fSAndroid Build Coastguard Worker codegen_->StoreNeedsWriteBarrier(value_type, instruction->GetValue(), write_barrier_kind);
3041*795d594fSAndroid Build Coastguard Worker
3042*795d594fSAndroid Build Coastguard Worker Register array = InputRegisterAt(instruction, 0);
3043*795d594fSAndroid Build Coastguard Worker CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 2);
3044*795d594fSAndroid Build Coastguard Worker CPURegister source = value;
3045*795d594fSAndroid Build Coastguard Worker Location index = locations->InAt(1);
3046*795d594fSAndroid Build Coastguard Worker size_t offset = mirror::Array::DataOffset(DataType::Size(value_type)).Uint32Value();
3047*795d594fSAndroid Build Coastguard Worker MemOperand destination = HeapOperand(array);
3048*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
3049*795d594fSAndroid Build Coastguard Worker
3050*795d594fSAndroid Build Coastguard Worker if (!needs_write_barrier) {
3051*795d594fSAndroid Build Coastguard Worker if (codegen_->ShouldCheckGCCard(value_type, instruction->GetValue(), write_barrier_kind)) {
3052*795d594fSAndroid Build Coastguard Worker codegen_->CheckGCCardIsValid(array);
3053*795d594fSAndroid Build Coastguard Worker }
3054*795d594fSAndroid Build Coastguard Worker
3055*795d594fSAndroid Build Coastguard Worker DCHECK(!needs_type_check);
3056*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
3057*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
3058*795d594fSAndroid Build Coastguard Worker offset += Int64FromLocation(index) << DataType::SizeShift(value_type);
3059*795d594fSAndroid Build Coastguard Worker destination = HeapOperand(array, offset);
3060*795d594fSAndroid Build Coastguard Worker } else {
3061*795d594fSAndroid Build Coastguard Worker Register temp_dest = temps.AcquireSameSizeAs(array);
3062*795d594fSAndroid Build Coastguard Worker if (instruction->GetArray()->IsIntermediateAddress()) {
3063*795d594fSAndroid Build Coastguard Worker // We do not need to compute the intermediate address from the array: the
3064*795d594fSAndroid Build Coastguard Worker // input instruction has done it already. See the comment in
3065*795d594fSAndroid Build Coastguard Worker // `TryExtractArrayAccessAddress()`.
3066*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
3067*795d594fSAndroid Build Coastguard Worker HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
3068*795d594fSAndroid Build Coastguard Worker DCHECK(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
3069*795d594fSAndroid Build Coastguard Worker }
3070*795d594fSAndroid Build Coastguard Worker temp_dest = array;
3071*795d594fSAndroid Build Coastguard Worker } else {
3072*795d594fSAndroid Build Coastguard Worker __ Add(temp_dest, array, offset);
3073*795d594fSAndroid Build Coastguard Worker }
3074*795d594fSAndroid Build Coastguard Worker destination = HeapOperand(temp_dest,
3075*795d594fSAndroid Build Coastguard Worker XRegisterFrom(index),
3076*795d594fSAndroid Build Coastguard Worker LSL,
3077*795d594fSAndroid Build Coastguard Worker DataType::SizeShift(value_type));
3078*795d594fSAndroid Build Coastguard Worker }
3079*795d594fSAndroid Build Coastguard Worker
3080*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
3081*795d594fSAndroid Build Coastguard Worker DCHECK(value.IsW());
3082*795d594fSAndroid Build Coastguard Worker Register temp_src = temps.AcquireW();
3083*795d594fSAndroid Build Coastguard Worker __ Mov(temp_src, value.W());
3084*795d594fSAndroid Build Coastguard Worker GetAssembler()->PoisonHeapReference(temp_src.W());
3085*795d594fSAndroid Build Coastguard Worker source = temp_src;
3086*795d594fSAndroid Build Coastguard Worker }
3087*795d594fSAndroid Build Coastguard Worker
3088*795d594fSAndroid Build Coastguard Worker {
3089*795d594fSAndroid Build Coastguard Worker // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
3090*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
3091*795d594fSAndroid Build Coastguard Worker codegen_->Store(value_type, source, destination);
3092*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
3093*795d594fSAndroid Build Coastguard Worker }
3094*795d594fSAndroid Build Coastguard Worker } else {
3095*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->GetArray()->IsIntermediateAddress());
3096*795d594fSAndroid Build Coastguard Worker bool can_value_be_null = true;
3097*795d594fSAndroid Build Coastguard Worker // The WriteBarrierKind::kEmitNotBeingReliedOn case is able to skip the write barrier when its
3098*795d594fSAndroid Build Coastguard Worker // value is null (without an extra CompareAndBranchIfZero since we already checked if the
3099*795d594fSAndroid Build Coastguard Worker // value is null for the type check).
3100*795d594fSAndroid Build Coastguard Worker bool skip_marking_gc_card = false;
3101*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = nullptr;
3102*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label skip_writing_card;
3103*795d594fSAndroid Build Coastguard Worker if (!Register(value).IsZero()) {
3104*795d594fSAndroid Build Coastguard Worker can_value_be_null = instruction->GetValueCanBeNull();
3105*795d594fSAndroid Build Coastguard Worker skip_marking_gc_card =
3106*795d594fSAndroid Build Coastguard Worker can_value_be_null && write_barrier_kind == WriteBarrierKind::kEmitNotBeingReliedOn;
3107*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label do_store;
3108*795d594fSAndroid Build Coastguard Worker if (can_value_be_null) {
3109*795d594fSAndroid Build Coastguard Worker if (skip_marking_gc_card) {
3110*795d594fSAndroid Build Coastguard Worker __ Cbz(Register(value), &skip_writing_card);
3111*795d594fSAndroid Build Coastguard Worker } else {
3112*795d594fSAndroid Build Coastguard Worker __ Cbz(Register(value), &do_store);
3113*795d594fSAndroid Build Coastguard Worker }
3114*795d594fSAndroid Build Coastguard Worker }
3115*795d594fSAndroid Build Coastguard Worker
3116*795d594fSAndroid Build Coastguard Worker if (needs_type_check) {
3117*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathARM64(instruction);
3118*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3119*795d594fSAndroid Build Coastguard Worker
3120*795d594fSAndroid Build Coastguard Worker const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3121*795d594fSAndroid Build Coastguard Worker const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3122*795d594fSAndroid Build Coastguard Worker const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3123*795d594fSAndroid Build Coastguard Worker
3124*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
3125*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(array);
3126*795d594fSAndroid Build Coastguard Worker Register temp2 = temps.AcquireSameSizeAs(array);
3127*795d594fSAndroid Build Coastguard Worker
3128*795d594fSAndroid Build Coastguard Worker // Note that when Baker read barriers are enabled, the type
3129*795d594fSAndroid Build Coastguard Worker // checks are performed without read barriers. This is fine,
3130*795d594fSAndroid Build Coastguard Worker // even in the case where a class object is in the from-space
3131*795d594fSAndroid Build Coastguard Worker // after the flip, as a comparison involving such a type would
3132*795d594fSAndroid Build Coastguard Worker // not produce a false positive; it may of course produce a
3133*795d594fSAndroid Build Coastguard Worker // false negative, in which case we would take the ArraySet
3134*795d594fSAndroid Build Coastguard Worker // slow path.
3135*795d594fSAndroid Build Coastguard Worker
3136*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = array->klass_
3137*795d594fSAndroid Build Coastguard Worker {
3138*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
3139*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
3140*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(array, class_offset));
3141*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
3142*795d594fSAndroid Build Coastguard Worker }
3143*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp);
3144*795d594fSAndroid Build Coastguard Worker
3145*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->component_type_
3146*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(temp, component_offset));
3147*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp2 = value->klass_
3148*795d594fSAndroid Build Coastguard Worker __ Ldr(temp2, HeapOperand(Register(value), class_offset));
3149*795d594fSAndroid Build Coastguard Worker // If heap poisoning is enabled, no need to unpoison `temp`
3150*795d594fSAndroid Build Coastguard Worker // nor `temp2`, as we are comparing two poisoned references.
3151*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, temp2);
3152*795d594fSAndroid Build Coastguard Worker
3153*795d594fSAndroid Build Coastguard Worker if (instruction->StaticTypeOfArrayIsObjectArray()) {
3154*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label do_put;
3155*795d594fSAndroid Build Coastguard Worker __ B(eq, &do_put);
3156*795d594fSAndroid Build Coastguard Worker // If heap poisoning is enabled, the `temp` reference has
3157*795d594fSAndroid Build Coastguard Worker // not been unpoisoned yet; unpoison it now.
3158*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp);
3159*795d594fSAndroid Build Coastguard Worker
3160*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->super_class_
3161*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(temp, super_offset));
3162*795d594fSAndroid Build Coastguard Worker // If heap poisoning is enabled, no need to unpoison
3163*795d594fSAndroid Build Coastguard Worker // `temp`, as we are comparing against null below.
3164*795d594fSAndroid Build Coastguard Worker __ Cbnz(temp, slow_path->GetEntryLabel());
3165*795d594fSAndroid Build Coastguard Worker __ Bind(&do_put);
3166*795d594fSAndroid Build Coastguard Worker } else {
3167*795d594fSAndroid Build Coastguard Worker __ B(ne, slow_path->GetEntryLabel());
3168*795d594fSAndroid Build Coastguard Worker }
3169*795d594fSAndroid Build Coastguard Worker }
3170*795d594fSAndroid Build Coastguard Worker
3171*795d594fSAndroid Build Coastguard Worker if (can_value_be_null && !skip_marking_gc_card) {
3172*795d594fSAndroid Build Coastguard Worker DCHECK(do_store.IsLinked());
3173*795d594fSAndroid Build Coastguard Worker __ Bind(&do_store);
3174*795d594fSAndroid Build Coastguard Worker }
3175*795d594fSAndroid Build Coastguard Worker }
3176*795d594fSAndroid Build Coastguard Worker
3177*795d594fSAndroid Build Coastguard Worker DCHECK_NE(write_barrier_kind, WriteBarrierKind::kDontEmit);
3178*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(Register(value).IsZero(),
3179*795d594fSAndroid Build Coastguard Worker write_barrier_kind == WriteBarrierKind::kEmitBeingReliedOn);
3180*795d594fSAndroid Build Coastguard Worker codegen_->MarkGCCard(array);
3181*795d594fSAndroid Build Coastguard Worker
3182*795d594fSAndroid Build Coastguard Worker if (skip_marking_gc_card) {
3183*795d594fSAndroid Build Coastguard Worker // Note that we don't check that the GC card is valid as it can be correctly clean.
3184*795d594fSAndroid Build Coastguard Worker DCHECK(skip_writing_card.IsLinked());
3185*795d594fSAndroid Build Coastguard Worker __ Bind(&skip_writing_card);
3186*795d594fSAndroid Build Coastguard Worker }
3187*795d594fSAndroid Build Coastguard Worker
3188*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(masm);
3189*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences) {
3190*795d594fSAndroid Build Coastguard Worker DCHECK(value.IsW());
3191*795d594fSAndroid Build Coastguard Worker Register temp_source = temps.AcquireW();
3192*795d594fSAndroid Build Coastguard Worker __ Mov(temp_source, value.W());
3193*795d594fSAndroid Build Coastguard Worker GetAssembler()->PoisonHeapReference(temp_source);
3194*795d594fSAndroid Build Coastguard Worker source = temp_source;
3195*795d594fSAndroid Build Coastguard Worker }
3196*795d594fSAndroid Build Coastguard Worker
3197*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
3198*795d594fSAndroid Build Coastguard Worker offset += Int64FromLocation(index) << DataType::SizeShift(value_type);
3199*795d594fSAndroid Build Coastguard Worker destination = HeapOperand(array, offset);
3200*795d594fSAndroid Build Coastguard Worker } else {
3201*795d594fSAndroid Build Coastguard Worker Register temp_base = temps.AcquireSameSizeAs(array);
3202*795d594fSAndroid Build Coastguard Worker __ Add(temp_base, array, offset);
3203*795d594fSAndroid Build Coastguard Worker destination = HeapOperand(temp_base,
3204*795d594fSAndroid Build Coastguard Worker XRegisterFrom(index),
3205*795d594fSAndroid Build Coastguard Worker LSL,
3206*795d594fSAndroid Build Coastguard Worker DataType::SizeShift(value_type));
3207*795d594fSAndroid Build Coastguard Worker }
3208*795d594fSAndroid Build Coastguard Worker
3209*795d594fSAndroid Build Coastguard Worker {
3210*795d594fSAndroid Build Coastguard Worker // Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
3211*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
3212*795d594fSAndroid Build Coastguard Worker __ Str(source, destination);
3213*795d594fSAndroid Build Coastguard Worker
3214*795d594fSAndroid Build Coastguard Worker if (can_value_be_null || !needs_type_check) {
3215*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(instruction);
3216*795d594fSAndroid Build Coastguard Worker }
3217*795d594fSAndroid Build Coastguard Worker }
3218*795d594fSAndroid Build Coastguard Worker
3219*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
3220*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
3221*795d594fSAndroid Build Coastguard Worker }
3222*795d594fSAndroid Build Coastguard Worker }
3223*795d594fSAndroid Build Coastguard Worker }
3224*795d594fSAndroid Build Coastguard Worker
VisitBoundsCheck(HBoundsCheck * instruction)3225*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
3226*795d594fSAndroid Build Coastguard Worker RegisterSet caller_saves = RegisterSet::Empty();
3227*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
3228*795d594fSAndroid Build Coastguard Worker caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
3229*795d594fSAndroid Build Coastguard Worker caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1).GetCode()));
3230*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
3231*795d594fSAndroid Build Coastguard Worker
3232*795d594fSAndroid Build Coastguard Worker // If both index and length are constant, we can check the bounds statically and
3233*795d594fSAndroid Build Coastguard Worker // generate code accordingly. We want to make sure we generate constant locations
3234*795d594fSAndroid Build Coastguard Worker // in that case, regardless of whether they are encodable in the comparison or not.
3235*795d594fSAndroid Build Coastguard Worker HInstruction* index = instruction->InputAt(0);
3236*795d594fSAndroid Build Coastguard Worker HInstruction* length = instruction->InputAt(1);
3237*795d594fSAndroid Build Coastguard Worker bool both_const = index->IsConstant() && length->IsConstant();
3238*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, both_const
3239*795d594fSAndroid Build Coastguard Worker ? Location::ConstantLocation(index)
3240*795d594fSAndroid Build Coastguard Worker : ARM64EncodableConstantOrRegister(index, instruction));
3241*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, both_const
3242*795d594fSAndroid Build Coastguard Worker ? Location::ConstantLocation(length)
3243*795d594fSAndroid Build Coastguard Worker : ARM64EncodableConstantOrRegister(length, instruction));
3244*795d594fSAndroid Build Coastguard Worker }
3245*795d594fSAndroid Build Coastguard Worker
VisitBoundsCheck(HBoundsCheck * instruction)3246*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
3247*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3248*795d594fSAndroid Build Coastguard Worker Location index_loc = locations->InAt(0);
3249*795d594fSAndroid Build Coastguard Worker Location length_loc = locations->InAt(1);
3250*795d594fSAndroid Build Coastguard Worker
3251*795d594fSAndroid Build Coastguard Worker int cmp_first_input = 0;
3252*795d594fSAndroid Build Coastguard Worker int cmp_second_input = 1;
3253*795d594fSAndroid Build Coastguard Worker Condition cond = hs;
3254*795d594fSAndroid Build Coastguard Worker
3255*795d594fSAndroid Build Coastguard Worker if (index_loc.IsConstant()) {
3256*795d594fSAndroid Build Coastguard Worker int64_t index = Int64FromLocation(index_loc);
3257*795d594fSAndroid Build Coastguard Worker if (length_loc.IsConstant()) {
3258*795d594fSAndroid Build Coastguard Worker int64_t length = Int64FromLocation(length_loc);
3259*795d594fSAndroid Build Coastguard Worker if (index < 0 || index >= length) {
3260*795d594fSAndroid Build Coastguard Worker BoundsCheckSlowPathARM64* slow_path =
3261*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathARM64(instruction);
3262*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3263*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
3264*795d594fSAndroid Build Coastguard Worker } else {
3265*795d594fSAndroid Build Coastguard Worker // BCE will remove the bounds check if we are guaranteed to pass.
3266*795d594fSAndroid Build Coastguard Worker // However, some optimization after BCE may have generated this, and we should not
3267*795d594fSAndroid Build Coastguard Worker // generate a bounds check if it is a valid range.
3268*795d594fSAndroid Build Coastguard Worker }
3269*795d594fSAndroid Build Coastguard Worker return;
3270*795d594fSAndroid Build Coastguard Worker }
3271*795d594fSAndroid Build Coastguard Worker // Only the index is constant: change the order of the operands and commute the condition
3272*795d594fSAndroid Build Coastguard Worker // so we can use an immediate constant for the index (only the second input to a cmp
3273*795d594fSAndroid Build Coastguard Worker // instruction can be an immediate).
3274*795d594fSAndroid Build Coastguard Worker cmp_first_input = 1;
3275*795d594fSAndroid Build Coastguard Worker cmp_second_input = 0;
3276*795d594fSAndroid Build Coastguard Worker cond = ls;
3277*795d594fSAndroid Build Coastguard Worker }
3278*795d594fSAndroid Build Coastguard Worker BoundsCheckSlowPathARM64* slow_path =
3279*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathARM64(instruction);
3280*795d594fSAndroid Build Coastguard Worker __ Cmp(InputRegisterAt(instruction, cmp_first_input),
3281*795d594fSAndroid Build Coastguard Worker InputOperandAt(instruction, cmp_second_input));
3282*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3283*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel(), cond);
3284*795d594fSAndroid Build Coastguard Worker }
3285*795d594fSAndroid Build Coastguard Worker
VisitClinitCheck(HClinitCheck * check)3286*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
3287*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3288*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3289*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3290*795d594fSAndroid Build Coastguard Worker if (check->HasUses()) {
3291*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::SameAsFirstInput());
3292*795d594fSAndroid Build Coastguard Worker }
3293*795d594fSAndroid Build Coastguard Worker // Rely on the type initialization to save everything we need.
3294*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
3295*795d594fSAndroid Build Coastguard Worker }
3296*795d594fSAndroid Build Coastguard Worker
VisitClinitCheck(HClinitCheck * check)3297*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
3298*795d594fSAndroid Build Coastguard Worker // We assume the class is not null.
3299*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
3300*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) LoadClassSlowPathARM64(check->GetLoadClass(), check);
3301*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3302*795d594fSAndroid Build Coastguard Worker GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
3303*795d594fSAndroid Build Coastguard Worker }
3304*795d594fSAndroid Build Coastguard Worker
IsFloatingPointZeroConstant(HInstruction * inst)3305*795d594fSAndroid Build Coastguard Worker static bool IsFloatingPointZeroConstant(HInstruction* inst) {
3306*795d594fSAndroid Build Coastguard Worker return (inst->IsFloatConstant() && (inst->AsFloatConstant()->IsArithmeticZero()))
3307*795d594fSAndroid Build Coastguard Worker || (inst->IsDoubleConstant() && (inst->AsDoubleConstant()->IsArithmeticZero()));
3308*795d594fSAndroid Build Coastguard Worker }
3309*795d594fSAndroid Build Coastguard Worker
GenerateFcmp(HInstruction * instruction)3310*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateFcmp(HInstruction* instruction) {
3311*795d594fSAndroid Build Coastguard Worker VRegister lhs_reg = InputFPRegisterAt(instruction, 0);
3312*795d594fSAndroid Build Coastguard Worker Location rhs_loc = instruction->GetLocations()->InAt(1);
3313*795d594fSAndroid Build Coastguard Worker if (rhs_loc.IsConstant()) {
3314*795d594fSAndroid Build Coastguard Worker // 0.0 is the only immediate that can be encoded directly in
3315*795d594fSAndroid Build Coastguard Worker // an FCMP instruction.
3316*795d594fSAndroid Build Coastguard Worker //
3317*795d594fSAndroid Build Coastguard Worker // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
3318*795d594fSAndroid Build Coastguard Worker // specify that in a floating-point comparison, positive zero
3319*795d594fSAndroid Build Coastguard Worker // and negative zero are considered equal, so we can use the
3320*795d594fSAndroid Build Coastguard Worker // literal 0.0 for both cases here.
3321*795d594fSAndroid Build Coastguard Worker //
3322*795d594fSAndroid Build Coastguard Worker // Note however that some methods (Float.equal, Float.compare,
3323*795d594fSAndroid Build Coastguard Worker // Float.compareTo, Double.equal, Double.compare,
3324*795d594fSAndroid Build Coastguard Worker // Double.compareTo, Math.max, Math.min, StrictMath.max,
3325*795d594fSAndroid Build Coastguard Worker // StrictMath.min) consider 0.0 to be (strictly) greater than
3326*795d594fSAndroid Build Coastguard Worker // -0.0. So if we ever translate calls to these methods into a
3327*795d594fSAndroid Build Coastguard Worker // HCompare instruction, we must handle the -0.0 case with
3328*795d594fSAndroid Build Coastguard Worker // care here.
3329*795d594fSAndroid Build Coastguard Worker DCHECK(IsFloatingPointZeroConstant(rhs_loc.GetConstant()));
3330*795d594fSAndroid Build Coastguard Worker __ Fcmp(lhs_reg, 0.0);
3331*795d594fSAndroid Build Coastguard Worker } else {
3332*795d594fSAndroid Build Coastguard Worker __ Fcmp(lhs_reg, InputFPRegisterAt(instruction, 1));
3333*795d594fSAndroid Build Coastguard Worker }
3334*795d594fSAndroid Build Coastguard Worker }
3335*795d594fSAndroid Build Coastguard Worker
VisitCompare(HCompare * compare)3336*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
3337*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3338*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
3339*795d594fSAndroid Build Coastguard Worker DataType::Type compare_type = compare->GetComparisonType();
3340*795d594fSAndroid Build Coastguard Worker HInstruction* rhs = compare->InputAt(1);
3341*795d594fSAndroid Build Coastguard Worker switch (compare_type) {
3342*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
3343*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
3344*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
3345*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
3346*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
3347*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
3348*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
3349*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
3350*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64: {
3351*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3352*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, ARM64EncodableConstantOrRegister(rhs, compare));
3353*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3354*795d594fSAndroid Build Coastguard Worker break;
3355*795d594fSAndroid Build Coastguard Worker }
3356*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
3357*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
3358*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
3359*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1,
3360*795d594fSAndroid Build Coastguard Worker IsFloatingPointZeroConstant(rhs)
3361*795d594fSAndroid Build Coastguard Worker ? Location::ConstantLocation(rhs)
3362*795d594fSAndroid Build Coastguard Worker : Location::RequiresFpuRegister());
3363*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
3364*795d594fSAndroid Build Coastguard Worker break;
3365*795d594fSAndroid Build Coastguard Worker }
3366*795d594fSAndroid Build Coastguard Worker default:
3367*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for compare operation " << compare_type;
3368*795d594fSAndroid Build Coastguard Worker }
3369*795d594fSAndroid Build Coastguard Worker }
3370*795d594fSAndroid Build Coastguard Worker
VisitCompare(HCompare * compare)3371*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
3372*795d594fSAndroid Build Coastguard Worker DataType::Type compare_type = compare->GetComparisonType();
3373*795d594fSAndroid Build Coastguard Worker
3374*795d594fSAndroid Build Coastguard Worker // 0 if: left == right
3375*795d594fSAndroid Build Coastguard Worker // 1 if: left > right
3376*795d594fSAndroid Build Coastguard Worker // -1 if: left < right
3377*795d594fSAndroid Build Coastguard Worker Condition less_cond = lt;
3378*795d594fSAndroid Build Coastguard Worker switch (compare_type) {
3379*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
3380*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
3381*795d594fSAndroid Build Coastguard Worker less_cond = lo;
3382*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
3383*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
3384*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
3385*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
3386*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
3387*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
3388*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
3389*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
3390*795d594fSAndroid Build Coastguard Worker Register result = OutputRegister(compare);
3391*795d594fSAndroid Build Coastguard Worker Register left = InputRegisterAt(compare, 0);
3392*795d594fSAndroid Build Coastguard Worker Operand right = InputOperandAt(compare, 1);
3393*795d594fSAndroid Build Coastguard Worker __ Cmp(left, right);
3394*795d594fSAndroid Build Coastguard Worker __ Cset(result, ne); // result == +1 if NE or 0 otherwise
3395*795d594fSAndroid Build Coastguard Worker __ Cneg(result, result, less_cond); // result == -1 if LT or unchanged otherwise
3396*795d594fSAndroid Build Coastguard Worker break;
3397*795d594fSAndroid Build Coastguard Worker }
3398*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
3399*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
3400*795d594fSAndroid Build Coastguard Worker Register result = OutputRegister(compare);
3401*795d594fSAndroid Build Coastguard Worker GenerateFcmp(compare);
3402*795d594fSAndroid Build Coastguard Worker __ Cset(result, ne);
3403*795d594fSAndroid Build Coastguard Worker __ Cneg(result, result, ARM64FPCondition(kCondLT, compare->IsGtBias()));
3404*795d594fSAndroid Build Coastguard Worker break;
3405*795d594fSAndroid Build Coastguard Worker }
3406*795d594fSAndroid Build Coastguard Worker default:
3407*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unimplemented compare type " << compare_type;
3408*795d594fSAndroid Build Coastguard Worker }
3409*795d594fSAndroid Build Coastguard Worker }
3410*795d594fSAndroid Build Coastguard Worker
HandleCondition(HCondition * instruction)3411*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleCondition(HCondition* instruction) {
3412*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
3413*795d594fSAndroid Build Coastguard Worker
3414*795d594fSAndroid Build Coastguard Worker HInstruction* rhs = instruction->InputAt(1);
3415*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
3416*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
3417*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1,
3418*795d594fSAndroid Build Coastguard Worker IsFloatingPointZeroConstant(rhs)
3419*795d594fSAndroid Build Coastguard Worker ? Location::ConstantLocation(rhs)
3420*795d594fSAndroid Build Coastguard Worker : Location::RequiresFpuRegister());
3421*795d594fSAndroid Build Coastguard Worker } else {
3422*795d594fSAndroid Build Coastguard Worker // Integer cases.
3423*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3424*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, ARM64EncodableConstantOrRegister(rhs, instruction));
3425*795d594fSAndroid Build Coastguard Worker }
3426*795d594fSAndroid Build Coastguard Worker
3427*795d594fSAndroid Build Coastguard Worker if (!instruction->IsEmittedAtUseSite()) {
3428*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3429*795d594fSAndroid Build Coastguard Worker }
3430*795d594fSAndroid Build Coastguard Worker }
3431*795d594fSAndroid Build Coastguard Worker
HandleCondition(HCondition * instruction)3432*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleCondition(HCondition* instruction) {
3433*795d594fSAndroid Build Coastguard Worker if (instruction->IsEmittedAtUseSite()) {
3434*795d594fSAndroid Build Coastguard Worker return;
3435*795d594fSAndroid Build Coastguard Worker }
3436*795d594fSAndroid Build Coastguard Worker
3437*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3438*795d594fSAndroid Build Coastguard Worker Register res = RegisterFrom(locations->Out(), instruction->GetType());
3439*795d594fSAndroid Build Coastguard Worker IfCondition if_cond = instruction->GetCondition();
3440*795d594fSAndroid Build Coastguard Worker
3441*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
3442*795d594fSAndroid Build Coastguard Worker GenerateFcmp(instruction);
3443*795d594fSAndroid Build Coastguard Worker __ Cset(res, ARM64FPCondition(if_cond, instruction->IsGtBias()));
3444*795d594fSAndroid Build Coastguard Worker } else {
3445*795d594fSAndroid Build Coastguard Worker // Integer cases.
3446*795d594fSAndroid Build Coastguard Worker Register lhs = InputRegisterAt(instruction, 0);
3447*795d594fSAndroid Build Coastguard Worker Operand rhs = InputOperandAt(instruction, 1);
3448*795d594fSAndroid Build Coastguard Worker __ Cmp(lhs, rhs);
3449*795d594fSAndroid Build Coastguard Worker __ Cset(res, ARM64Condition(if_cond));
3450*795d594fSAndroid Build Coastguard Worker }
3451*795d594fSAndroid Build Coastguard Worker }
3452*795d594fSAndroid Build Coastguard Worker
3453*795d594fSAndroid Build Coastguard Worker #define FOR_EACH_CONDITION_INSTRUCTION(M) \
3454*795d594fSAndroid Build Coastguard Worker M(Equal) \
3455*795d594fSAndroid Build Coastguard Worker M(NotEqual) \
3456*795d594fSAndroid Build Coastguard Worker M(LessThan) \
3457*795d594fSAndroid Build Coastguard Worker M(LessThanOrEqual) \
3458*795d594fSAndroid Build Coastguard Worker M(GreaterThan) \
3459*795d594fSAndroid Build Coastguard Worker M(GreaterThanOrEqual) \
3460*795d594fSAndroid Build Coastguard Worker M(Below) \
3461*795d594fSAndroid Build Coastguard Worker M(BelowOrEqual) \
3462*795d594fSAndroid Build Coastguard Worker M(Above) \
3463*795d594fSAndroid Build Coastguard Worker M(AboveOrEqual)
3464*795d594fSAndroid Build Coastguard Worker #define DEFINE_CONDITION_VISITORS(Name) \
3465*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::Visit##Name(H##Name* comp) { HandleCondition(comp); } \
3466*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { HandleCondition(comp); }
FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)3467*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
3468*795d594fSAndroid Build Coastguard Worker #undef DEFINE_CONDITION_VISITORS
3469*795d594fSAndroid Build Coastguard Worker #undef FOR_EACH_CONDITION_INSTRUCTION
3470*795d594fSAndroid Build Coastguard Worker
3471*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntDivForPower2Denom(HDiv* instruction) {
3472*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
3473*795d594fSAndroid Build Coastguard Worker uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm));
3474*795d594fSAndroid Build Coastguard Worker DCHECK(IsPowerOfTwo(abs_imm)) << abs_imm;
3475*795d594fSAndroid Build Coastguard Worker
3476*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
3477*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
3478*795d594fSAndroid Build Coastguard Worker
3479*795d594fSAndroid Build Coastguard Worker Register final_dividend;
3480*795d594fSAndroid Build Coastguard Worker if (HasNonNegativeOrMinIntInputAt(instruction, 0)) {
3481*795d594fSAndroid Build Coastguard Worker // No need to adjust the result for non-negative dividends or the INT32_MIN/INT64_MIN dividends.
3482*795d594fSAndroid Build Coastguard Worker // NOTE: The generated code for HDiv correctly works for the INT32_MIN/INT64_MIN dividends:
3483*795d594fSAndroid Build Coastguard Worker // imm == 2
3484*795d594fSAndroid Build Coastguard Worker // add out, dividend(0x80000000), dividend(0x80000000), lsr #31 => out = 0x80000001
3485*795d594fSAndroid Build Coastguard Worker // asr out, out(0x80000001), #1 => out = 0xc0000000
3486*795d594fSAndroid Build Coastguard Worker // This is the same as 'asr out, 0x80000000, #1'
3487*795d594fSAndroid Build Coastguard Worker //
3488*795d594fSAndroid Build Coastguard Worker // imm > 2
3489*795d594fSAndroid Build Coastguard Worker // add temp, dividend(0x80000000), imm - 1 => temp = 0b10..01..1, where the number
3490*795d594fSAndroid Build Coastguard Worker // of the rightmost 1s is ctz_imm.
3491*795d594fSAndroid Build Coastguard Worker // cmp dividend(0x80000000), 0 => N = 1, V = 0 (lt is true)
3492*795d594fSAndroid Build Coastguard Worker // csel out, temp(0b10..01..1), dividend(0x80000000), lt => out = 0b10..01..1
3493*795d594fSAndroid Build Coastguard Worker // asr out, out(0b10..01..1), #ctz_imm => out = 0b1..10..0, where the number of the
3494*795d594fSAndroid Build Coastguard Worker // leftmost 1s is ctz_imm + 1.
3495*795d594fSAndroid Build Coastguard Worker // This is the same as 'asr out, dividend(0x80000000), #ctz_imm'.
3496*795d594fSAndroid Build Coastguard Worker //
3497*795d594fSAndroid Build Coastguard Worker // imm == INT32_MIN
3498*795d594fSAndroid Build Coastguard Worker // add tmp, dividend(0x80000000), #0x7fffffff => tmp = -1
3499*795d594fSAndroid Build Coastguard Worker // cmp dividend(0x80000000), 0 => N = 1, V = 0 (lt is true)
3500*795d594fSAndroid Build Coastguard Worker // csel out, temp(-1), dividend(0x80000000), lt => out = -1
3501*795d594fSAndroid Build Coastguard Worker // neg out, out(-1), asr #31 => out = 1
3502*795d594fSAndroid Build Coastguard Worker // This is the same as 'neg out, dividend(0x80000000), asr #31'.
3503*795d594fSAndroid Build Coastguard Worker final_dividend = dividend;
3504*795d594fSAndroid Build Coastguard Worker } else {
3505*795d594fSAndroid Build Coastguard Worker if (abs_imm == 2) {
3506*795d594fSAndroid Build Coastguard Worker int bits = DataType::Size(instruction->GetResultType()) * kBitsPerByte;
3507*795d594fSAndroid Build Coastguard Worker __ Add(out, dividend, Operand(dividend, LSR, bits - 1));
3508*795d594fSAndroid Build Coastguard Worker } else {
3509*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
3510*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
3511*795d594fSAndroid Build Coastguard Worker __ Add(temp, dividend, abs_imm - 1);
3512*795d594fSAndroid Build Coastguard Worker __ Cmp(dividend, 0);
3513*795d594fSAndroid Build Coastguard Worker __ Csel(out, temp, dividend, lt);
3514*795d594fSAndroid Build Coastguard Worker }
3515*795d594fSAndroid Build Coastguard Worker final_dividend = out;
3516*795d594fSAndroid Build Coastguard Worker }
3517*795d594fSAndroid Build Coastguard Worker
3518*795d594fSAndroid Build Coastguard Worker int ctz_imm = CTZ(abs_imm);
3519*795d594fSAndroid Build Coastguard Worker if (imm > 0) {
3520*795d594fSAndroid Build Coastguard Worker __ Asr(out, final_dividend, ctz_imm);
3521*795d594fSAndroid Build Coastguard Worker } else {
3522*795d594fSAndroid Build Coastguard Worker __ Neg(out, Operand(final_dividend, ASR, ctz_imm));
3523*795d594fSAndroid Build Coastguard Worker }
3524*795d594fSAndroid Build Coastguard Worker }
3525*795d594fSAndroid Build Coastguard Worker
3526*795d594fSAndroid Build Coastguard Worker // Return true if the magic number was modified by subtracting 2^32(Int32 div) or 2^64(Int64 div).
3527*795d594fSAndroid Build Coastguard Worker // So dividend needs to be added.
NeedToAddDividend(int64_t magic_number,int64_t divisor)3528*795d594fSAndroid Build Coastguard Worker static inline bool NeedToAddDividend(int64_t magic_number, int64_t divisor) {
3529*795d594fSAndroid Build Coastguard Worker return divisor > 0 && magic_number < 0;
3530*795d594fSAndroid Build Coastguard Worker }
3531*795d594fSAndroid Build Coastguard Worker
3532*795d594fSAndroid Build Coastguard Worker // Return true if the magic number was modified by adding 2^32(Int32 div) or 2^64(Int64 div).
3533*795d594fSAndroid Build Coastguard Worker // So dividend needs to be subtracted.
NeedToSubDividend(int64_t magic_number,int64_t divisor)3534*795d594fSAndroid Build Coastguard Worker static inline bool NeedToSubDividend(int64_t magic_number, int64_t divisor) {
3535*795d594fSAndroid Build Coastguard Worker return divisor < 0 && magic_number > 0;
3536*795d594fSAndroid Build Coastguard Worker }
3537*795d594fSAndroid Build Coastguard Worker
3538*795d594fSAndroid Build Coastguard Worker // Generate code which increments the value in register 'in' by 1 if the value is negative.
3539*795d594fSAndroid Build Coastguard Worker // It is done with 'add out, in, in, lsr #31 or #63'.
3540*795d594fSAndroid Build Coastguard Worker // If the value is a result of an operation setting the N flag, CINC MI can be used
3541*795d594fSAndroid Build Coastguard Worker // instead of ADD. 'use_cond_inc' controls this.
GenerateIncrementNegativeByOne(Register out,Register in,bool use_cond_inc)3542*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIncrementNegativeByOne(
3543*795d594fSAndroid Build Coastguard Worker Register out,
3544*795d594fSAndroid Build Coastguard Worker Register in,
3545*795d594fSAndroid Build Coastguard Worker bool use_cond_inc) {
3546*795d594fSAndroid Build Coastguard Worker if (use_cond_inc) {
3547*795d594fSAndroid Build Coastguard Worker __ Cinc(out, in, mi);
3548*795d594fSAndroid Build Coastguard Worker } else {
3549*795d594fSAndroid Build Coastguard Worker __ Add(out, in, Operand(in, LSR, in.GetSizeInBits() - 1));
3550*795d594fSAndroid Build Coastguard Worker }
3551*795d594fSAndroid Build Coastguard Worker }
3552*795d594fSAndroid Build Coastguard Worker
3553*795d594fSAndroid Build Coastguard Worker // Helper to generate code producing the result of HRem with a constant divisor.
GenerateResultRemWithAnyConstant(Register out,Register dividend,Register quotient,int64_t divisor,UseScratchRegisterScope * temps_scope)3554*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateResultRemWithAnyConstant(
3555*795d594fSAndroid Build Coastguard Worker Register out,
3556*795d594fSAndroid Build Coastguard Worker Register dividend,
3557*795d594fSAndroid Build Coastguard Worker Register quotient,
3558*795d594fSAndroid Build Coastguard Worker int64_t divisor,
3559*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope* temps_scope) {
3560*795d594fSAndroid Build Coastguard Worker Register temp_imm = temps_scope->AcquireSameSizeAs(out);
3561*795d594fSAndroid Build Coastguard Worker __ Mov(temp_imm, divisor);
3562*795d594fSAndroid Build Coastguard Worker __ Msub(out, quotient, temp_imm, dividend);
3563*795d594fSAndroid Build Coastguard Worker }
3564*795d594fSAndroid Build Coastguard Worker
3565*795d594fSAndroid Build Coastguard Worker // Helper to generate code for HDiv/HRem instructions when a dividend is non-negative and
3566*795d594fSAndroid Build Coastguard Worker // a divisor is a positive constant, not power of 2.
GenerateInt64UnsignedDivRemWithAnyPositiveConstant(HBinaryOperation * instruction)3567*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateInt64UnsignedDivRemWithAnyPositiveConstant(
3568*795d594fSAndroid Build Coastguard Worker HBinaryOperation* instruction) {
3569*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsDiv() || instruction->IsRem());
3570*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetResultType() == DataType::Type::kInt64);
3571*795d594fSAndroid Build Coastguard Worker
3572*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3573*795d594fSAndroid Build Coastguard Worker Location second = locations->InAt(1);
3574*795d594fSAndroid Build Coastguard Worker DCHECK(second.IsConstant());
3575*795d594fSAndroid Build Coastguard Worker
3576*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
3577*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
3578*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromConstant(second.GetConstant());
3579*795d594fSAndroid Build Coastguard Worker DCHECK_GT(imm, 0);
3580*795d594fSAndroid Build Coastguard Worker
3581*795d594fSAndroid Build Coastguard Worker int64_t magic;
3582*795d594fSAndroid Build Coastguard Worker int shift;
3583*795d594fSAndroid Build Coastguard Worker CalculateMagicAndShiftForDivRem(imm, /* is_long= */ true, &magic, &shift);
3584*795d594fSAndroid Build Coastguard Worker
3585*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
3586*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
3587*795d594fSAndroid Build Coastguard Worker
3588*795d594fSAndroid Build Coastguard Worker auto generate_unsigned_div_code = [this, magic, shift](Register out,
3589*795d594fSAndroid Build Coastguard Worker Register dividend,
3590*795d594fSAndroid Build Coastguard Worker Register temp) {
3591*795d594fSAndroid Build Coastguard Worker // temp = get_high(dividend * magic)
3592*795d594fSAndroid Build Coastguard Worker __ Mov(temp, magic);
3593*795d594fSAndroid Build Coastguard Worker if (magic > 0 && shift == 0) {
3594*795d594fSAndroid Build Coastguard Worker __ Smulh(out, dividend, temp);
3595*795d594fSAndroid Build Coastguard Worker } else {
3596*795d594fSAndroid Build Coastguard Worker __ Smulh(temp, dividend, temp);
3597*795d594fSAndroid Build Coastguard Worker if (magic < 0) {
3598*795d594fSAndroid Build Coastguard Worker // The negative magic means that the multiplier m is greater than INT64_MAX.
3599*795d594fSAndroid Build Coastguard Worker // In such a case shift is never 0. See the proof in
3600*795d594fSAndroid Build Coastguard Worker // InstructionCodeGeneratorARMVIXL::GenerateDivRemWithAnyConstant.
3601*795d594fSAndroid Build Coastguard Worker __ Add(temp, temp, dividend);
3602*795d594fSAndroid Build Coastguard Worker }
3603*795d594fSAndroid Build Coastguard Worker DCHECK_NE(shift, 0);
3604*795d594fSAndroid Build Coastguard Worker __ Lsr(out, temp, shift);
3605*795d594fSAndroid Build Coastguard Worker }
3606*795d594fSAndroid Build Coastguard Worker };
3607*795d594fSAndroid Build Coastguard Worker
3608*795d594fSAndroid Build Coastguard Worker if (instruction->IsDiv()) {
3609*795d594fSAndroid Build Coastguard Worker generate_unsigned_div_code(out, dividend, temp);
3610*795d594fSAndroid Build Coastguard Worker } else {
3611*795d594fSAndroid Build Coastguard Worker generate_unsigned_div_code(temp, dividend, temp);
3612*795d594fSAndroid Build Coastguard Worker GenerateResultRemWithAnyConstant(out, dividend, temp, imm, &temps);
3613*795d594fSAndroid Build Coastguard Worker }
3614*795d594fSAndroid Build Coastguard Worker }
3615*795d594fSAndroid Build Coastguard Worker
3616*795d594fSAndroid Build Coastguard Worker // Helper to generate code for HDiv/HRem instructions for any dividend and a constant divisor
3617*795d594fSAndroid Build Coastguard Worker // (not power of 2).
GenerateInt64DivRemWithAnyConstant(HBinaryOperation * instruction)3618*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateInt64DivRemWithAnyConstant(
3619*795d594fSAndroid Build Coastguard Worker HBinaryOperation* instruction) {
3620*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsDiv() || instruction->IsRem());
3621*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetResultType() == DataType::Type::kInt64);
3622*795d594fSAndroid Build Coastguard Worker
3623*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3624*795d594fSAndroid Build Coastguard Worker Location second = locations->InAt(1);
3625*795d594fSAndroid Build Coastguard Worker DCHECK(second.IsConstant());
3626*795d594fSAndroid Build Coastguard Worker
3627*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
3628*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
3629*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromConstant(second.GetConstant());
3630*795d594fSAndroid Build Coastguard Worker
3631*795d594fSAndroid Build Coastguard Worker int64_t magic;
3632*795d594fSAndroid Build Coastguard Worker int shift;
3633*795d594fSAndroid Build Coastguard Worker CalculateMagicAndShiftForDivRem(imm, /* is_long= */ true, &magic, &shift);
3634*795d594fSAndroid Build Coastguard Worker
3635*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
3636*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
3637*795d594fSAndroid Build Coastguard Worker
3638*795d594fSAndroid Build Coastguard Worker // temp = get_high(dividend * magic)
3639*795d594fSAndroid Build Coastguard Worker __ Mov(temp, magic);
3640*795d594fSAndroid Build Coastguard Worker __ Smulh(temp, dividend, temp);
3641*795d594fSAndroid Build Coastguard Worker
3642*795d594fSAndroid Build Coastguard Worker // The multiplication result might need some corrections to be finalized.
3643*795d594fSAndroid Build Coastguard Worker // The last correction is to increment by 1, if the result is negative.
3644*795d594fSAndroid Build Coastguard Worker // Currently it is done with 'add result, temp_result, temp_result, lsr #31 or #63'.
3645*795d594fSAndroid Build Coastguard Worker // Such ADD usually has latency 2, e.g. on Cortex-A55.
3646*795d594fSAndroid Build Coastguard Worker // However if one of the corrections is ADD or SUB, the sign can be detected
3647*795d594fSAndroid Build Coastguard Worker // with ADDS/SUBS. They set the N flag if the result is negative.
3648*795d594fSAndroid Build Coastguard Worker // This allows to use CINC MI which has latency 1.
3649*795d594fSAndroid Build Coastguard Worker bool use_cond_inc = false;
3650*795d594fSAndroid Build Coastguard Worker
3651*795d594fSAndroid Build Coastguard Worker // Some combinations of magic_number and the divisor require to correct the result.
3652*795d594fSAndroid Build Coastguard Worker // Check whether the correction is needed.
3653*795d594fSAndroid Build Coastguard Worker if (NeedToAddDividend(magic, imm)) {
3654*795d594fSAndroid Build Coastguard Worker __ Adds(temp, temp, dividend);
3655*795d594fSAndroid Build Coastguard Worker use_cond_inc = true;
3656*795d594fSAndroid Build Coastguard Worker } else if (NeedToSubDividend(magic, imm)) {
3657*795d594fSAndroid Build Coastguard Worker __ Subs(temp, temp, dividend);
3658*795d594fSAndroid Build Coastguard Worker use_cond_inc = true;
3659*795d594fSAndroid Build Coastguard Worker }
3660*795d594fSAndroid Build Coastguard Worker
3661*795d594fSAndroid Build Coastguard Worker if (shift != 0) {
3662*795d594fSAndroid Build Coastguard Worker __ Asr(temp, temp, shift);
3663*795d594fSAndroid Build Coastguard Worker }
3664*795d594fSAndroid Build Coastguard Worker
3665*795d594fSAndroid Build Coastguard Worker if (instruction->IsRem()) {
3666*795d594fSAndroid Build Coastguard Worker GenerateIncrementNegativeByOne(temp, temp, use_cond_inc);
3667*795d594fSAndroid Build Coastguard Worker GenerateResultRemWithAnyConstant(out, dividend, temp, imm, &temps);
3668*795d594fSAndroid Build Coastguard Worker } else {
3669*795d594fSAndroid Build Coastguard Worker GenerateIncrementNegativeByOne(out, temp, use_cond_inc);
3670*795d594fSAndroid Build Coastguard Worker }
3671*795d594fSAndroid Build Coastguard Worker }
3672*795d594fSAndroid Build Coastguard Worker
GenerateInt32DivRemWithAnyConstant(HBinaryOperation * instruction)3673*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateInt32DivRemWithAnyConstant(
3674*795d594fSAndroid Build Coastguard Worker HBinaryOperation* instruction) {
3675*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsDiv() || instruction->IsRem());
3676*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
3677*795d594fSAndroid Build Coastguard Worker
3678*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
3679*795d594fSAndroid Build Coastguard Worker Location second = locations->InAt(1);
3680*795d594fSAndroid Build Coastguard Worker DCHECK(second.IsConstant());
3681*795d594fSAndroid Build Coastguard Worker
3682*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
3683*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
3684*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromConstant(second.GetConstant());
3685*795d594fSAndroid Build Coastguard Worker
3686*795d594fSAndroid Build Coastguard Worker int64_t magic;
3687*795d594fSAndroid Build Coastguard Worker int shift;
3688*795d594fSAndroid Build Coastguard Worker CalculateMagicAndShiftForDivRem(imm, /* is_long= */ false, &magic, &shift);
3689*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
3690*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
3691*795d594fSAndroid Build Coastguard Worker
3692*795d594fSAndroid Build Coastguard Worker // temp = get_high(dividend * magic)
3693*795d594fSAndroid Build Coastguard Worker __ Mov(temp, magic);
3694*795d594fSAndroid Build Coastguard Worker __ Smull(temp.X(), dividend, temp);
3695*795d594fSAndroid Build Coastguard Worker
3696*795d594fSAndroid Build Coastguard Worker // The multiplication result might need some corrections to be finalized.
3697*795d594fSAndroid Build Coastguard Worker // The last correction is to increment by 1, if the result is negative.
3698*795d594fSAndroid Build Coastguard Worker // Currently it is done with 'add result, temp_result, temp_result, lsr #31 or #63'.
3699*795d594fSAndroid Build Coastguard Worker // Such ADD usually has latency 2, e.g. on Cortex-A55.
3700*795d594fSAndroid Build Coastguard Worker // However if one of the corrections is ADD or SUB, the sign can be detected
3701*795d594fSAndroid Build Coastguard Worker // with ADDS/SUBS. They set the N flag if the result is negative.
3702*795d594fSAndroid Build Coastguard Worker // This allows to use CINC MI which has latency 1.
3703*795d594fSAndroid Build Coastguard Worker bool use_cond_inc = false;
3704*795d594fSAndroid Build Coastguard Worker
3705*795d594fSAndroid Build Coastguard Worker // ADD/SUB correction is performed in the high 32 bits
3706*795d594fSAndroid Build Coastguard Worker // as high 32 bits are ignored because type are kInt32.
3707*795d594fSAndroid Build Coastguard Worker if (NeedToAddDividend(magic, imm)) {
3708*795d594fSAndroid Build Coastguard Worker __ Adds(temp.X(), temp.X(), Operand(dividend.X(), LSL, 32));
3709*795d594fSAndroid Build Coastguard Worker use_cond_inc = true;
3710*795d594fSAndroid Build Coastguard Worker } else if (NeedToSubDividend(magic, imm)) {
3711*795d594fSAndroid Build Coastguard Worker __ Subs(temp.X(), temp.X(), Operand(dividend.X(), LSL, 32));
3712*795d594fSAndroid Build Coastguard Worker use_cond_inc = true;
3713*795d594fSAndroid Build Coastguard Worker }
3714*795d594fSAndroid Build Coastguard Worker
3715*795d594fSAndroid Build Coastguard Worker // Extract the result from the high 32 bits and apply the final right shift.
3716*795d594fSAndroid Build Coastguard Worker DCHECK_LT(shift, 32);
3717*795d594fSAndroid Build Coastguard Worker if (imm > 0 && HasNonNegativeInputAt(instruction, 0)) {
3718*795d594fSAndroid Build Coastguard Worker // No need to adjust the result for a non-negative dividend and a positive divisor.
3719*795d594fSAndroid Build Coastguard Worker if (instruction->IsDiv()) {
3720*795d594fSAndroid Build Coastguard Worker __ Lsr(out.X(), temp.X(), 32 + shift);
3721*795d594fSAndroid Build Coastguard Worker } else {
3722*795d594fSAndroid Build Coastguard Worker __ Lsr(temp.X(), temp.X(), 32 + shift);
3723*795d594fSAndroid Build Coastguard Worker GenerateResultRemWithAnyConstant(out, dividend, temp, imm, &temps);
3724*795d594fSAndroid Build Coastguard Worker }
3725*795d594fSAndroid Build Coastguard Worker } else {
3726*795d594fSAndroid Build Coastguard Worker __ Asr(temp.X(), temp.X(), 32 + shift);
3727*795d594fSAndroid Build Coastguard Worker
3728*795d594fSAndroid Build Coastguard Worker if (instruction->IsRem()) {
3729*795d594fSAndroid Build Coastguard Worker GenerateIncrementNegativeByOne(temp, temp, use_cond_inc);
3730*795d594fSAndroid Build Coastguard Worker GenerateResultRemWithAnyConstant(out, dividend, temp, imm, &temps);
3731*795d594fSAndroid Build Coastguard Worker } else {
3732*795d594fSAndroid Build Coastguard Worker GenerateIncrementNegativeByOne(out, temp, use_cond_inc);
3733*795d594fSAndroid Build Coastguard Worker }
3734*795d594fSAndroid Build Coastguard Worker }
3735*795d594fSAndroid Build Coastguard Worker }
3736*795d594fSAndroid Build Coastguard Worker
GenerateDivRemWithAnyConstant(HBinaryOperation * instruction,int64_t divisor)3737*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction,
3738*795d594fSAndroid Build Coastguard Worker int64_t divisor) {
3739*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsDiv() || instruction->IsRem());
3740*795d594fSAndroid Build Coastguard Worker if (instruction->GetResultType() == DataType::Type::kInt64) {
3741*795d594fSAndroid Build Coastguard Worker if (divisor > 0 && HasNonNegativeInputAt(instruction, 0)) {
3742*795d594fSAndroid Build Coastguard Worker GenerateInt64UnsignedDivRemWithAnyPositiveConstant(instruction);
3743*795d594fSAndroid Build Coastguard Worker } else {
3744*795d594fSAndroid Build Coastguard Worker GenerateInt64DivRemWithAnyConstant(instruction);
3745*795d594fSAndroid Build Coastguard Worker }
3746*795d594fSAndroid Build Coastguard Worker } else {
3747*795d594fSAndroid Build Coastguard Worker GenerateInt32DivRemWithAnyConstant(instruction);
3748*795d594fSAndroid Build Coastguard Worker }
3749*795d594fSAndroid Build Coastguard Worker }
3750*795d594fSAndroid Build Coastguard Worker
GenerateIntDivForConstDenom(HDiv * instruction)3751*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntDivForConstDenom(HDiv *instruction) {
3752*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
3753*795d594fSAndroid Build Coastguard Worker
3754*795d594fSAndroid Build Coastguard Worker if (imm == 0) {
3755*795d594fSAndroid Build Coastguard Worker // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3756*795d594fSAndroid Build Coastguard Worker return;
3757*795d594fSAndroid Build Coastguard Worker }
3758*795d594fSAndroid Build Coastguard Worker
3759*795d594fSAndroid Build Coastguard Worker if (IsPowerOfTwo(AbsOrMin(imm))) {
3760*795d594fSAndroid Build Coastguard Worker GenerateIntDivForPower2Denom(instruction);
3761*795d594fSAndroid Build Coastguard Worker } else {
3762*795d594fSAndroid Build Coastguard Worker // Cases imm == -1 or imm == 1 are handled by InstructionSimplifier.
3763*795d594fSAndroid Build Coastguard Worker DCHECK(imm < -2 || imm > 2) << imm;
3764*795d594fSAndroid Build Coastguard Worker GenerateDivRemWithAnyConstant(instruction, imm);
3765*795d594fSAndroid Build Coastguard Worker }
3766*795d594fSAndroid Build Coastguard Worker }
3767*795d594fSAndroid Build Coastguard Worker
GenerateIntDiv(HDiv * instruction)3768*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntDiv(HDiv *instruction) {
3769*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntOrLongType(instruction->GetResultType()))
3770*795d594fSAndroid Build Coastguard Worker << instruction->GetResultType();
3771*795d594fSAndroid Build Coastguard Worker
3772*795d594fSAndroid Build Coastguard Worker if (instruction->GetLocations()->InAt(1).IsConstant()) {
3773*795d594fSAndroid Build Coastguard Worker GenerateIntDivForConstDenom(instruction);
3774*795d594fSAndroid Build Coastguard Worker } else {
3775*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
3776*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
3777*795d594fSAndroid Build Coastguard Worker Register divisor = InputRegisterAt(instruction, 1);
3778*795d594fSAndroid Build Coastguard Worker __ Sdiv(out, dividend, divisor);
3779*795d594fSAndroid Build Coastguard Worker }
3780*795d594fSAndroid Build Coastguard Worker }
3781*795d594fSAndroid Build Coastguard Worker
VisitDiv(HDiv * div)3782*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitDiv(HDiv* div) {
3783*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3784*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(div, LocationSummary::kNoCall);
3785*795d594fSAndroid Build Coastguard Worker switch (div->GetResultType()) {
3786*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
3787*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
3788*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3789*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
3790*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3791*795d594fSAndroid Build Coastguard Worker break;
3792*795d594fSAndroid Build Coastguard Worker
3793*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
3794*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
3795*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
3796*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
3797*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3798*795d594fSAndroid Build Coastguard Worker break;
3799*795d594fSAndroid Build Coastguard Worker
3800*795d594fSAndroid Build Coastguard Worker default:
3801*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3802*795d594fSAndroid Build Coastguard Worker }
3803*795d594fSAndroid Build Coastguard Worker }
3804*795d594fSAndroid Build Coastguard Worker
VisitDiv(HDiv * div)3805*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
3806*795d594fSAndroid Build Coastguard Worker DataType::Type type = div->GetResultType();
3807*795d594fSAndroid Build Coastguard Worker switch (type) {
3808*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
3809*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
3810*795d594fSAndroid Build Coastguard Worker GenerateIntDiv(div);
3811*795d594fSAndroid Build Coastguard Worker break;
3812*795d594fSAndroid Build Coastguard Worker
3813*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
3814*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
3815*795d594fSAndroid Build Coastguard Worker __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
3816*795d594fSAndroid Build Coastguard Worker break;
3817*795d594fSAndroid Build Coastguard Worker
3818*795d594fSAndroid Build Coastguard Worker default:
3819*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected div type " << type;
3820*795d594fSAndroid Build Coastguard Worker }
3821*795d594fSAndroid Build Coastguard Worker }
3822*795d594fSAndroid Build Coastguard Worker
VisitDivZeroCheck(HDivZeroCheck * instruction)3823*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3824*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
3825*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3826*795d594fSAndroid Build Coastguard Worker }
3827*795d594fSAndroid Build Coastguard Worker
VisitDivZeroCheck(HDivZeroCheck * instruction)3828*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3829*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
3830*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathARM64(instruction);
3831*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3832*795d594fSAndroid Build Coastguard Worker Location value = instruction->GetLocations()->InAt(0);
3833*795d594fSAndroid Build Coastguard Worker
3834*795d594fSAndroid Build Coastguard Worker DataType::Type type = instruction->GetType();
3835*795d594fSAndroid Build Coastguard Worker
3836*795d594fSAndroid Build Coastguard Worker if (!DataType::IsIntegralType(type)) {
3837*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
3838*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
3839*795d594fSAndroid Build Coastguard Worker }
3840*795d594fSAndroid Build Coastguard Worker
3841*795d594fSAndroid Build Coastguard Worker if (value.IsConstant()) {
3842*795d594fSAndroid Build Coastguard Worker int64_t divisor = Int64FromLocation(value);
3843*795d594fSAndroid Build Coastguard Worker if (divisor == 0) {
3844*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
3845*795d594fSAndroid Build Coastguard Worker } else {
3846*795d594fSAndroid Build Coastguard Worker // A division by a non-null constant is valid. We don't need to perform
3847*795d594fSAndroid Build Coastguard Worker // any check, so simply fall through.
3848*795d594fSAndroid Build Coastguard Worker }
3849*795d594fSAndroid Build Coastguard Worker } else {
3850*795d594fSAndroid Build Coastguard Worker __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
3851*795d594fSAndroid Build Coastguard Worker }
3852*795d594fSAndroid Build Coastguard Worker }
3853*795d594fSAndroid Build Coastguard Worker
VisitDoubleConstant(HDoubleConstant * constant)3854*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
3855*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3856*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
3857*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::ConstantLocation(constant));
3858*795d594fSAndroid Build Coastguard Worker }
3859*795d594fSAndroid Build Coastguard Worker
VisitDoubleConstant(HDoubleConstant * constant)3860*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitDoubleConstant(
3861*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] HDoubleConstant* constant) {
3862*795d594fSAndroid Build Coastguard Worker // Will be generated at use site.
3863*795d594fSAndroid Build Coastguard Worker }
3864*795d594fSAndroid Build Coastguard Worker
VisitExit(HExit * exit)3865*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitExit(HExit* exit) {
3866*795d594fSAndroid Build Coastguard Worker exit->SetLocations(nullptr);
3867*795d594fSAndroid Build Coastguard Worker }
3868*795d594fSAndroid Build Coastguard Worker
VisitExit(HExit * exit)3869*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitExit([[maybe_unused]] HExit* exit) {}
3870*795d594fSAndroid Build Coastguard Worker
VisitFloatConstant(HFloatConstant * constant)3871*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
3872*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3873*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
3874*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::ConstantLocation(constant));
3875*795d594fSAndroid Build Coastguard Worker }
3876*795d594fSAndroid Build Coastguard Worker
VisitFloatConstant(HFloatConstant * constant)3877*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitFloatConstant([[maybe_unused]] HFloatConstant* constant) {
3878*795d594fSAndroid Build Coastguard Worker // Will be generated at use site.
3879*795d594fSAndroid Build Coastguard Worker }
3880*795d594fSAndroid Build Coastguard Worker
HandleGoto(HInstruction * got,HBasicBlock * successor)3881*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
3882*795d594fSAndroid Build Coastguard Worker if (successor->IsExitBlock()) {
3883*795d594fSAndroid Build Coastguard Worker DCHECK(got->GetPrevious()->AlwaysThrows());
3884*795d594fSAndroid Build Coastguard Worker return; // no code needed
3885*795d594fSAndroid Build Coastguard Worker }
3886*795d594fSAndroid Build Coastguard Worker
3887*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = got->GetBlock();
3888*795d594fSAndroid Build Coastguard Worker HInstruction* previous = got->GetPrevious();
3889*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
3890*795d594fSAndroid Build Coastguard Worker
3891*795d594fSAndroid Build Coastguard Worker if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
3892*795d594fSAndroid Build Coastguard Worker codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false);
3893*795d594fSAndroid Build Coastguard Worker GenerateSuspendCheck(info->GetSuspendCheck(), successor);
3894*795d594fSAndroid Build Coastguard Worker return; // `GenerateSuspendCheck()` emitted the jump.
3895*795d594fSAndroid Build Coastguard Worker }
3896*795d594fSAndroid Build Coastguard Worker if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
3897*795d594fSAndroid Build Coastguard Worker GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
3898*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
3899*795d594fSAndroid Build Coastguard Worker }
3900*795d594fSAndroid Build Coastguard Worker if (!codegen_->GoesToNextBlock(block, successor)) {
3901*795d594fSAndroid Build Coastguard Worker __ B(codegen_->GetLabelOf(successor));
3902*795d594fSAndroid Build Coastguard Worker }
3903*795d594fSAndroid Build Coastguard Worker }
3904*795d594fSAndroid Build Coastguard Worker
VisitGoto(HGoto * got)3905*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitGoto(HGoto* got) {
3906*795d594fSAndroid Build Coastguard Worker got->SetLocations(nullptr);
3907*795d594fSAndroid Build Coastguard Worker }
3908*795d594fSAndroid Build Coastguard Worker
VisitGoto(HGoto * got)3909*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
3910*795d594fSAndroid Build Coastguard Worker HandleGoto(got, got->GetSuccessor());
3911*795d594fSAndroid Build Coastguard Worker }
3912*795d594fSAndroid Build Coastguard Worker
VisitTryBoundary(HTryBoundary * try_boundary)3913*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitTryBoundary(HTryBoundary* try_boundary) {
3914*795d594fSAndroid Build Coastguard Worker try_boundary->SetLocations(nullptr);
3915*795d594fSAndroid Build Coastguard Worker }
3916*795d594fSAndroid Build Coastguard Worker
VisitTryBoundary(HTryBoundary * try_boundary)3917*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitTryBoundary(HTryBoundary* try_boundary) {
3918*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
3919*795d594fSAndroid Build Coastguard Worker if (!successor->IsExitBlock()) {
3920*795d594fSAndroid Build Coastguard Worker HandleGoto(try_boundary, successor);
3921*795d594fSAndroid Build Coastguard Worker }
3922*795d594fSAndroid Build Coastguard Worker }
3923*795d594fSAndroid Build Coastguard Worker
GenerateTestAndBranch(HInstruction * instruction,size_t condition_input_index,vixl::aarch64::Label * true_target,vixl::aarch64::Label * false_target)3924*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateTestAndBranch(HInstruction* instruction,
3925*795d594fSAndroid Build Coastguard Worker size_t condition_input_index,
3926*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* true_target,
3927*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* false_target) {
3928*795d594fSAndroid Build Coastguard Worker HInstruction* cond = instruction->InputAt(condition_input_index);
3929*795d594fSAndroid Build Coastguard Worker
3930*795d594fSAndroid Build Coastguard Worker if (true_target == nullptr && false_target == nullptr) {
3931*795d594fSAndroid Build Coastguard Worker // Nothing to do. The code always falls through.
3932*795d594fSAndroid Build Coastguard Worker return;
3933*795d594fSAndroid Build Coastguard Worker } else if (cond->IsIntConstant()) {
3934*795d594fSAndroid Build Coastguard Worker // Constant condition, statically compared against "true" (integer value 1).
3935*795d594fSAndroid Build Coastguard Worker if (cond->AsIntConstant()->IsTrue()) {
3936*795d594fSAndroid Build Coastguard Worker if (true_target != nullptr) {
3937*795d594fSAndroid Build Coastguard Worker __ B(true_target);
3938*795d594fSAndroid Build Coastguard Worker }
3939*795d594fSAndroid Build Coastguard Worker } else {
3940*795d594fSAndroid Build Coastguard Worker DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
3941*795d594fSAndroid Build Coastguard Worker if (false_target != nullptr) {
3942*795d594fSAndroid Build Coastguard Worker __ B(false_target);
3943*795d594fSAndroid Build Coastguard Worker }
3944*795d594fSAndroid Build Coastguard Worker }
3945*795d594fSAndroid Build Coastguard Worker return;
3946*795d594fSAndroid Build Coastguard Worker }
3947*795d594fSAndroid Build Coastguard Worker
3948*795d594fSAndroid Build Coastguard Worker // The following code generates these patterns:
3949*795d594fSAndroid Build Coastguard Worker // (1) true_target == nullptr && false_target != nullptr
3950*795d594fSAndroid Build Coastguard Worker // - opposite condition true => branch to false_target
3951*795d594fSAndroid Build Coastguard Worker // (2) true_target != nullptr && false_target == nullptr
3952*795d594fSAndroid Build Coastguard Worker // - condition true => branch to true_target
3953*795d594fSAndroid Build Coastguard Worker // (3) true_target != nullptr && false_target != nullptr
3954*795d594fSAndroid Build Coastguard Worker // - condition true => branch to true_target
3955*795d594fSAndroid Build Coastguard Worker // - branch to false_target
3956*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(cond)) {
3957*795d594fSAndroid Build Coastguard Worker // The condition instruction has been materialized, compare the output to 0.
3958*795d594fSAndroid Build Coastguard Worker Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
3959*795d594fSAndroid Build Coastguard Worker DCHECK(cond_val.IsRegister());
3960*795d594fSAndroid Build Coastguard Worker if (true_target == nullptr) {
3961*795d594fSAndroid Build Coastguard Worker __ Cbz(InputRegisterAt(instruction, condition_input_index), false_target);
3962*795d594fSAndroid Build Coastguard Worker } else {
3963*795d594fSAndroid Build Coastguard Worker __ Cbnz(InputRegisterAt(instruction, condition_input_index), true_target);
3964*795d594fSAndroid Build Coastguard Worker }
3965*795d594fSAndroid Build Coastguard Worker } else {
3966*795d594fSAndroid Build Coastguard Worker // The condition instruction has not been materialized, use its inputs as
3967*795d594fSAndroid Build Coastguard Worker // the comparison and its condition as the branch condition.
3968*795d594fSAndroid Build Coastguard Worker HCondition* condition = cond->AsCondition();
3969*795d594fSAndroid Build Coastguard Worker
3970*795d594fSAndroid Build Coastguard Worker DataType::Type type = condition->InputAt(0)->GetType();
3971*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type)) {
3972*795d594fSAndroid Build Coastguard Worker GenerateFcmp(condition);
3973*795d594fSAndroid Build Coastguard Worker if (true_target == nullptr) {
3974*795d594fSAndroid Build Coastguard Worker IfCondition opposite_condition = condition->GetOppositeCondition();
3975*795d594fSAndroid Build Coastguard Worker __ B(ARM64FPCondition(opposite_condition, condition->IsGtBias()), false_target);
3976*795d594fSAndroid Build Coastguard Worker } else {
3977*795d594fSAndroid Build Coastguard Worker __ B(ARM64FPCondition(condition->GetCondition(), condition->IsGtBias()), true_target);
3978*795d594fSAndroid Build Coastguard Worker }
3979*795d594fSAndroid Build Coastguard Worker } else {
3980*795d594fSAndroid Build Coastguard Worker // Integer cases.
3981*795d594fSAndroid Build Coastguard Worker Register lhs = InputRegisterAt(condition, 0);
3982*795d594fSAndroid Build Coastguard Worker Operand rhs = InputOperandAt(condition, 1);
3983*795d594fSAndroid Build Coastguard Worker
3984*795d594fSAndroid Build Coastguard Worker Condition arm64_cond;
3985*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* non_fallthrough_target;
3986*795d594fSAndroid Build Coastguard Worker if (true_target == nullptr) {
3987*795d594fSAndroid Build Coastguard Worker arm64_cond = ARM64Condition(condition->GetOppositeCondition());
3988*795d594fSAndroid Build Coastguard Worker non_fallthrough_target = false_target;
3989*795d594fSAndroid Build Coastguard Worker } else {
3990*795d594fSAndroid Build Coastguard Worker arm64_cond = ARM64Condition(condition->GetCondition());
3991*795d594fSAndroid Build Coastguard Worker non_fallthrough_target = true_target;
3992*795d594fSAndroid Build Coastguard Worker }
3993*795d594fSAndroid Build Coastguard Worker
3994*795d594fSAndroid Build Coastguard Worker if ((arm64_cond == eq || arm64_cond == ne || arm64_cond == lt || arm64_cond == ge) &&
3995*795d594fSAndroid Build Coastguard Worker rhs.IsImmediate() && (rhs.GetImmediate() == 0)) {
3996*795d594fSAndroid Build Coastguard Worker switch (arm64_cond) {
3997*795d594fSAndroid Build Coastguard Worker case eq:
3998*795d594fSAndroid Build Coastguard Worker __ Cbz(lhs, non_fallthrough_target);
3999*795d594fSAndroid Build Coastguard Worker break;
4000*795d594fSAndroid Build Coastguard Worker case ne:
4001*795d594fSAndroid Build Coastguard Worker __ Cbnz(lhs, non_fallthrough_target);
4002*795d594fSAndroid Build Coastguard Worker break;
4003*795d594fSAndroid Build Coastguard Worker case lt:
4004*795d594fSAndroid Build Coastguard Worker // Test the sign bit and branch accordingly.
4005*795d594fSAndroid Build Coastguard Worker __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, non_fallthrough_target);
4006*795d594fSAndroid Build Coastguard Worker break;
4007*795d594fSAndroid Build Coastguard Worker case ge:
4008*795d594fSAndroid Build Coastguard Worker // Test the sign bit and branch accordingly.
4009*795d594fSAndroid Build Coastguard Worker __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, non_fallthrough_target);
4010*795d594fSAndroid Build Coastguard Worker break;
4011*795d594fSAndroid Build Coastguard Worker default:
4012*795d594fSAndroid Build Coastguard Worker // Without the `static_cast` the compiler throws an error for
4013*795d594fSAndroid Build Coastguard Worker // `-Werror=sign-promo`.
4014*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
4015*795d594fSAndroid Build Coastguard Worker }
4016*795d594fSAndroid Build Coastguard Worker } else {
4017*795d594fSAndroid Build Coastguard Worker __ Cmp(lhs, rhs);
4018*795d594fSAndroid Build Coastguard Worker __ B(arm64_cond, non_fallthrough_target);
4019*795d594fSAndroid Build Coastguard Worker }
4020*795d594fSAndroid Build Coastguard Worker }
4021*795d594fSAndroid Build Coastguard Worker }
4022*795d594fSAndroid Build Coastguard Worker
4023*795d594fSAndroid Build Coastguard Worker // If neither branch falls through (case 3), the conditional branch to `true_target`
4024*795d594fSAndroid Build Coastguard Worker // was already emitted (case 2) and we need to emit a jump to `false_target`.
4025*795d594fSAndroid Build Coastguard Worker if (true_target != nullptr && false_target != nullptr) {
4026*795d594fSAndroid Build Coastguard Worker __ B(false_target);
4027*795d594fSAndroid Build Coastguard Worker }
4028*795d594fSAndroid Build Coastguard Worker }
4029*795d594fSAndroid Build Coastguard Worker
VisitIf(HIf * if_instr)4030*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
4031*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
4032*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
4033*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
4034*795d594fSAndroid Build Coastguard Worker }
4035*795d594fSAndroid Build Coastguard Worker }
4036*795d594fSAndroid Build Coastguard Worker
VisitIf(HIf * if_instr)4037*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
4038*795d594fSAndroid Build Coastguard Worker HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
4039*795d594fSAndroid Build Coastguard Worker HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
4040*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* true_target = codegen_->GetLabelOf(true_successor);
4041*795d594fSAndroid Build Coastguard Worker if (codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor)) {
4042*795d594fSAndroid Build Coastguard Worker true_target = nullptr;
4043*795d594fSAndroid Build Coastguard Worker }
4044*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* false_target = codegen_->GetLabelOf(false_successor);
4045*795d594fSAndroid Build Coastguard Worker if (codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor)) {
4046*795d594fSAndroid Build Coastguard Worker false_target = nullptr;
4047*795d594fSAndroid Build Coastguard Worker }
4048*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
4049*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsCompilingBaseline() &&
4050*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerOptions().ProfileBranches() &&
4051*795d594fSAndroid Build Coastguard Worker !Runtime::Current()->IsAotCompiler()) {
4052*795d594fSAndroid Build Coastguard Worker DCHECK(if_instr->InputAt(0)->IsCondition());
4053*795d594fSAndroid Build Coastguard Worker ProfilingInfo* info = GetGraph()->GetProfilingInfo();
4054*795d594fSAndroid Build Coastguard Worker DCHECK(info != nullptr);
4055*795d594fSAndroid Build Coastguard Worker BranchCache* cache = info->GetBranchCache(if_instr->GetDexPc());
4056*795d594fSAndroid Build Coastguard Worker // Currently, not all If branches are profiled.
4057*795d594fSAndroid Build Coastguard Worker if (cache != nullptr) {
4058*795d594fSAndroid Build Coastguard Worker uint64_t address =
4059*795d594fSAndroid Build Coastguard Worker reinterpret_cast64<uint64_t>(cache) + BranchCache::FalseOffset().Int32Value();
4060*795d594fSAndroid Build Coastguard Worker static_assert(
4061*795d594fSAndroid Build Coastguard Worker BranchCache::TrueOffset().Int32Value() - BranchCache::FalseOffset().Int32Value() == 2,
4062*795d594fSAndroid Build Coastguard Worker "Unexpected offsets for BranchCache");
4063*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
4064*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
4065*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireX();
4066*795d594fSAndroid Build Coastguard Worker Register counter = temps.AcquireW();
4067*795d594fSAndroid Build Coastguard Worker Register condition = InputRegisterAt(if_instr, 0).X();
4068*795d594fSAndroid Build Coastguard Worker __ Mov(temp, address);
4069*795d594fSAndroid Build Coastguard Worker __ Ldrh(counter, MemOperand(temp, condition, LSL, 1));
4070*795d594fSAndroid Build Coastguard Worker __ Add(counter, counter, 1);
4071*795d594fSAndroid Build Coastguard Worker __ Tbnz(counter, 16, &done);
4072*795d594fSAndroid Build Coastguard Worker __ Strh(counter, MemOperand(temp, condition, LSL, 1));
4073*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
4074*795d594fSAndroid Build Coastguard Worker }
4075*795d594fSAndroid Build Coastguard Worker }
4076*795d594fSAndroid Build Coastguard Worker }
4077*795d594fSAndroid Build Coastguard Worker GenerateTestAndBranch(if_instr, /* condition_input_index= */ 0, true_target, false_target);
4078*795d594fSAndroid Build Coastguard Worker }
4079*795d594fSAndroid Build Coastguard Worker
VisitDeoptimize(HDeoptimize * deoptimize)4080*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
4081*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator())
4082*795d594fSAndroid Build Coastguard Worker LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
4083*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
4084*795d594fSAndroid Build Coastguard Worker RegisterSet caller_saves = RegisterSet::Empty();
4085*795d594fSAndroid Build Coastguard Worker caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
4086*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(caller_saves);
4087*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
4088*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
4089*795d594fSAndroid Build Coastguard Worker }
4090*795d594fSAndroid Build Coastguard Worker }
4091*795d594fSAndroid Build Coastguard Worker
VisitDeoptimize(HDeoptimize * deoptimize)4092*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
4093*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
4094*795d594fSAndroid Build Coastguard Worker deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM64>(deoptimize);
4095*795d594fSAndroid Build Coastguard Worker GenerateTestAndBranch(deoptimize,
4096*795d594fSAndroid Build Coastguard Worker /* condition_input_index= */ 0,
4097*795d594fSAndroid Build Coastguard Worker slow_path->GetEntryLabel(),
4098*795d594fSAndroid Build Coastguard Worker /* false_target= */ nullptr);
4099*795d594fSAndroid Build Coastguard Worker }
4100*795d594fSAndroid Build Coastguard Worker
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)4101*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
4102*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator())
4103*795d594fSAndroid Build Coastguard Worker LocationSummary(flag, LocationSummary::kNoCall);
4104*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
4105*795d594fSAndroid Build Coastguard Worker }
4106*795d594fSAndroid Build Coastguard Worker
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)4107*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
4108*795d594fSAndroid Build Coastguard Worker __ Ldr(OutputRegister(flag),
4109*795d594fSAndroid Build Coastguard Worker MemOperand(sp, codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
4110*795d594fSAndroid Build Coastguard Worker }
4111*795d594fSAndroid Build Coastguard Worker
IsConditionOnFloatingPointValues(HInstruction * condition)4112*795d594fSAndroid Build Coastguard Worker static inline bool IsConditionOnFloatingPointValues(HInstruction* condition) {
4113*795d594fSAndroid Build Coastguard Worker return condition->IsCondition() &&
4114*795d594fSAndroid Build Coastguard Worker DataType::IsFloatingPointType(condition->InputAt(0)->GetType());
4115*795d594fSAndroid Build Coastguard Worker }
4116*795d594fSAndroid Build Coastguard Worker
GetConditionForSelect(HCondition * condition)4117*795d594fSAndroid Build Coastguard Worker static inline Condition GetConditionForSelect(HCondition* condition) {
4118*795d594fSAndroid Build Coastguard Worker IfCondition cond = condition->GetCondition();
4119*795d594fSAndroid Build Coastguard Worker return IsConditionOnFloatingPointValues(condition) ? ARM64FPCondition(cond, condition->IsGtBias())
4120*795d594fSAndroid Build Coastguard Worker : ARM64Condition(cond);
4121*795d594fSAndroid Build Coastguard Worker }
4122*795d594fSAndroid Build Coastguard Worker
VisitSelect(HSelect * select)4123*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitSelect(HSelect* select) {
4124*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
4125*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(select->GetType())) {
4126*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
4127*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
4128*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4129*795d594fSAndroid Build Coastguard Worker } else {
4130*795d594fSAndroid Build Coastguard Worker HConstant* cst_true_value = select->GetTrueValue()->AsConstantOrNull();
4131*795d594fSAndroid Build Coastguard Worker HConstant* cst_false_value = select->GetFalseValue()->AsConstantOrNull();
4132*795d594fSAndroid Build Coastguard Worker bool is_true_value_constant = cst_true_value != nullptr;
4133*795d594fSAndroid Build Coastguard Worker bool is_false_value_constant = cst_false_value != nullptr;
4134*795d594fSAndroid Build Coastguard Worker // Ask VIXL whether we should synthesize constants in registers.
4135*795d594fSAndroid Build Coastguard Worker // We give an arbitrary register to VIXL when dealing with non-constant inputs.
4136*795d594fSAndroid Build Coastguard Worker Operand true_op = is_true_value_constant ?
4137*795d594fSAndroid Build Coastguard Worker Operand(Int64FromConstant(cst_true_value)) : Operand(x1);
4138*795d594fSAndroid Build Coastguard Worker Operand false_op = is_false_value_constant ?
4139*795d594fSAndroid Build Coastguard Worker Operand(Int64FromConstant(cst_false_value)) : Operand(x2);
4140*795d594fSAndroid Build Coastguard Worker bool true_value_in_register = false;
4141*795d594fSAndroid Build Coastguard Worker bool false_value_in_register = false;
4142*795d594fSAndroid Build Coastguard Worker MacroAssembler::GetCselSynthesisInformation(
4143*795d594fSAndroid Build Coastguard Worker x0, true_op, false_op, &true_value_in_register, &false_value_in_register);
4144*795d594fSAndroid Build Coastguard Worker true_value_in_register |= !is_true_value_constant;
4145*795d594fSAndroid Build Coastguard Worker false_value_in_register |= !is_false_value_constant;
4146*795d594fSAndroid Build Coastguard Worker
4147*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, true_value_in_register ? Location::RequiresRegister()
4148*795d594fSAndroid Build Coastguard Worker : Location::ConstantLocation(cst_true_value));
4149*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, false_value_in_register ? Location::RequiresRegister()
4150*795d594fSAndroid Build Coastguard Worker : Location::ConstantLocation(cst_false_value));
4151*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4152*795d594fSAndroid Build Coastguard Worker }
4153*795d594fSAndroid Build Coastguard Worker
4154*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
4155*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
4156*795d594fSAndroid Build Coastguard Worker }
4157*795d594fSAndroid Build Coastguard Worker }
4158*795d594fSAndroid Build Coastguard Worker
VisitSelect(HSelect * select)4159*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitSelect(HSelect* select) {
4160*795d594fSAndroid Build Coastguard Worker HInstruction* cond = select->GetCondition();
4161*795d594fSAndroid Build Coastguard Worker Condition csel_cond;
4162*795d594fSAndroid Build Coastguard Worker
4163*795d594fSAndroid Build Coastguard Worker if (IsBooleanValueOrMaterializedCondition(cond)) {
4164*795d594fSAndroid Build Coastguard Worker if (cond->IsCondition() && cond->GetNext() == select) {
4165*795d594fSAndroid Build Coastguard Worker // Use the condition flags set by the previous instruction.
4166*795d594fSAndroid Build Coastguard Worker csel_cond = GetConditionForSelect(cond->AsCondition());
4167*795d594fSAndroid Build Coastguard Worker } else {
4168*795d594fSAndroid Build Coastguard Worker __ Cmp(InputRegisterAt(select, 2), 0);
4169*795d594fSAndroid Build Coastguard Worker csel_cond = ne;
4170*795d594fSAndroid Build Coastguard Worker }
4171*795d594fSAndroid Build Coastguard Worker } else if (IsConditionOnFloatingPointValues(cond)) {
4172*795d594fSAndroid Build Coastguard Worker GenerateFcmp(cond);
4173*795d594fSAndroid Build Coastguard Worker csel_cond = GetConditionForSelect(cond->AsCondition());
4174*795d594fSAndroid Build Coastguard Worker } else {
4175*795d594fSAndroid Build Coastguard Worker __ Cmp(InputRegisterAt(cond, 0), InputOperandAt(cond, 1));
4176*795d594fSAndroid Build Coastguard Worker csel_cond = GetConditionForSelect(cond->AsCondition());
4177*795d594fSAndroid Build Coastguard Worker }
4178*795d594fSAndroid Build Coastguard Worker
4179*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(select->GetType())) {
4180*795d594fSAndroid Build Coastguard Worker __ Fcsel(OutputFPRegister(select),
4181*795d594fSAndroid Build Coastguard Worker InputFPRegisterAt(select, 1),
4182*795d594fSAndroid Build Coastguard Worker InputFPRegisterAt(select, 0),
4183*795d594fSAndroid Build Coastguard Worker csel_cond);
4184*795d594fSAndroid Build Coastguard Worker } else {
4185*795d594fSAndroid Build Coastguard Worker __ Csel(OutputRegister(select),
4186*795d594fSAndroid Build Coastguard Worker InputOperandAt(select, 1),
4187*795d594fSAndroid Build Coastguard Worker InputOperandAt(select, 0),
4188*795d594fSAndroid Build Coastguard Worker csel_cond);
4189*795d594fSAndroid Build Coastguard Worker }
4190*795d594fSAndroid Build Coastguard Worker }
4191*795d594fSAndroid Build Coastguard Worker
VisitNop(HNop * nop)4192*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNop(HNop* nop) {
4193*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(nop);
4194*795d594fSAndroid Build Coastguard Worker }
4195*795d594fSAndroid Build Coastguard Worker
VisitNop(HNop *)4196*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNop(HNop*) {
4197*795d594fSAndroid Build Coastguard Worker // The environment recording already happened in CodeGenerator::Compile.
4198*795d594fSAndroid Build Coastguard Worker }
4199*795d594fSAndroid Build Coastguard Worker
IncreaseFrame(size_t adjustment)4200*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::IncreaseFrame(size_t adjustment) {
4201*795d594fSAndroid Build Coastguard Worker __ Claim(adjustment);
4202*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().AdjustCFAOffset(adjustment);
4203*795d594fSAndroid Build Coastguard Worker }
4204*795d594fSAndroid Build Coastguard Worker
DecreaseFrame(size_t adjustment)4205*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::DecreaseFrame(size_t adjustment) {
4206*795d594fSAndroid Build Coastguard Worker __ Drop(adjustment);
4207*795d594fSAndroid Build Coastguard Worker GetAssembler()->cfi().AdjustCFAOffset(-adjustment);
4208*795d594fSAndroid Build Coastguard Worker }
4209*795d594fSAndroid Build Coastguard Worker
GenerateNop()4210*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateNop() {
4211*795d594fSAndroid Build Coastguard Worker __ Nop();
4212*795d594fSAndroid Build Coastguard Worker }
4213*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldGet(HInstanceFieldGet * instruction)4214*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4215*795d594fSAndroid Build Coastguard Worker HandleFieldGet(instruction, instruction->GetFieldInfo());
4216*795d594fSAndroid Build Coastguard Worker }
4217*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldGet(HInstanceFieldGet * instruction)4218*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4219*795d594fSAndroid Build Coastguard Worker HandleFieldGet(instruction, instruction->GetFieldInfo());
4220*795d594fSAndroid Build Coastguard Worker }
4221*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldSet(HInstanceFieldSet * instruction)4222*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4223*795d594fSAndroid Build Coastguard Worker HandleFieldSet(instruction);
4224*795d594fSAndroid Build Coastguard Worker }
4225*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldSet(HInstanceFieldSet * instruction)4226*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4227*795d594fSAndroid Build Coastguard Worker HandleFieldSet(instruction,
4228*795d594fSAndroid Build Coastguard Worker instruction->GetFieldInfo(),
4229*795d594fSAndroid Build Coastguard Worker instruction->GetValueCanBeNull(),
4230*795d594fSAndroid Build Coastguard Worker instruction->GetWriteBarrierKind());
4231*795d594fSAndroid Build Coastguard Worker }
4232*795d594fSAndroid Build Coastguard Worker
4233*795d594fSAndroid Build Coastguard Worker // Temp is used for read barrier.
NumberOfInstanceOfTemps(bool emit_read_barrier,TypeCheckKind type_check_kind)4234*795d594fSAndroid Build Coastguard Worker static size_t NumberOfInstanceOfTemps(bool emit_read_barrier, TypeCheckKind type_check_kind) {
4235*795d594fSAndroid Build Coastguard Worker if (emit_read_barrier &&
4236*795d594fSAndroid Build Coastguard Worker (kUseBakerReadBarrier ||
4237*795d594fSAndroid Build Coastguard Worker type_check_kind == TypeCheckKind::kAbstractClassCheck ||
4238*795d594fSAndroid Build Coastguard Worker type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
4239*795d594fSAndroid Build Coastguard Worker type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
4240*795d594fSAndroid Build Coastguard Worker return 1;
4241*795d594fSAndroid Build Coastguard Worker }
4242*795d594fSAndroid Build Coastguard Worker return 0;
4243*795d594fSAndroid Build Coastguard Worker }
4244*795d594fSAndroid Build Coastguard Worker
4245*795d594fSAndroid Build Coastguard Worker // Interface case has 3 temps, one for holding the number of interfaces, one for the current
4246*795d594fSAndroid Build Coastguard Worker // interface pointer, one for loading the current interface.
4247*795d594fSAndroid Build Coastguard Worker // The other checks have one temp for loading the object's class.
NumberOfCheckCastTemps(bool emit_read_barrier,TypeCheckKind type_check_kind)4248*795d594fSAndroid Build Coastguard Worker static size_t NumberOfCheckCastTemps(bool emit_read_barrier, TypeCheckKind type_check_kind) {
4249*795d594fSAndroid Build Coastguard Worker if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
4250*795d594fSAndroid Build Coastguard Worker return 3;
4251*795d594fSAndroid Build Coastguard Worker }
4252*795d594fSAndroid Build Coastguard Worker return 1 + NumberOfInstanceOfTemps(emit_read_barrier, type_check_kind);
4253*795d594fSAndroid Build Coastguard Worker }
4254*795d594fSAndroid Build Coastguard Worker
VisitInstanceOf(HInstanceOf * instruction)4255*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
4256*795d594fSAndroid Build Coastguard Worker LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4257*795d594fSAndroid Build Coastguard Worker TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4258*795d594fSAndroid Build Coastguard Worker bool baker_read_barrier_slow_path = false;
4259*795d594fSAndroid Build Coastguard Worker switch (type_check_kind) {
4260*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kExactCheck:
4261*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kAbstractClassCheck:
4262*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kClassHierarchyCheck:
4263*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayObjectCheck:
4264*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kInterfaceCheck: {
4265*795d594fSAndroid Build Coastguard Worker bool needs_read_barrier = codegen_->InstanceOfNeedsReadBarrier(instruction);
4266*795d594fSAndroid Build Coastguard Worker call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
4267*795d594fSAndroid Build Coastguard Worker baker_read_barrier_slow_path = (kUseBakerReadBarrier && needs_read_barrier) &&
4268*795d594fSAndroid Build Coastguard Worker (type_check_kind != TypeCheckKind::kInterfaceCheck);
4269*795d594fSAndroid Build Coastguard Worker break;
4270*795d594fSAndroid Build Coastguard Worker }
4271*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayCheck:
4272*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kUnresolvedCheck:
4273*795d594fSAndroid Build Coastguard Worker call_kind = LocationSummary::kCallOnSlowPath;
4274*795d594fSAndroid Build Coastguard Worker break;
4275*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kBitstringCheck:
4276*795d594fSAndroid Build Coastguard Worker break;
4277*795d594fSAndroid Build Coastguard Worker }
4278*795d594fSAndroid Build Coastguard Worker
4279*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
4280*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
4281*795d594fSAndroid Build Coastguard Worker if (baker_read_barrier_slow_path) {
4282*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
4283*795d594fSAndroid Build Coastguard Worker }
4284*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
4285*795d594fSAndroid Build Coastguard Worker if (type_check_kind == TypeCheckKind::kBitstringCheck) {
4286*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)));
4287*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)));
4288*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)));
4289*795d594fSAndroid Build Coastguard Worker } else {
4290*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
4291*795d594fSAndroid Build Coastguard Worker }
4292*795d594fSAndroid Build Coastguard Worker // The "out" register is used as a temporary, so it overlaps with the inputs.
4293*795d594fSAndroid Build Coastguard Worker // Note that TypeCheckSlowPathARM64 uses this register too.
4294*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4295*795d594fSAndroid Build Coastguard Worker // Add temps if necessary for read barriers.
4296*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(
4297*795d594fSAndroid Build Coastguard Worker NumberOfInstanceOfTemps(codegen_->EmitReadBarrier(), type_check_kind));
4298*795d594fSAndroid Build Coastguard Worker }
4299*795d594fSAndroid Build Coastguard Worker
VisitInstanceOf(HInstanceOf * instruction)4300*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
4301*795d594fSAndroid Build Coastguard Worker TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4302*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
4303*795d594fSAndroid Build Coastguard Worker Location obj_loc = locations->InAt(0);
4304*795d594fSAndroid Build Coastguard Worker Register obj = InputRegisterAt(instruction, 0);
4305*795d594fSAndroid Build Coastguard Worker Register cls = (type_check_kind == TypeCheckKind::kBitstringCheck)
4306*795d594fSAndroid Build Coastguard Worker ? Register()
4307*795d594fSAndroid Build Coastguard Worker : InputRegisterAt(instruction, 1);
4308*795d594fSAndroid Build Coastguard Worker Location out_loc = locations->Out();
4309*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
4310*795d594fSAndroid Build Coastguard Worker const size_t num_temps = NumberOfInstanceOfTemps(codegen_->EmitReadBarrier(), type_check_kind);
4311*795d594fSAndroid Build Coastguard Worker DCHECK_LE(num_temps, 1u);
4312*795d594fSAndroid Build Coastguard Worker Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
4313*795d594fSAndroid Build Coastguard Worker const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4314*795d594fSAndroid Build Coastguard Worker const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4315*795d594fSAndroid Build Coastguard Worker const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4316*795d594fSAndroid Build Coastguard Worker const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4317*795d594fSAndroid Build Coastguard Worker const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
4318*795d594fSAndroid Build Coastguard Worker const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
4319*795d594fSAndroid Build Coastguard Worker const uint32_t object_array_data_offset =
4320*795d594fSAndroid Build Coastguard Worker mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
4321*795d594fSAndroid Build Coastguard Worker
4322*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done, zero;
4323*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = nullptr;
4324*795d594fSAndroid Build Coastguard Worker
4325*795d594fSAndroid Build Coastguard Worker // Return 0 if `obj` is null.
4326*795d594fSAndroid Build Coastguard Worker // Avoid null check if we know `obj` is not null.
4327*795d594fSAndroid Build Coastguard Worker if (instruction->MustDoNullCheck()) {
4328*795d594fSAndroid Build Coastguard Worker __ Cbz(obj, &zero);
4329*795d594fSAndroid Build Coastguard Worker }
4330*795d594fSAndroid Build Coastguard Worker
4331*795d594fSAndroid Build Coastguard Worker switch (type_check_kind) {
4332*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kExactCheck: {
4333*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option =
4334*795d594fSAndroid Build Coastguard Worker codegen_->ReadBarrierOptionForInstanceOf(instruction);
4335*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = obj->klass_
4336*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4337*795d594fSAndroid Build Coastguard Worker out_loc,
4338*795d594fSAndroid Build Coastguard Worker obj_loc,
4339*795d594fSAndroid Build Coastguard Worker class_offset,
4340*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4341*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4342*795d594fSAndroid Build Coastguard Worker __ Cmp(out, cls);
4343*795d594fSAndroid Build Coastguard Worker __ Cset(out, eq);
4344*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4345*795d594fSAndroid Build Coastguard Worker __ B(&done);
4346*795d594fSAndroid Build Coastguard Worker }
4347*795d594fSAndroid Build Coastguard Worker break;
4348*795d594fSAndroid Build Coastguard Worker }
4349*795d594fSAndroid Build Coastguard Worker
4350*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kAbstractClassCheck: {
4351*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option =
4352*795d594fSAndroid Build Coastguard Worker codegen_->ReadBarrierOptionForInstanceOf(instruction);
4353*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = obj->klass_
4354*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4355*795d594fSAndroid Build Coastguard Worker out_loc,
4356*795d594fSAndroid Build Coastguard Worker obj_loc,
4357*795d594fSAndroid Build Coastguard Worker class_offset,
4358*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4359*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4360*795d594fSAndroid Build Coastguard Worker // If the class is abstract, we eagerly fetch the super class of the
4361*795d594fSAndroid Build Coastguard Worker // object to avoid doing a comparison we know will fail.
4362*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label loop, success;
4363*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
4364*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = out->super_class_
4365*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4366*795d594fSAndroid Build Coastguard Worker out_loc,
4367*795d594fSAndroid Build Coastguard Worker super_offset,
4368*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4369*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4370*795d594fSAndroid Build Coastguard Worker // If `out` is null, we use it for the result, and jump to `done`.
4371*795d594fSAndroid Build Coastguard Worker __ Cbz(out, &done);
4372*795d594fSAndroid Build Coastguard Worker __ Cmp(out, cls);
4373*795d594fSAndroid Build Coastguard Worker __ B(ne, &loop);
4374*795d594fSAndroid Build Coastguard Worker __ Mov(out, 1);
4375*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4376*795d594fSAndroid Build Coastguard Worker __ B(&done);
4377*795d594fSAndroid Build Coastguard Worker }
4378*795d594fSAndroid Build Coastguard Worker break;
4379*795d594fSAndroid Build Coastguard Worker }
4380*795d594fSAndroid Build Coastguard Worker
4381*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kClassHierarchyCheck: {
4382*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option =
4383*795d594fSAndroid Build Coastguard Worker codegen_->ReadBarrierOptionForInstanceOf(instruction);
4384*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = obj->klass_
4385*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4386*795d594fSAndroid Build Coastguard Worker out_loc,
4387*795d594fSAndroid Build Coastguard Worker obj_loc,
4388*795d594fSAndroid Build Coastguard Worker class_offset,
4389*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4390*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4391*795d594fSAndroid Build Coastguard Worker // Walk over the class hierarchy to find a match.
4392*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label loop, success;
4393*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
4394*795d594fSAndroid Build Coastguard Worker __ Cmp(out, cls);
4395*795d594fSAndroid Build Coastguard Worker __ B(eq, &success);
4396*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = out->super_class_
4397*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4398*795d594fSAndroid Build Coastguard Worker out_loc,
4399*795d594fSAndroid Build Coastguard Worker super_offset,
4400*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4401*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4402*795d594fSAndroid Build Coastguard Worker __ Cbnz(out, &loop);
4403*795d594fSAndroid Build Coastguard Worker // If `out` is null, we use it for the result, and jump to `done`.
4404*795d594fSAndroid Build Coastguard Worker __ B(&done);
4405*795d594fSAndroid Build Coastguard Worker __ Bind(&success);
4406*795d594fSAndroid Build Coastguard Worker __ Mov(out, 1);
4407*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4408*795d594fSAndroid Build Coastguard Worker __ B(&done);
4409*795d594fSAndroid Build Coastguard Worker }
4410*795d594fSAndroid Build Coastguard Worker break;
4411*795d594fSAndroid Build Coastguard Worker }
4412*795d594fSAndroid Build Coastguard Worker
4413*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayObjectCheck: {
4414*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option =
4415*795d594fSAndroid Build Coastguard Worker codegen_->ReadBarrierOptionForInstanceOf(instruction);
4416*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = obj->klass_
4417*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4418*795d594fSAndroid Build Coastguard Worker out_loc,
4419*795d594fSAndroid Build Coastguard Worker obj_loc,
4420*795d594fSAndroid Build Coastguard Worker class_offset,
4421*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4422*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4423*795d594fSAndroid Build Coastguard Worker // Do an exact check.
4424*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label exact_check;
4425*795d594fSAndroid Build Coastguard Worker __ Cmp(out, cls);
4426*795d594fSAndroid Build Coastguard Worker __ B(eq, &exact_check);
4427*795d594fSAndroid Build Coastguard Worker // Otherwise, we need to check that the object's class is a non-primitive array.
4428*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = out->component_type_
4429*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4430*795d594fSAndroid Build Coastguard Worker out_loc,
4431*795d594fSAndroid Build Coastguard Worker component_offset,
4432*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4433*795d594fSAndroid Build Coastguard Worker read_barrier_option);
4434*795d594fSAndroid Build Coastguard Worker // If `out` is null, we use it for the result, and jump to `done`.
4435*795d594fSAndroid Build Coastguard Worker __ Cbz(out, &done);
4436*795d594fSAndroid Build Coastguard Worker __ Ldrh(out, HeapOperand(out, primitive_offset));
4437*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4438*795d594fSAndroid Build Coastguard Worker __ Cbnz(out, &zero);
4439*795d594fSAndroid Build Coastguard Worker __ Bind(&exact_check);
4440*795d594fSAndroid Build Coastguard Worker __ Mov(out, 1);
4441*795d594fSAndroid Build Coastguard Worker __ B(&done);
4442*795d594fSAndroid Build Coastguard Worker break;
4443*795d594fSAndroid Build Coastguard Worker }
4444*795d594fSAndroid Build Coastguard Worker
4445*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayCheck: {
4446*795d594fSAndroid Build Coastguard Worker // No read barrier since the slow path will retry upon failure.
4447*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ out = obj->klass_
4448*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4449*795d594fSAndroid Build Coastguard Worker out_loc,
4450*795d594fSAndroid Build Coastguard Worker obj_loc,
4451*795d594fSAndroid Build Coastguard Worker class_offset,
4452*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4453*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4454*795d594fSAndroid Build Coastguard Worker __ Cmp(out, cls);
4455*795d594fSAndroid Build Coastguard Worker DCHECK(locations->OnlyCallsOnSlowPath());
4456*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARM64(
4457*795d594fSAndroid Build Coastguard Worker instruction, /* is_fatal= */ false);
4458*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
4459*795d594fSAndroid Build Coastguard Worker __ B(ne, slow_path->GetEntryLabel());
4460*795d594fSAndroid Build Coastguard Worker __ Mov(out, 1);
4461*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4462*795d594fSAndroid Build Coastguard Worker __ B(&done);
4463*795d594fSAndroid Build Coastguard Worker }
4464*795d594fSAndroid Build Coastguard Worker break;
4465*795d594fSAndroid Build Coastguard Worker }
4466*795d594fSAndroid Build Coastguard Worker
4467*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kInterfaceCheck: {
4468*795d594fSAndroid Build Coastguard Worker if (codegen_->InstanceOfNeedsReadBarrier(instruction)) {
4469*795d594fSAndroid Build Coastguard Worker DCHECK(locations->OnlyCallsOnSlowPath());
4470*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARM64(
4471*795d594fSAndroid Build Coastguard Worker instruction, /* is_fatal= */ false);
4472*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
4473*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
4474*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
4475*795d594fSAndroid Build Coastguard Worker break;
4476*795d594fSAndroid Build Coastguard Worker }
4477*795d594fSAndroid Build Coastguard Worker // For Baker read barrier, take the slow path while marking.
4478*795d594fSAndroid Build Coastguard Worker __ Cbnz(mr, slow_path->GetEntryLabel());
4479*795d594fSAndroid Build Coastguard Worker }
4480*795d594fSAndroid Build Coastguard Worker
4481*795d594fSAndroid Build Coastguard Worker // Fast-path without read barriers.
4482*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
4483*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW();
4484*795d594fSAndroid Build Coastguard Worker Register temp2 = temps.AcquireW();
4485*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4486*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(obj, class_offset));
4487*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp);
4488*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->iftable_
4489*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, HeapOperand(temp, iftable_offset));
4490*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp);
4491*795d594fSAndroid Build Coastguard Worker // Load the size of the `IfTable`. The `Class::iftable_` is never null.
4492*795d594fSAndroid Build Coastguard Worker __ Ldr(out, HeapOperand(temp, array_length_offset));
4493*795d594fSAndroid Build Coastguard Worker // Loop through the `IfTable` and check if any class matches.
4494*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label loop;
4495*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
4496*795d594fSAndroid Build Coastguard Worker __ Cbz(out, &done); // If taken, the result in `out` is already 0 (false).
4497*795d594fSAndroid Build Coastguard Worker __ Ldr(temp2, HeapOperand(temp, object_array_data_offset));
4498*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp2);
4499*795d594fSAndroid Build Coastguard Worker // Go to next interface.
4500*795d594fSAndroid Build Coastguard Worker __ Add(temp, temp, 2 * kHeapReferenceSize);
4501*795d594fSAndroid Build Coastguard Worker __ Sub(out, out, 2);
4502*795d594fSAndroid Build Coastguard Worker // Compare the classes and continue the loop if they do not match.
4503*795d594fSAndroid Build Coastguard Worker __ Cmp(cls, temp2);
4504*795d594fSAndroid Build Coastguard Worker __ B(ne, &loop);
4505*795d594fSAndroid Build Coastguard Worker __ Mov(out, 1);
4506*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4507*795d594fSAndroid Build Coastguard Worker __ B(&done);
4508*795d594fSAndroid Build Coastguard Worker }
4509*795d594fSAndroid Build Coastguard Worker break;
4510*795d594fSAndroid Build Coastguard Worker }
4511*795d594fSAndroid Build Coastguard Worker
4512*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kUnresolvedCheck: {
4513*795d594fSAndroid Build Coastguard Worker // Note that we indeed only call on slow path, but we always go
4514*795d594fSAndroid Build Coastguard Worker // into the slow path for the unresolved check case.
4515*795d594fSAndroid Build Coastguard Worker //
4516*795d594fSAndroid Build Coastguard Worker // We cannot directly call the InstanceofNonTrivial runtime
4517*795d594fSAndroid Build Coastguard Worker // entry point without resorting to a type checking slow path
4518*795d594fSAndroid Build Coastguard Worker // here (i.e. by calling InvokeRuntime directly), as it would
4519*795d594fSAndroid Build Coastguard Worker // require to assign fixed registers for the inputs of this
4520*795d594fSAndroid Build Coastguard Worker // HInstanceOf instruction (following the runtime calling
4521*795d594fSAndroid Build Coastguard Worker // convention), which might be cluttered by the potential first
4522*795d594fSAndroid Build Coastguard Worker // read barrier emission at the beginning of this method.
4523*795d594fSAndroid Build Coastguard Worker //
4524*795d594fSAndroid Build Coastguard Worker // TODO: Introduce a new runtime entry point taking the object
4525*795d594fSAndroid Build Coastguard Worker // to test (instead of its class) as argument, and let it deal
4526*795d594fSAndroid Build Coastguard Worker // with the read barrier issues. This will let us refactor this
4527*795d594fSAndroid Build Coastguard Worker // case of the `switch` code as it was previously (with a direct
4528*795d594fSAndroid Build Coastguard Worker // call to the runtime not using a type checking slow path).
4529*795d594fSAndroid Build Coastguard Worker // This should also be beneficial for the other cases above.
4530*795d594fSAndroid Build Coastguard Worker DCHECK(locations->OnlyCallsOnSlowPath());
4531*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARM64(
4532*795d594fSAndroid Build Coastguard Worker instruction, /* is_fatal= */ false);
4533*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
4534*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
4535*795d594fSAndroid Build Coastguard Worker break;
4536*795d594fSAndroid Build Coastguard Worker }
4537*795d594fSAndroid Build Coastguard Worker
4538*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kBitstringCheck: {
4539*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4540*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4541*795d594fSAndroid Build Coastguard Worker out_loc,
4542*795d594fSAndroid Build Coastguard Worker obj_loc,
4543*795d594fSAndroid Build Coastguard Worker class_offset,
4544*795d594fSAndroid Build Coastguard Worker maybe_temp_loc,
4545*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4546*795d594fSAndroid Build Coastguard Worker
4547*795d594fSAndroid Build Coastguard Worker GenerateBitstringTypeCheckCompare(instruction, out);
4548*795d594fSAndroid Build Coastguard Worker __ Cset(out, eq);
4549*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4550*795d594fSAndroid Build Coastguard Worker __ B(&done);
4551*795d594fSAndroid Build Coastguard Worker }
4552*795d594fSAndroid Build Coastguard Worker break;
4553*795d594fSAndroid Build Coastguard Worker }
4554*795d594fSAndroid Build Coastguard Worker }
4555*795d594fSAndroid Build Coastguard Worker
4556*795d594fSAndroid Build Coastguard Worker if (zero.IsLinked()) {
4557*795d594fSAndroid Build Coastguard Worker __ Bind(&zero);
4558*795d594fSAndroid Build Coastguard Worker __ Mov(out, 0);
4559*795d594fSAndroid Build Coastguard Worker }
4560*795d594fSAndroid Build Coastguard Worker
4561*795d594fSAndroid Build Coastguard Worker if (done.IsLinked()) {
4562*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
4563*795d594fSAndroid Build Coastguard Worker }
4564*795d594fSAndroid Build Coastguard Worker
4565*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4566*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
4567*795d594fSAndroid Build Coastguard Worker }
4568*795d594fSAndroid Build Coastguard Worker }
4569*795d594fSAndroid Build Coastguard Worker
VisitCheckCast(HCheckCast * instruction)4570*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
4571*795d594fSAndroid Build Coastguard Worker TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4572*795d594fSAndroid Build Coastguard Worker LocationSummary::CallKind call_kind = codegen_->GetCheckCastCallKind(instruction);
4573*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
4574*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
4575*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
4576*795d594fSAndroid Build Coastguard Worker if (type_check_kind == TypeCheckKind::kBitstringCheck) {
4577*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)));
4578*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)));
4579*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)));
4580*795d594fSAndroid Build Coastguard Worker } else {
4581*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
4582*795d594fSAndroid Build Coastguard Worker }
4583*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(NumberOfCheckCastTemps(codegen_->EmitReadBarrier(), type_check_kind));
4584*795d594fSAndroid Build Coastguard Worker }
4585*795d594fSAndroid Build Coastguard Worker
VisitCheckCast(HCheckCast * instruction)4586*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
4587*795d594fSAndroid Build Coastguard Worker TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4588*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
4589*795d594fSAndroid Build Coastguard Worker Location obj_loc = locations->InAt(0);
4590*795d594fSAndroid Build Coastguard Worker Register obj = InputRegisterAt(instruction, 0);
4591*795d594fSAndroid Build Coastguard Worker Register cls = (type_check_kind == TypeCheckKind::kBitstringCheck)
4592*795d594fSAndroid Build Coastguard Worker ? Register()
4593*795d594fSAndroid Build Coastguard Worker : InputRegisterAt(instruction, 1);
4594*795d594fSAndroid Build Coastguard Worker const size_t num_temps = NumberOfCheckCastTemps(codegen_->EmitReadBarrier(), type_check_kind);
4595*795d594fSAndroid Build Coastguard Worker DCHECK_GE(num_temps, 1u);
4596*795d594fSAndroid Build Coastguard Worker DCHECK_LE(num_temps, 3u);
4597*795d594fSAndroid Build Coastguard Worker Location temp_loc = locations->GetTemp(0);
4598*795d594fSAndroid Build Coastguard Worker Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
4599*795d594fSAndroid Build Coastguard Worker Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
4600*795d594fSAndroid Build Coastguard Worker Register temp = WRegisterFrom(temp_loc);
4601*795d594fSAndroid Build Coastguard Worker const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4602*795d594fSAndroid Build Coastguard Worker const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4603*795d594fSAndroid Build Coastguard Worker const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4604*795d594fSAndroid Build Coastguard Worker const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4605*795d594fSAndroid Build Coastguard Worker const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
4606*795d594fSAndroid Build Coastguard Worker const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
4607*795d594fSAndroid Build Coastguard Worker const uint32_t object_array_data_offset =
4608*795d594fSAndroid Build Coastguard Worker mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
4609*795d594fSAndroid Build Coastguard Worker
4610*795d594fSAndroid Build Coastguard Worker bool is_type_check_slow_path_fatal = codegen_->IsTypeCheckSlowPathFatal(instruction);
4611*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* type_check_slow_path =
4612*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARM64(
4613*795d594fSAndroid Build Coastguard Worker instruction, is_type_check_slow_path_fatal);
4614*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(type_check_slow_path);
4615*795d594fSAndroid Build Coastguard Worker
4616*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
4617*795d594fSAndroid Build Coastguard Worker // Avoid null check if we know obj is not null.
4618*795d594fSAndroid Build Coastguard Worker if (instruction->MustDoNullCheck()) {
4619*795d594fSAndroid Build Coastguard Worker __ Cbz(obj, &done);
4620*795d594fSAndroid Build Coastguard Worker }
4621*795d594fSAndroid Build Coastguard Worker
4622*795d594fSAndroid Build Coastguard Worker switch (type_check_kind) {
4623*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kExactCheck:
4624*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayCheck: {
4625*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4626*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4627*795d594fSAndroid Build Coastguard Worker temp_loc,
4628*795d594fSAndroid Build Coastguard Worker obj_loc,
4629*795d594fSAndroid Build Coastguard Worker class_offset,
4630*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4631*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4632*795d594fSAndroid Build Coastguard Worker
4633*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, cls);
4634*795d594fSAndroid Build Coastguard Worker // Jump to slow path for throwing the exception or doing a
4635*795d594fSAndroid Build Coastguard Worker // more involved array check.
4636*795d594fSAndroid Build Coastguard Worker __ B(ne, type_check_slow_path->GetEntryLabel());
4637*795d594fSAndroid Build Coastguard Worker break;
4638*795d594fSAndroid Build Coastguard Worker }
4639*795d594fSAndroid Build Coastguard Worker
4640*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kAbstractClassCheck: {
4641*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4642*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4643*795d594fSAndroid Build Coastguard Worker temp_loc,
4644*795d594fSAndroid Build Coastguard Worker obj_loc,
4645*795d594fSAndroid Build Coastguard Worker class_offset,
4646*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4647*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4648*795d594fSAndroid Build Coastguard Worker
4649*795d594fSAndroid Build Coastguard Worker // If the class is abstract, we eagerly fetch the super class of the
4650*795d594fSAndroid Build Coastguard Worker // object to avoid doing a comparison we know will fail.
4651*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label loop;
4652*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
4653*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->super_class_
4654*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4655*795d594fSAndroid Build Coastguard Worker temp_loc,
4656*795d594fSAndroid Build Coastguard Worker super_offset,
4657*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4658*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4659*795d594fSAndroid Build Coastguard Worker
4660*795d594fSAndroid Build Coastguard Worker // If the class reference currently in `temp` is null, jump to the slow path to throw the
4661*795d594fSAndroid Build Coastguard Worker // exception.
4662*795d594fSAndroid Build Coastguard Worker __ Cbz(temp, type_check_slow_path->GetEntryLabel());
4663*795d594fSAndroid Build Coastguard Worker // Otherwise, compare classes.
4664*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, cls);
4665*795d594fSAndroid Build Coastguard Worker __ B(ne, &loop);
4666*795d594fSAndroid Build Coastguard Worker break;
4667*795d594fSAndroid Build Coastguard Worker }
4668*795d594fSAndroid Build Coastguard Worker
4669*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kClassHierarchyCheck: {
4670*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4671*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4672*795d594fSAndroid Build Coastguard Worker temp_loc,
4673*795d594fSAndroid Build Coastguard Worker obj_loc,
4674*795d594fSAndroid Build Coastguard Worker class_offset,
4675*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4676*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4677*795d594fSAndroid Build Coastguard Worker
4678*795d594fSAndroid Build Coastguard Worker // Walk over the class hierarchy to find a match.
4679*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label loop;
4680*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
4681*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, cls);
4682*795d594fSAndroid Build Coastguard Worker __ B(eq, &done);
4683*795d594fSAndroid Build Coastguard Worker
4684*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->super_class_
4685*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4686*795d594fSAndroid Build Coastguard Worker temp_loc,
4687*795d594fSAndroid Build Coastguard Worker super_offset,
4688*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4689*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4690*795d594fSAndroid Build Coastguard Worker
4691*795d594fSAndroid Build Coastguard Worker // If the class reference currently in `temp` is not null, jump
4692*795d594fSAndroid Build Coastguard Worker // back at the beginning of the loop.
4693*795d594fSAndroid Build Coastguard Worker __ Cbnz(temp, &loop);
4694*795d594fSAndroid Build Coastguard Worker // Otherwise, jump to the slow path to throw the exception.
4695*795d594fSAndroid Build Coastguard Worker __ B(type_check_slow_path->GetEntryLabel());
4696*795d594fSAndroid Build Coastguard Worker break;
4697*795d594fSAndroid Build Coastguard Worker }
4698*795d594fSAndroid Build Coastguard Worker
4699*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayObjectCheck: {
4700*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4701*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4702*795d594fSAndroid Build Coastguard Worker temp_loc,
4703*795d594fSAndroid Build Coastguard Worker obj_loc,
4704*795d594fSAndroid Build Coastguard Worker class_offset,
4705*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4706*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4707*795d594fSAndroid Build Coastguard Worker
4708*795d594fSAndroid Build Coastguard Worker // Do an exact check.
4709*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, cls);
4710*795d594fSAndroid Build Coastguard Worker __ B(eq, &done);
4711*795d594fSAndroid Build Coastguard Worker
4712*795d594fSAndroid Build Coastguard Worker // Otherwise, we need to check that the object's class is a non-primitive array.
4713*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->component_type_
4714*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4715*795d594fSAndroid Build Coastguard Worker temp_loc,
4716*795d594fSAndroid Build Coastguard Worker component_offset,
4717*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4718*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4719*795d594fSAndroid Build Coastguard Worker
4720*795d594fSAndroid Build Coastguard Worker // If the component type is null, jump to the slow path to throw the exception.
4721*795d594fSAndroid Build Coastguard Worker __ Cbz(temp, type_check_slow_path->GetEntryLabel());
4722*795d594fSAndroid Build Coastguard Worker // Otherwise, the object is indeed an array. Further check that this component type is not a
4723*795d594fSAndroid Build Coastguard Worker // primitive type.
4724*795d594fSAndroid Build Coastguard Worker __ Ldrh(temp, HeapOperand(temp, primitive_offset));
4725*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4726*795d594fSAndroid Build Coastguard Worker __ Cbnz(temp, type_check_slow_path->GetEntryLabel());
4727*795d594fSAndroid Build Coastguard Worker break;
4728*795d594fSAndroid Build Coastguard Worker }
4729*795d594fSAndroid Build Coastguard Worker
4730*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kUnresolvedCheck:
4731*795d594fSAndroid Build Coastguard Worker // We always go into the type check slow path for the unresolved check cases.
4732*795d594fSAndroid Build Coastguard Worker //
4733*795d594fSAndroid Build Coastguard Worker // We cannot directly call the CheckCast runtime entry point
4734*795d594fSAndroid Build Coastguard Worker // without resorting to a type checking slow path here (i.e. by
4735*795d594fSAndroid Build Coastguard Worker // calling InvokeRuntime directly), as it would require to
4736*795d594fSAndroid Build Coastguard Worker // assign fixed registers for the inputs of this HInstanceOf
4737*795d594fSAndroid Build Coastguard Worker // instruction (following the runtime calling convention), which
4738*795d594fSAndroid Build Coastguard Worker // might be cluttered by the potential first read barrier
4739*795d594fSAndroid Build Coastguard Worker // emission at the beginning of this method.
4740*795d594fSAndroid Build Coastguard Worker __ B(type_check_slow_path->GetEntryLabel());
4741*795d594fSAndroid Build Coastguard Worker break;
4742*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kInterfaceCheck: {
4743*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4744*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4745*795d594fSAndroid Build Coastguard Worker temp_loc,
4746*795d594fSAndroid Build Coastguard Worker obj_loc,
4747*795d594fSAndroid Build Coastguard Worker class_offset,
4748*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4749*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4750*795d594fSAndroid Build Coastguard Worker
4751*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->iftable_
4752*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadOneRegister(instruction,
4753*795d594fSAndroid Build Coastguard Worker temp_loc,
4754*795d594fSAndroid Build Coastguard Worker iftable_offset,
4755*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4756*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4757*795d594fSAndroid Build Coastguard Worker // Load the size of the `IfTable`. The `Class::iftable_` is never null.
4758*795d594fSAndroid Build Coastguard Worker __ Ldr(WRegisterFrom(maybe_temp2_loc), HeapOperand(temp.W(), array_length_offset));
4759*795d594fSAndroid Build Coastguard Worker // Loop through the iftable and check if any class matches.
4760*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label start_loop;
4761*795d594fSAndroid Build Coastguard Worker __ Bind(&start_loop);
4762*795d594fSAndroid Build Coastguard Worker __ Cbz(WRegisterFrom(maybe_temp2_loc), type_check_slow_path->GetEntryLabel());
4763*795d594fSAndroid Build Coastguard Worker __ Ldr(WRegisterFrom(maybe_temp3_loc), HeapOperand(temp.W(), object_array_data_offset));
4764*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(WRegisterFrom(maybe_temp3_loc));
4765*795d594fSAndroid Build Coastguard Worker // Go to next interface.
4766*795d594fSAndroid Build Coastguard Worker __ Add(temp, temp, 2 * kHeapReferenceSize);
4767*795d594fSAndroid Build Coastguard Worker __ Sub(WRegisterFrom(maybe_temp2_loc), WRegisterFrom(maybe_temp2_loc), 2);
4768*795d594fSAndroid Build Coastguard Worker // Compare the classes and continue the loop if they do not match.
4769*795d594fSAndroid Build Coastguard Worker __ Cmp(cls, WRegisterFrom(maybe_temp3_loc));
4770*795d594fSAndroid Build Coastguard Worker __ B(ne, &start_loop);
4771*795d594fSAndroid Build Coastguard Worker break;
4772*795d594fSAndroid Build Coastguard Worker }
4773*795d594fSAndroid Build Coastguard Worker
4774*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kBitstringCheck: {
4775*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = obj->klass_
4776*795d594fSAndroid Build Coastguard Worker GenerateReferenceLoadTwoRegisters(instruction,
4777*795d594fSAndroid Build Coastguard Worker temp_loc,
4778*795d594fSAndroid Build Coastguard Worker obj_loc,
4779*795d594fSAndroid Build Coastguard Worker class_offset,
4780*795d594fSAndroid Build Coastguard Worker maybe_temp2_loc,
4781*795d594fSAndroid Build Coastguard Worker kWithoutReadBarrier);
4782*795d594fSAndroid Build Coastguard Worker
4783*795d594fSAndroid Build Coastguard Worker GenerateBitstringTypeCheckCompare(instruction, temp);
4784*795d594fSAndroid Build Coastguard Worker __ B(ne, type_check_slow_path->GetEntryLabel());
4785*795d594fSAndroid Build Coastguard Worker break;
4786*795d594fSAndroid Build Coastguard Worker }
4787*795d594fSAndroid Build Coastguard Worker }
4788*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
4789*795d594fSAndroid Build Coastguard Worker
4790*795d594fSAndroid Build Coastguard Worker __ Bind(type_check_slow_path->GetExitLabel());
4791*795d594fSAndroid Build Coastguard Worker }
4792*795d594fSAndroid Build Coastguard Worker
VisitIntConstant(HIntConstant * constant)4793*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
4794*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
4795*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::ConstantLocation(constant));
4796*795d594fSAndroid Build Coastguard Worker }
4797*795d594fSAndroid Build Coastguard Worker
VisitIntConstant(HIntConstant * constant)4798*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitIntConstant([[maybe_unused]] HIntConstant* constant) {
4799*795d594fSAndroid Build Coastguard Worker // Will be generated at use site.
4800*795d594fSAndroid Build Coastguard Worker }
4801*795d594fSAndroid Build Coastguard Worker
VisitNullConstant(HNullConstant * constant)4802*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNullConstant(HNullConstant* constant) {
4803*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
4804*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::ConstantLocation(constant));
4805*795d594fSAndroid Build Coastguard Worker }
4806*795d594fSAndroid Build Coastguard Worker
VisitNullConstant(HNullConstant * constant)4807*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNullConstant([[maybe_unused]] HNullConstant* constant) {
4808*795d594fSAndroid Build Coastguard Worker // Will be generated at use site.
4809*795d594fSAndroid Build Coastguard Worker }
4810*795d594fSAndroid Build Coastguard Worker
VisitInvokeUnresolved(HInvokeUnresolved * invoke)4811*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
4812*795d594fSAndroid Build Coastguard Worker // The trampoline uses the same calling convention as dex calling conventions,
4813*795d594fSAndroid Build Coastguard Worker // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
4814*795d594fSAndroid Build Coastguard Worker // the method_idx.
4815*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
4816*795d594fSAndroid Build Coastguard Worker }
4817*795d594fSAndroid Build Coastguard Worker
VisitInvokeUnresolved(HInvokeUnresolved * invoke)4818*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
4819*795d594fSAndroid Build Coastguard Worker codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
4820*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
4821*795d594fSAndroid Build Coastguard Worker }
4822*795d594fSAndroid Build Coastguard Worker
HandleInvoke(HInvoke * invoke)4823*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
4824*795d594fSAndroid Build Coastguard Worker InvokeDexCallingConventionVisitorARM64 calling_convention_visitor;
4825*795d594fSAndroid Build Coastguard Worker CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
4826*795d594fSAndroid Build Coastguard Worker }
4827*795d594fSAndroid Build Coastguard Worker
VisitInvokeInterface(HInvokeInterface * invoke)4828*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
4829*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
4830*795d594fSAndroid Build Coastguard Worker if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
4831*795d594fSAndroid Build Coastguard Worker // We cannot request ip1 as it's blocked by the register allocator.
4832*795d594fSAndroid Build Coastguard Worker invoke->GetLocations()->SetInAt(invoke->GetNumberOfArguments() - 1, Location::Any());
4833*795d594fSAndroid Build Coastguard Worker }
4834*795d594fSAndroid Build Coastguard Worker }
4835*795d594fSAndroid Build Coastguard Worker
MaybeGenerateInlineCacheCheck(HInstruction * instruction,Register klass)4836*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeGenerateInlineCacheCheck(HInstruction* instruction,
4837*795d594fSAndroid Build Coastguard Worker Register klass) {
4838*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(klass.GetCode(), 0u);
4839*795d594fSAndroid Build Coastguard Worker if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) {
4840*795d594fSAndroid Build Coastguard Worker ProfilingInfo* info = GetGraph()->GetProfilingInfo();
4841*795d594fSAndroid Build Coastguard Worker DCHECK(info != nullptr);
4842*795d594fSAndroid Build Coastguard Worker InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(
4843*795d594fSAndroid Build Coastguard Worker info, GetCompilerOptions(), instruction->AsInvoke());
4844*795d594fSAndroid Build Coastguard Worker if (cache != nullptr) {
4845*795d594fSAndroid Build Coastguard Worker uint64_t address = reinterpret_cast64<uint64_t>(cache);
4846*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label done;
4847*795d594fSAndroid Build Coastguard Worker __ Mov(x8, address);
4848*795d594fSAndroid Build Coastguard Worker __ Ldr(w9, MemOperand(x8, InlineCache::ClassesOffset().Int32Value()));
4849*795d594fSAndroid Build Coastguard Worker // Fast path for a monomorphic cache.
4850*795d594fSAndroid Build Coastguard Worker __ Cmp(klass.W(), w9);
4851*795d594fSAndroid Build Coastguard Worker __ B(eq, &done);
4852*795d594fSAndroid Build Coastguard Worker InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc());
4853*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
4854*795d594fSAndroid Build Coastguard Worker } else {
4855*795d594fSAndroid Build Coastguard Worker // This is unexpected, but we don't guarantee stable compilation across
4856*795d594fSAndroid Build Coastguard Worker // JIT runs so just warn about it.
4857*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
4858*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod();
4859*795d594fSAndroid Build Coastguard Worker }
4860*795d594fSAndroid Build Coastguard Worker }
4861*795d594fSAndroid Build Coastguard Worker }
4862*795d594fSAndroid Build Coastguard Worker
VisitInvokeInterface(HInvokeInterface * invoke)4863*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
4864*795d594fSAndroid Build Coastguard Worker // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
4865*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
4866*795d594fSAndroid Build Coastguard Worker Register temp = XRegisterFrom(locations->GetTemp(0));
4867*795d594fSAndroid Build Coastguard Worker Location receiver = locations->InAt(0);
4868*795d594fSAndroid Build Coastguard Worker Offset class_offset = mirror::Object::ClassOffset();
4869*795d594fSAndroid Build Coastguard Worker Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize);
4870*795d594fSAndroid Build Coastguard Worker
4871*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
4872*795d594fSAndroid Build Coastguard Worker if (receiver.IsStackSlot()) {
4873*795d594fSAndroid Build Coastguard Worker __ Ldr(temp.W(), StackOperandFrom(receiver));
4874*795d594fSAndroid Build Coastguard Worker {
4875*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
4876*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = temp->klass_
4877*795d594fSAndroid Build Coastguard Worker __ Ldr(temp.W(), HeapOperand(temp.W(), class_offset));
4878*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(invoke);
4879*795d594fSAndroid Build Coastguard Worker }
4880*795d594fSAndroid Build Coastguard Worker } else {
4881*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
4882*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = receiver->klass_
4883*795d594fSAndroid Build Coastguard Worker __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
4884*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(invoke);
4885*795d594fSAndroid Build Coastguard Worker }
4886*795d594fSAndroid Build Coastguard Worker
4887*795d594fSAndroid Build Coastguard Worker // Instead of simply (possibly) unpoisoning `temp` here, we should
4888*795d594fSAndroid Build Coastguard Worker // emit a read barrier for the previous class reference load.
4889*795d594fSAndroid Build Coastguard Worker // However this is not required in practice, as this is an
4890*795d594fSAndroid Build Coastguard Worker // intermediate/temporary reference and because the current
4891*795d594fSAndroid Build Coastguard Worker // concurrent copying collector keeps the from-space memory
4892*795d594fSAndroid Build Coastguard Worker // intact/accessible until the end of the marking phase (the
4893*795d594fSAndroid Build Coastguard Worker // concurrent copying collector may not in the future).
4894*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
4895*795d594fSAndroid Build Coastguard Worker
4896*795d594fSAndroid Build Coastguard Worker // If we're compiling baseline, update the inline cache.
4897*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateInlineCacheCheck(invoke, temp);
4898*795d594fSAndroid Build Coastguard Worker
4899*795d594fSAndroid Build Coastguard Worker // The register ip1 is required to be used for the hidden argument in
4900*795d594fSAndroid Build Coastguard Worker // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
4901*795d594fSAndroid Build Coastguard Worker MacroAssembler* masm = GetVIXLAssembler();
4902*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope scratch_scope(masm);
4903*795d594fSAndroid Build Coastguard Worker scratch_scope.Exclude(ip1);
4904*795d594fSAndroid Build Coastguard Worker if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
4905*795d594fSAndroid Build Coastguard Worker Location interface_method = locations->InAt(invoke->GetNumberOfArguments() - 1);
4906*795d594fSAndroid Build Coastguard Worker if (interface_method.IsStackSlot()) {
4907*795d594fSAndroid Build Coastguard Worker __ Ldr(ip1, StackOperandFrom(interface_method));
4908*795d594fSAndroid Build Coastguard Worker } else {
4909*795d594fSAndroid Build Coastguard Worker __ Mov(ip1, XRegisterFrom(interface_method));
4910*795d594fSAndroid Build Coastguard Worker }
4911*795d594fSAndroid Build Coastguard Worker // If the load kind is through a runtime call, we will pass the method we
4912*795d594fSAndroid Build Coastguard Worker // fetch the IMT, which will either be a no-op if we don't hit the conflict
4913*795d594fSAndroid Build Coastguard Worker // stub, or will make us always go through the trampoline when there is a
4914*795d594fSAndroid Build Coastguard Worker // conflict.
4915*795d594fSAndroid Build Coastguard Worker } else if (invoke->GetHiddenArgumentLoadKind() != MethodLoadKind::kRuntimeCall) {
4916*795d594fSAndroid Build Coastguard Worker codegen_->LoadMethod(
4917*795d594fSAndroid Build Coastguard Worker invoke->GetHiddenArgumentLoadKind(), Location::RegisterLocation(ip1.GetCode()), invoke);
4918*795d594fSAndroid Build Coastguard Worker }
4919*795d594fSAndroid Build Coastguard Worker
4920*795d594fSAndroid Build Coastguard Worker __ Ldr(temp,
4921*795d594fSAndroid Build Coastguard Worker MemOperand(temp, mirror::Class::ImtPtrOffset(kArm64PointerSize).Uint32Value()));
4922*795d594fSAndroid Build Coastguard Worker uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
4923*795d594fSAndroid Build Coastguard Worker invoke->GetImtIndex(), kArm64PointerSize));
4924*795d594fSAndroid Build Coastguard Worker // temp = temp->GetImtEntryAt(method_offset);
4925*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, MemOperand(temp, method_offset));
4926*795d594fSAndroid Build Coastguard Worker if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRuntimeCall) {
4927*795d594fSAndroid Build Coastguard Worker // We pass the method from the IMT in case of a conflict. This will ensure
4928*795d594fSAndroid Build Coastguard Worker // we go into the runtime to resolve the actual method.
4929*795d594fSAndroid Build Coastguard Worker __ Mov(ip1, temp);
4930*795d594fSAndroid Build Coastguard Worker }
4931*795d594fSAndroid Build Coastguard Worker // lr = temp->GetEntryPoint();
4932*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(temp, entry_point.Int32Value()));
4933*795d594fSAndroid Build Coastguard Worker
4934*795d594fSAndroid Build Coastguard Worker {
4935*795d594fSAndroid Build Coastguard Worker // Ensure the pc position is recorded immediately after the `blr` instruction.
4936*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, CodeBufferCheckScope::kExactSize);
4937*795d594fSAndroid Build Coastguard Worker
4938*795d594fSAndroid Build Coastguard Worker // lr();
4939*795d594fSAndroid Build Coastguard Worker __ blr(lr);
4940*795d594fSAndroid Build Coastguard Worker DCHECK(!codegen_->IsLeafMethod());
4941*795d594fSAndroid Build Coastguard Worker codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
4942*795d594fSAndroid Build Coastguard Worker }
4943*795d594fSAndroid Build Coastguard Worker
4944*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
4945*795d594fSAndroid Build Coastguard Worker }
4946*795d594fSAndroid Build Coastguard Worker
VisitInvokeVirtual(HInvokeVirtual * invoke)4947*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
4948*795d594fSAndroid Build Coastguard Worker IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetAllocator(), codegen_);
4949*795d594fSAndroid Build Coastguard Worker if (intrinsic.TryDispatch(invoke)) {
4950*795d594fSAndroid Build Coastguard Worker return;
4951*795d594fSAndroid Build Coastguard Worker }
4952*795d594fSAndroid Build Coastguard Worker
4953*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
4954*795d594fSAndroid Build Coastguard Worker }
4955*795d594fSAndroid Build Coastguard Worker
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)4956*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
4957*795d594fSAndroid Build Coastguard Worker // Explicit clinit checks triggered by static invokes must have been pruned by
4958*795d594fSAndroid Build Coastguard Worker // art::PrepareForRegisterAllocation.
4959*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
4960*795d594fSAndroid Build Coastguard Worker
4961*795d594fSAndroid Build Coastguard Worker IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetAllocator(), codegen_);
4962*795d594fSAndroid Build Coastguard Worker if (intrinsic.TryDispatch(invoke)) {
4963*795d594fSAndroid Build Coastguard Worker return;
4964*795d594fSAndroid Build Coastguard Worker }
4965*795d594fSAndroid Build Coastguard Worker
4966*795d594fSAndroid Build Coastguard Worker if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
4967*795d594fSAndroid Build Coastguard Worker CriticalNativeCallingConventionVisitorARM64 calling_convention_visitor(
4968*795d594fSAndroid Build Coastguard Worker /*for_register_allocation=*/ true);
4969*795d594fSAndroid Build Coastguard Worker CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
4970*795d594fSAndroid Build Coastguard Worker } else {
4971*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
4972*795d594fSAndroid Build Coastguard Worker }
4973*795d594fSAndroid Build Coastguard Worker }
4974*795d594fSAndroid Build Coastguard Worker
TryGenerateIntrinsicCode(HInvoke * invoke,CodeGeneratorARM64 * codegen)4975*795d594fSAndroid Build Coastguard Worker static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM64* codegen) {
4976*795d594fSAndroid Build Coastguard Worker if (invoke->GetLocations()->Intrinsified()) {
4977*795d594fSAndroid Build Coastguard Worker IntrinsicCodeGeneratorARM64 intrinsic(codegen);
4978*795d594fSAndroid Build Coastguard Worker intrinsic.Dispatch(invoke);
4979*795d594fSAndroid Build Coastguard Worker return true;
4980*795d594fSAndroid Build Coastguard Worker }
4981*795d594fSAndroid Build Coastguard Worker return false;
4982*795d594fSAndroid Build Coastguard Worker }
4983*795d594fSAndroid Build Coastguard Worker
GetSupportedInvokeStaticOrDirectDispatch(const HInvokeStaticOrDirect::DispatchInfo & desired_dispatch_info,ArtMethod * method)4984*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch(
4985*795d594fSAndroid Build Coastguard Worker const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
4986*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] ArtMethod* method) {
4987*795d594fSAndroid Build Coastguard Worker // On ARM64 we support all dispatch types.
4988*795d594fSAndroid Build Coastguard Worker return desired_dispatch_info;
4989*795d594fSAndroid Build Coastguard Worker }
4990*795d594fSAndroid Build Coastguard Worker
LoadMethod(MethodLoadKind load_kind,Location temp,HInvoke * invoke)4991*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke) {
4992*795d594fSAndroid Build Coastguard Worker switch (load_kind) {
4993*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kBootImageLinkTimePcRelative: {
4994*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
4995*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative method patch.
4996*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label =
4997*795d594fSAndroid Build Coastguard Worker NewBootImageMethodPatch(invoke->GetResolvedMethodReference());
4998*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
4999*795d594fSAndroid Build Coastguard Worker // Add ADD with its PC-relative method patch.
5000*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label =
5001*795d594fSAndroid Build Coastguard Worker NewBootImageMethodPatch(invoke->GetResolvedMethodReference(), adrp_label);
5002*795d594fSAndroid Build Coastguard Worker EmitAddPlaceholder(add_label, XRegisterFrom(temp), XRegisterFrom(temp));
5003*795d594fSAndroid Build Coastguard Worker break;
5004*795d594fSAndroid Build Coastguard Worker }
5005*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kBootImageRelRo: {
5006*795d594fSAndroid Build Coastguard Worker // Note: Boot image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
5007*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = GetBootImageOffset(invoke);
5008*795d594fSAndroid Build Coastguard Worker LoadBootImageRelRoEntry(WRegisterFrom(temp), boot_image_offset);
5009*795d594fSAndroid Build Coastguard Worker break;
5010*795d594fSAndroid Build Coastguard Worker }
5011*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kAppImageRelRo: {
5012*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsAppImage());
5013*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative method patch.
5014*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label =
5015*795d594fSAndroid Build Coastguard Worker NewAppImageMethodPatch(invoke->GetResolvedMethodReference());
5016*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
5017*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative method patch.
5018*795d594fSAndroid Build Coastguard Worker // Note: App image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
5019*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label =
5020*795d594fSAndroid Build Coastguard Worker NewAppImageMethodPatch(invoke->GetResolvedMethodReference(), adrp_label);
5021*795d594fSAndroid Build Coastguard Worker EmitLdrOffsetPlaceholder(ldr_label, WRegisterFrom(temp), XRegisterFrom(temp));
5022*795d594fSAndroid Build Coastguard Worker break;
5023*795d594fSAndroid Build Coastguard Worker }
5024*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kBssEntry: {
5025*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative .bss entry patch.
5026*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = NewMethodBssEntryPatch(invoke->GetMethodReference());
5027*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
5028*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative .bss entry patch.
5029*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label =
5030*795d594fSAndroid Build Coastguard Worker NewMethodBssEntryPatch(invoke->GetMethodReference(), adrp_label);
5031*795d594fSAndroid Build Coastguard Worker // All aligned loads are implicitly atomic consume operations on ARM64.
5032*795d594fSAndroid Build Coastguard Worker EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp));
5033*795d594fSAndroid Build Coastguard Worker break;
5034*795d594fSAndroid Build Coastguard Worker }
5035*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kJitDirectAddress: {
5036*795d594fSAndroid Build Coastguard Worker // Load method address from literal pool.
5037*795d594fSAndroid Build Coastguard Worker __ Ldr(XRegisterFrom(temp),
5038*795d594fSAndroid Build Coastguard Worker jit_patches_.DeduplicateUint64Literal(
5039*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uint64_t>(invoke->GetResolvedMethod())));
5040*795d594fSAndroid Build Coastguard Worker break;
5041*795d594fSAndroid Build Coastguard Worker }
5042*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kRuntimeCall: {
5043*795d594fSAndroid Build Coastguard Worker // Test situation, don't do anything.
5044*795d594fSAndroid Build Coastguard Worker break;
5045*795d594fSAndroid Build Coastguard Worker }
5046*795d594fSAndroid Build Coastguard Worker default: {
5047*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Load kind should have already been handled " << load_kind;
5048*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
5049*795d594fSAndroid Build Coastguard Worker }
5050*795d594fSAndroid Build Coastguard Worker }
5051*795d594fSAndroid Build Coastguard Worker }
5052*795d594fSAndroid Build Coastguard Worker
GenerateStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Location temp,SlowPathCode * slow_path)5053*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateStaticOrDirectCall(
5054*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
5055*795d594fSAndroid Build Coastguard Worker // Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
5056*795d594fSAndroid Build Coastguard Worker Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
5057*795d594fSAndroid Build Coastguard Worker switch (invoke->GetMethodLoadKind()) {
5058*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kStringInit: {
5059*795d594fSAndroid Build Coastguard Worker uint32_t offset =
5060*795d594fSAndroid Build Coastguard Worker GetThreadOffset<kArm64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
5061*795d594fSAndroid Build Coastguard Worker // temp = thread->string_init_entrypoint
5062*795d594fSAndroid Build Coastguard Worker __ Ldr(XRegisterFrom(temp), MemOperand(tr, offset));
5063*795d594fSAndroid Build Coastguard Worker break;
5064*795d594fSAndroid Build Coastguard Worker }
5065*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kRecursive:
5066*795d594fSAndroid Build Coastguard Worker callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodIndex());
5067*795d594fSAndroid Build Coastguard Worker break;
5068*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kRuntimeCall:
5069*795d594fSAndroid Build Coastguard Worker GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
5070*795d594fSAndroid Build Coastguard Worker return; // No code pointer retrieval; the runtime performs the call directly.
5071*795d594fSAndroid Build Coastguard Worker case MethodLoadKind::kBootImageLinkTimePcRelative:
5072*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5073*795d594fSAndroid Build Coastguard Worker if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
5074*795d594fSAndroid Build Coastguard Worker // Do not materialize the method pointer, load directly the entrypoint.
5075*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative JNI entrypoint patch.
5076*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label =
5077*795d594fSAndroid Build Coastguard Worker NewBootImageJniEntrypointPatch(invoke->GetResolvedMethodReference());
5078*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, lr);
5079*795d594fSAndroid Build Coastguard Worker // Add the LDR with its PC-relative method patch.
5080*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label =
5081*795d594fSAndroid Build Coastguard Worker NewBootImageJniEntrypointPatch(invoke->GetResolvedMethodReference(), adrp_label);
5082*795d594fSAndroid Build Coastguard Worker EmitLdrOffsetPlaceholder(add_label, lr, lr);
5083*795d594fSAndroid Build Coastguard Worker break;
5084*795d594fSAndroid Build Coastguard Worker }
5085*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
5086*795d594fSAndroid Build Coastguard Worker default:
5087*795d594fSAndroid Build Coastguard Worker LoadMethod(invoke->GetMethodLoadKind(), temp, invoke);
5088*795d594fSAndroid Build Coastguard Worker break;
5089*795d594fSAndroid Build Coastguard Worker }
5090*795d594fSAndroid Build Coastguard Worker
5091*795d594fSAndroid Build Coastguard Worker auto call_lr = [&]() {
5092*795d594fSAndroid Build Coastguard Worker // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
5093*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(),
5094*795d594fSAndroid Build Coastguard Worker kInstructionSize,
5095*795d594fSAndroid Build Coastguard Worker CodeBufferCheckScope::kExactSize);
5096*795d594fSAndroid Build Coastguard Worker // lr()
5097*795d594fSAndroid Build Coastguard Worker __ blr(lr);
5098*795d594fSAndroid Build Coastguard Worker RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5099*795d594fSAndroid Build Coastguard Worker };
5100*795d594fSAndroid Build Coastguard Worker switch (invoke->GetCodePtrLocation()) {
5101*795d594fSAndroid Build Coastguard Worker case CodePtrLocation::kCallSelf:
5102*795d594fSAndroid Build Coastguard Worker {
5103*795d594fSAndroid Build Coastguard Worker DCHECK(!GetGraph()->HasShouldDeoptimizeFlag());
5104*795d594fSAndroid Build Coastguard Worker // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
5105*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(),
5106*795d594fSAndroid Build Coastguard Worker kInstructionSize,
5107*795d594fSAndroid Build Coastguard Worker CodeBufferCheckScope::kExactSize);
5108*795d594fSAndroid Build Coastguard Worker __ bl(&frame_entry_label_);
5109*795d594fSAndroid Build Coastguard Worker RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5110*795d594fSAndroid Build Coastguard Worker }
5111*795d594fSAndroid Build Coastguard Worker break;
5112*795d594fSAndroid Build Coastguard Worker case CodePtrLocation::kCallCriticalNative: {
5113*795d594fSAndroid Build Coastguard Worker size_t out_frame_size =
5114*795d594fSAndroid Build Coastguard Worker PrepareCriticalNativeCall<CriticalNativeCallingConventionVisitorARM64,
5115*795d594fSAndroid Build Coastguard Worker kAapcs64StackAlignment,
5116*795d594fSAndroid Build Coastguard Worker GetCriticalNativeDirectCallFrameSize>(invoke);
5117*795d594fSAndroid Build Coastguard Worker if (invoke->GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative) {
5118*795d594fSAndroid Build Coastguard Worker call_lr();
5119*795d594fSAndroid Build Coastguard Worker } else {
5120*795d594fSAndroid Build Coastguard Worker // LR = callee_method->ptr_sized_fields_.data_; // EntryPointFromJni
5121*795d594fSAndroid Build Coastguard Worker MemberOffset offset = ArtMethod::EntryPointFromJniOffset(kArm64PointerSize);
5122*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(XRegisterFrom(callee_method), offset.Int32Value()));
5123*795d594fSAndroid Build Coastguard Worker // lr()
5124*795d594fSAndroid Build Coastguard Worker call_lr();
5125*795d594fSAndroid Build Coastguard Worker }
5126*795d594fSAndroid Build Coastguard Worker // Zero-/sign-extend the result when needed due to native and managed ABI mismatch.
5127*795d594fSAndroid Build Coastguard Worker switch (invoke->GetType()) {
5128*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
5129*795d594fSAndroid Build Coastguard Worker __ Ubfx(w0, w0, 0, 8);
5130*795d594fSAndroid Build Coastguard Worker break;
5131*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
5132*795d594fSAndroid Build Coastguard Worker __ Sbfx(w0, w0, 0, 8);
5133*795d594fSAndroid Build Coastguard Worker break;
5134*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
5135*795d594fSAndroid Build Coastguard Worker __ Ubfx(w0, w0, 0, 16);
5136*795d594fSAndroid Build Coastguard Worker break;
5137*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
5138*795d594fSAndroid Build Coastguard Worker __ Sbfx(w0, w0, 0, 16);
5139*795d594fSAndroid Build Coastguard Worker break;
5140*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
5141*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
5142*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
5143*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
5144*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
5145*795d594fSAndroid Build Coastguard Worker break;
5146*795d594fSAndroid Build Coastguard Worker default:
5147*795d594fSAndroid Build Coastguard Worker DCHECK(false) << invoke->GetType();
5148*795d594fSAndroid Build Coastguard Worker break;
5149*795d594fSAndroid Build Coastguard Worker }
5150*795d594fSAndroid Build Coastguard Worker if (out_frame_size != 0u) {
5151*795d594fSAndroid Build Coastguard Worker DecreaseFrame(out_frame_size);
5152*795d594fSAndroid Build Coastguard Worker }
5153*795d594fSAndroid Build Coastguard Worker break;
5154*795d594fSAndroid Build Coastguard Worker }
5155*795d594fSAndroid Build Coastguard Worker case CodePtrLocation::kCallArtMethod: {
5156*795d594fSAndroid Build Coastguard Worker // LR = callee_method->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
5157*795d594fSAndroid Build Coastguard Worker MemberOffset offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize);
5158*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(XRegisterFrom(callee_method), offset.Int32Value()));
5159*795d594fSAndroid Build Coastguard Worker // lr()
5160*795d594fSAndroid Build Coastguard Worker call_lr();
5161*795d594fSAndroid Build Coastguard Worker break;
5162*795d594fSAndroid Build Coastguard Worker }
5163*795d594fSAndroid Build Coastguard Worker }
5164*795d594fSAndroid Build Coastguard Worker
5165*795d594fSAndroid Build Coastguard Worker DCHECK(!IsLeafMethod());
5166*795d594fSAndroid Build Coastguard Worker }
5167*795d594fSAndroid Build Coastguard Worker
GenerateVirtualCall(HInvokeVirtual * invoke,Location temp_in,SlowPathCode * slow_path)5168*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateVirtualCall(
5169*795d594fSAndroid Build Coastguard Worker HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
5170*795d594fSAndroid Build Coastguard Worker // Use the calling convention instead of the location of the receiver, as
5171*795d594fSAndroid Build Coastguard Worker // intrinsics may have put the receiver in a different register. In the intrinsics
5172*795d594fSAndroid Build Coastguard Worker // slow path, the arguments have been moved to the right place, so here we are
5173*795d594fSAndroid Build Coastguard Worker // guaranteed that the receiver is the first register of the calling convention.
5174*795d594fSAndroid Build Coastguard Worker InvokeDexCallingConvention calling_convention;
5175*795d594fSAndroid Build Coastguard Worker Register receiver = calling_convention.GetRegisterAt(0);
5176*795d594fSAndroid Build Coastguard Worker Register temp = XRegisterFrom(temp_in);
5177*795d594fSAndroid Build Coastguard Worker size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5178*795d594fSAndroid Build Coastguard Worker invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
5179*795d594fSAndroid Build Coastguard Worker Offset class_offset = mirror::Object::ClassOffset();
5180*795d594fSAndroid Build Coastguard Worker Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize);
5181*795d594fSAndroid Build Coastguard Worker
5182*795d594fSAndroid Build Coastguard Worker DCHECK(receiver.IsRegister());
5183*795d594fSAndroid Build Coastguard Worker
5184*795d594fSAndroid Build Coastguard Worker {
5185*795d594fSAndroid Build Coastguard Worker // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
5186*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
5187*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = receiver->klass_
5188*795d594fSAndroid Build Coastguard Worker __ Ldr(temp.W(), HeapOperandFrom(LocationFrom(receiver), class_offset));
5189*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(invoke);
5190*795d594fSAndroid Build Coastguard Worker }
5191*795d594fSAndroid Build Coastguard Worker // Instead of simply (possibly) unpoisoning `temp` here, we should
5192*795d594fSAndroid Build Coastguard Worker // emit a read barrier for the previous class reference load.
5193*795d594fSAndroid Build Coastguard Worker // However this is not required in practice, as this is an
5194*795d594fSAndroid Build Coastguard Worker // intermediate/temporary reference and because the current
5195*795d594fSAndroid Build Coastguard Worker // concurrent copying collector keeps the from-space memory
5196*795d594fSAndroid Build Coastguard Worker // intact/accessible until the end of the marking phase (the
5197*795d594fSAndroid Build Coastguard Worker // concurrent copying collector may not in the future).
5198*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
5199*795d594fSAndroid Build Coastguard Worker
5200*795d594fSAndroid Build Coastguard Worker // If we're compiling baseline, update the inline cache.
5201*795d594fSAndroid Build Coastguard Worker MaybeGenerateInlineCacheCheck(invoke, temp);
5202*795d594fSAndroid Build Coastguard Worker
5203*795d594fSAndroid Build Coastguard Worker // temp = temp->GetMethodAt(method_offset);
5204*795d594fSAndroid Build Coastguard Worker __ Ldr(temp, MemOperand(temp, method_offset));
5205*795d594fSAndroid Build Coastguard Worker // lr = temp->GetEntryPoint();
5206*795d594fSAndroid Build Coastguard Worker __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
5207*795d594fSAndroid Build Coastguard Worker {
5208*795d594fSAndroid Build Coastguard Worker // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
5209*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, CodeBufferCheckScope::kExactSize);
5210*795d594fSAndroid Build Coastguard Worker // lr();
5211*795d594fSAndroid Build Coastguard Worker __ blr(lr);
5212*795d594fSAndroid Build Coastguard Worker RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5213*795d594fSAndroid Build Coastguard Worker }
5214*795d594fSAndroid Build Coastguard Worker }
5215*795d594fSAndroid Build Coastguard Worker
MoveFromReturnRegister(Location trg,DataType::Type type)5216*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MoveFromReturnRegister(Location trg, DataType::Type type) {
5217*795d594fSAndroid Build Coastguard Worker if (!trg.IsValid()) {
5218*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kVoid);
5219*795d594fSAndroid Build Coastguard Worker return;
5220*795d594fSAndroid Build Coastguard Worker }
5221*795d594fSAndroid Build Coastguard Worker
5222*795d594fSAndroid Build Coastguard Worker DCHECK_NE(type, DataType::Type::kVoid);
5223*795d594fSAndroid Build Coastguard Worker
5224*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
5225*795d594fSAndroid Build Coastguard Worker Register trg_reg = RegisterFrom(trg, type);
5226*795d594fSAndroid Build Coastguard Worker Register res_reg = RegisterFrom(ARM64ReturnLocation(type), type);
5227*795d594fSAndroid Build Coastguard Worker __ Mov(trg_reg, res_reg, kDiscardForSameWReg);
5228*795d594fSAndroid Build Coastguard Worker } else {
5229*795d594fSAndroid Build Coastguard Worker VRegister trg_reg = FPRegisterFrom(trg, type);
5230*795d594fSAndroid Build Coastguard Worker VRegister res_reg = FPRegisterFrom(ARM64ReturnLocation(type), type);
5231*795d594fSAndroid Build Coastguard Worker __ Fmov(trg_reg, res_reg);
5232*795d594fSAndroid Build Coastguard Worker }
5233*795d594fSAndroid Build Coastguard Worker }
5234*795d594fSAndroid Build Coastguard Worker
VisitInvokePolymorphic(HInvokePolymorphic * invoke)5235*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
5236*795d594fSAndroid Build Coastguard Worker IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetAllocator(), codegen_);
5237*795d594fSAndroid Build Coastguard Worker if (intrinsic.TryDispatch(invoke)) {
5238*795d594fSAndroid Build Coastguard Worker return;
5239*795d594fSAndroid Build Coastguard Worker }
5240*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
5241*795d594fSAndroid Build Coastguard Worker }
5242*795d594fSAndroid Build Coastguard Worker
VisitInvokePolymorphic(HInvokePolymorphic * invoke)5243*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
5244*795d594fSAndroid Build Coastguard Worker if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5245*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5246*795d594fSAndroid Build Coastguard Worker return;
5247*795d594fSAndroid Build Coastguard Worker }
5248*795d594fSAndroid Build Coastguard Worker codegen_->GenerateInvokePolymorphicCall(invoke);
5249*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5250*795d594fSAndroid Build Coastguard Worker }
5251*795d594fSAndroid Build Coastguard Worker
VisitInvokeCustom(HInvokeCustom * invoke)5252*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitInvokeCustom(HInvokeCustom* invoke) {
5253*795d594fSAndroid Build Coastguard Worker HandleInvoke(invoke);
5254*795d594fSAndroid Build Coastguard Worker }
5255*795d594fSAndroid Build Coastguard Worker
VisitInvokeCustom(HInvokeCustom * invoke)5256*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokeCustom(HInvokeCustom* invoke) {
5257*795d594fSAndroid Build Coastguard Worker codegen_->GenerateInvokeCustomCall(invoke);
5258*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5259*795d594fSAndroid Build Coastguard Worker }
5260*795d594fSAndroid Build Coastguard Worker
NewBootImageIntrinsicPatch(uint32_t intrinsic_data,vixl::aarch64::Label * adrp_label)5261*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageIntrinsicPatch(
5262*795d594fSAndroid Build Coastguard Worker uint32_t intrinsic_data,
5263*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5264*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5265*795d594fSAndroid Build Coastguard Worker /* dex_file= */ nullptr, intrinsic_data, adrp_label, &boot_image_other_patches_);
5266*795d594fSAndroid Build Coastguard Worker }
5267*795d594fSAndroid Build Coastguard Worker
NewBootImageRelRoPatch(uint32_t boot_image_offset,vixl::aarch64::Label * adrp_label)5268*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageRelRoPatch(
5269*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset,
5270*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5271*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5272*795d594fSAndroid Build Coastguard Worker /* dex_file= */ nullptr, boot_image_offset, adrp_label, &boot_image_other_patches_);
5273*795d594fSAndroid Build Coastguard Worker }
5274*795d594fSAndroid Build Coastguard Worker
NewBootImageMethodPatch(MethodReference target_method,vixl::aarch64::Label * adrp_label)5275*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageMethodPatch(
5276*795d594fSAndroid Build Coastguard Worker MethodReference target_method,
5277*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5278*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5279*795d594fSAndroid Build Coastguard Worker target_method.dex_file, target_method.index, adrp_label, &boot_image_method_patches_);
5280*795d594fSAndroid Build Coastguard Worker }
5281*795d594fSAndroid Build Coastguard Worker
NewAppImageMethodPatch(MethodReference target_method,vixl::aarch64::Label * adrp_label)5282*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewAppImageMethodPatch(
5283*795d594fSAndroid Build Coastguard Worker MethodReference target_method,
5284*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5285*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5286*795d594fSAndroid Build Coastguard Worker target_method.dex_file, target_method.index, adrp_label, &app_image_method_patches_);
5287*795d594fSAndroid Build Coastguard Worker }
5288*795d594fSAndroid Build Coastguard Worker
NewMethodBssEntryPatch(MethodReference target_method,vixl::aarch64::Label * adrp_label)5289*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewMethodBssEntryPatch(
5290*795d594fSAndroid Build Coastguard Worker MethodReference target_method,
5291*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5292*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5293*795d594fSAndroid Build Coastguard Worker target_method.dex_file, target_method.index, adrp_label, &method_bss_entry_patches_);
5294*795d594fSAndroid Build Coastguard Worker }
5295*795d594fSAndroid Build Coastguard Worker
NewBootImageTypePatch(const DexFile & dex_file,dex::TypeIndex type_index,vixl::aarch64::Label * adrp_label)5296*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageTypePatch(
5297*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
5298*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index,
5299*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5300*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(&dex_file, type_index.index_, adrp_label, &boot_image_type_patches_);
5301*795d594fSAndroid Build Coastguard Worker }
5302*795d594fSAndroid Build Coastguard Worker
NewAppImageTypePatch(const DexFile & dex_file,dex::TypeIndex type_index,vixl::aarch64::Label * adrp_label)5303*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewAppImageTypePatch(
5304*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
5305*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index,
5306*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5307*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(&dex_file, type_index.index_, adrp_label, &app_image_type_patches_);
5308*795d594fSAndroid Build Coastguard Worker }
5309*795d594fSAndroid Build Coastguard Worker
NewBssEntryTypePatch(HLoadClass * load_class,vixl::aarch64::Label * adrp_label)5310*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBssEntryTypePatch(
5311*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class,
5312*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5313*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = load_class->GetDexFile();
5314*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index = load_class->GetTypeIndex();
5315*795d594fSAndroid Build Coastguard Worker ArenaDeque<PcRelativePatchInfo>* patches = nullptr;
5316*795d594fSAndroid Build Coastguard Worker switch (load_class->GetLoadKind()) {
5317*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntry:
5318*795d594fSAndroid Build Coastguard Worker patches = &type_bss_entry_patches_;
5319*795d594fSAndroid Build Coastguard Worker break;
5320*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPublic:
5321*795d594fSAndroid Build Coastguard Worker patches = &public_type_bss_entry_patches_;
5322*795d594fSAndroid Build Coastguard Worker break;
5323*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPackage:
5324*795d594fSAndroid Build Coastguard Worker patches = &package_type_bss_entry_patches_;
5325*795d594fSAndroid Build Coastguard Worker break;
5326*795d594fSAndroid Build Coastguard Worker default:
5327*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected load kind: " << load_class->GetLoadKind();
5328*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
5329*795d594fSAndroid Build Coastguard Worker }
5330*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(&dex_file, type_index.index_, adrp_label, patches);
5331*795d594fSAndroid Build Coastguard Worker }
5332*795d594fSAndroid Build Coastguard Worker
NewBootImageStringPatch(const DexFile & dex_file,dex::StringIndex string_index,vixl::aarch64::Label * adrp_label)5333*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageStringPatch(
5334*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
5335*795d594fSAndroid Build Coastguard Worker dex::StringIndex string_index,
5336*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5337*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5338*795d594fSAndroid Build Coastguard Worker &dex_file, string_index.index_, adrp_label, &boot_image_string_patches_);
5339*795d594fSAndroid Build Coastguard Worker }
5340*795d594fSAndroid Build Coastguard Worker
NewStringBssEntryPatch(const DexFile & dex_file,dex::StringIndex string_index,vixl::aarch64::Label * adrp_label)5341*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewStringBssEntryPatch(
5342*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
5343*795d594fSAndroid Build Coastguard Worker dex::StringIndex string_index,
5344*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5345*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(&dex_file, string_index.index_, adrp_label, &string_bss_entry_patches_);
5346*795d594fSAndroid Build Coastguard Worker }
5347*795d594fSAndroid Build Coastguard Worker
NewMethodTypeBssEntryPatch(HLoadMethodType * load_method_type,vixl::aarch64::Label * adrp_label)5348*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewMethodTypeBssEntryPatch(
5349*795d594fSAndroid Build Coastguard Worker HLoadMethodType* load_method_type,
5350*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5351*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(&load_method_type->GetDexFile(),
5352*795d594fSAndroid Build Coastguard Worker load_method_type->GetProtoIndex().index_,
5353*795d594fSAndroid Build Coastguard Worker adrp_label,
5354*795d594fSAndroid Build Coastguard Worker &method_type_bss_entry_patches_);
5355*795d594fSAndroid Build Coastguard Worker }
5356*795d594fSAndroid Build Coastguard Worker
NewBootImageJniEntrypointPatch(MethodReference target_method,vixl::aarch64::Label * adrp_label)5357*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageJniEntrypointPatch(
5358*795d594fSAndroid Build Coastguard Worker MethodReference target_method,
5359*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label) {
5360*795d594fSAndroid Build Coastguard Worker return NewPcRelativePatch(
5361*795d594fSAndroid Build Coastguard Worker target_method.dex_file, target_method.index, adrp_label, &boot_image_jni_entrypoint_patches_);
5362*795d594fSAndroid Build Coastguard Worker }
5363*795d594fSAndroid Build Coastguard Worker
EmitEntrypointThunkCall(ThreadOffset64 entrypoint_offset)5364*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitEntrypointThunkCall(ThreadOffset64 entrypoint_offset) {
5365*795d594fSAndroid Build Coastguard Worker DCHECK(!__ AllowMacroInstructions()); // In ExactAssemblyScope.
5366*795d594fSAndroid Build Coastguard Worker DCHECK(!GetCompilerOptions().IsJitCompiler());
5367*795d594fSAndroid Build Coastguard Worker call_entrypoint_patches_.emplace_back(/*dex_file*/ nullptr, entrypoint_offset.Uint32Value());
5368*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* bl_label = &call_entrypoint_patches_.back().label;
5369*795d594fSAndroid Build Coastguard Worker __ bind(bl_label);
5370*795d594fSAndroid Build Coastguard Worker __ bl(static_cast<int64_t>(0)); // Placeholder, patched at link-time.
5371*795d594fSAndroid Build Coastguard Worker }
5372*795d594fSAndroid Build Coastguard Worker
EmitBakerReadBarrierCbnz(uint32_t custom_data)5373*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitBakerReadBarrierCbnz(uint32_t custom_data) {
5374*795d594fSAndroid Build Coastguard Worker DCHECK(!__ AllowMacroInstructions()); // In ExactAssemblyScope.
5375*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsJitCompiler()) {
5376*795d594fSAndroid Build Coastguard Worker auto it = jit_baker_read_barrier_slow_paths_.FindOrAdd(custom_data);
5377*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* slow_path_entry = &it->second.label;
5378*795d594fSAndroid Build Coastguard Worker __ cbnz(mr, slow_path_entry);
5379*795d594fSAndroid Build Coastguard Worker } else {
5380*795d594fSAndroid Build Coastguard Worker baker_read_barrier_patches_.emplace_back(custom_data);
5381*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* cbnz_label = &baker_read_barrier_patches_.back().label;
5382*795d594fSAndroid Build Coastguard Worker __ bind(cbnz_label);
5383*795d594fSAndroid Build Coastguard Worker __ cbnz(mr, static_cast<int64_t>(0)); // Placeholder, patched at link-time.
5384*795d594fSAndroid Build Coastguard Worker }
5385*795d594fSAndroid Build Coastguard Worker }
5386*795d594fSAndroid Build Coastguard Worker
NewPcRelativePatch(const DexFile * dex_file,uint32_t offset_or_index,vixl::aarch64::Label * adrp_label,ArenaDeque<PcRelativePatchInfo> * patches)5387*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativePatch(
5388*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
5389*795d594fSAndroid Build Coastguard Worker uint32_t offset_or_index,
5390*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label,
5391*795d594fSAndroid Build Coastguard Worker ArenaDeque<PcRelativePatchInfo>* patches) {
5392*795d594fSAndroid Build Coastguard Worker // Add a patch entry and return the label.
5393*795d594fSAndroid Build Coastguard Worker patches->emplace_back(dex_file, offset_or_index);
5394*795d594fSAndroid Build Coastguard Worker PcRelativePatchInfo* info = &patches->back();
5395*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* label = &info->label;
5396*795d594fSAndroid Build Coastguard Worker // If adrp_label is null, this is the ADRP patch and needs to point to its own label.
5397*795d594fSAndroid Build Coastguard Worker info->pc_insn_label = (adrp_label != nullptr) ? adrp_label : label;
5398*795d594fSAndroid Build Coastguard Worker return label;
5399*795d594fSAndroid Build Coastguard Worker }
5400*795d594fSAndroid Build Coastguard Worker
EmitJitRootPatches(uint8_t * code,const uint8_t * roots_data)5401*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
5402*795d594fSAndroid Build Coastguard Worker jit_patches_.EmitJitRootPatches(code, roots_data, *GetCodeGenerationData());
5403*795d594fSAndroid Build Coastguard Worker }
5404*795d594fSAndroid Build Coastguard Worker
EmitAdrpPlaceholder(vixl::aarch64::Label * fixup_label,vixl::aarch64::Register reg)5405*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label,
5406*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register reg) {
5407*795d594fSAndroid Build Coastguard Worker DCHECK(reg.IsX());
5408*795d594fSAndroid Build Coastguard Worker SingleEmissionCheckScope guard(GetVIXLAssembler());
5409*795d594fSAndroid Build Coastguard Worker __ Bind(fixup_label);
5410*795d594fSAndroid Build Coastguard Worker __ adrp(reg, /* offset placeholder */ static_cast<int64_t>(0));
5411*795d594fSAndroid Build Coastguard Worker }
5412*795d594fSAndroid Build Coastguard Worker
EmitAddPlaceholder(vixl::aarch64::Label * fixup_label,vixl::aarch64::Register out,vixl::aarch64::Register base)5413*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
5414*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register out,
5415*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register base) {
5416*795d594fSAndroid Build Coastguard Worker DCHECK(out.IsX());
5417*795d594fSAndroid Build Coastguard Worker DCHECK(base.IsX());
5418*795d594fSAndroid Build Coastguard Worker SingleEmissionCheckScope guard(GetVIXLAssembler());
5419*795d594fSAndroid Build Coastguard Worker __ Bind(fixup_label);
5420*795d594fSAndroid Build Coastguard Worker __ add(out, base, Operand(/* offset placeholder */ 0));
5421*795d594fSAndroid Build Coastguard Worker }
5422*795d594fSAndroid Build Coastguard Worker
EmitLdrOffsetPlaceholder(vixl::aarch64::Label * fixup_label,vixl::aarch64::Register out,vixl::aarch64::Register base)5423*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitLdrOffsetPlaceholder(vixl::aarch64::Label* fixup_label,
5424*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register out,
5425*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register base) {
5426*795d594fSAndroid Build Coastguard Worker DCHECK(base.IsX());
5427*795d594fSAndroid Build Coastguard Worker SingleEmissionCheckScope guard(GetVIXLAssembler());
5428*795d594fSAndroid Build Coastguard Worker __ Bind(fixup_label);
5429*795d594fSAndroid Build Coastguard Worker __ ldr(out, MemOperand(base, /* offset placeholder */ 0));
5430*795d594fSAndroid Build Coastguard Worker }
5431*795d594fSAndroid Build Coastguard Worker
LoadBootImageRelRoEntry(vixl::aarch64::Register reg,uint32_t boot_image_offset)5432*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadBootImageRelRoEntry(vixl::aarch64::Register reg,
5433*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset) {
5434*795d594fSAndroid Build Coastguard Worker DCHECK(reg.IsW());
5435*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative boot image .data.img.rel.ro patch.
5436*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = NewBootImageRelRoPatch(boot_image_offset);
5437*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, reg.X());
5438*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative boot image .data.img.rel.ro patch.
5439*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label = NewBootImageRelRoPatch(boot_image_offset, adrp_label);
5440*795d594fSAndroid Build Coastguard Worker EmitLdrOffsetPlaceholder(ldr_label, reg.W(), reg.X());
5441*795d594fSAndroid Build Coastguard Worker }
5442*795d594fSAndroid Build Coastguard Worker
LoadBootImageAddress(vixl::aarch64::Register reg,uint32_t boot_image_reference)5443*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadBootImageAddress(vixl::aarch64::Register reg,
5444*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_reference) {
5445*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage()) {
5446*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative type patch.
5447*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = NewBootImageIntrinsicPatch(boot_image_reference);
5448*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, reg.X());
5449*795d594fSAndroid Build Coastguard Worker // Add ADD with its PC-relative type patch.
5450*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label = NewBootImageIntrinsicPatch(boot_image_reference, adrp_label);
5451*795d594fSAndroid Build Coastguard Worker EmitAddPlaceholder(add_label, reg.X(), reg.X());
5452*795d594fSAndroid Build Coastguard Worker } else if (GetCompilerOptions().GetCompilePic()) {
5453*795d594fSAndroid Build Coastguard Worker LoadBootImageRelRoEntry(reg, boot_image_reference);
5454*795d594fSAndroid Build Coastguard Worker } else {
5455*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsJitCompiler());
5456*795d594fSAndroid Build Coastguard Worker gc::Heap* heap = Runtime::Current()->GetHeap();
5457*795d594fSAndroid Build Coastguard Worker DCHECK(!heap->GetBootImageSpaces().empty());
5458*795d594fSAndroid Build Coastguard Worker const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_reference;
5459*795d594fSAndroid Build Coastguard Worker __ Ldr(reg.W(), DeduplicateBootImageAddressLiteral(reinterpret_cast<uintptr_t>(address)));
5460*795d594fSAndroid Build Coastguard Worker }
5461*795d594fSAndroid Build Coastguard Worker }
5462*795d594fSAndroid Build Coastguard Worker
LoadTypeForBootImageIntrinsic(vixl::aarch64::Register reg,TypeReference target_type)5463*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadTypeForBootImageIntrinsic(vixl::aarch64::Register reg,
5464*795d594fSAndroid Build Coastguard Worker TypeReference target_type) {
5465*795d594fSAndroid Build Coastguard Worker // Load the type the same way as for HLoadClass::LoadKind::kBootImageLinkTimePcRelative.
5466*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5467*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative type patch.
5468*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label =
5469*795d594fSAndroid Build Coastguard Worker NewBootImageTypePatch(*target_type.dex_file, target_type.TypeIndex());
5470*795d594fSAndroid Build Coastguard Worker EmitAdrpPlaceholder(adrp_label, reg.X());
5471*795d594fSAndroid Build Coastguard Worker // Add ADD with its PC-relative type patch.
5472*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label =
5473*795d594fSAndroid Build Coastguard Worker NewBootImageTypePatch(*target_type.dex_file, target_type.TypeIndex(), adrp_label);
5474*795d594fSAndroid Build Coastguard Worker EmitAddPlaceholder(add_label, reg.X(), reg.X());
5475*795d594fSAndroid Build Coastguard Worker }
5476*795d594fSAndroid Build Coastguard Worker
LoadIntrinsicDeclaringClass(vixl::aarch64::Register reg,HInvoke * invoke)5477*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadIntrinsicDeclaringClass(vixl::aarch64::Register reg, HInvoke* invoke) {
5478*795d594fSAndroid Build Coastguard Worker DCHECK_NE(invoke->GetIntrinsic(), Intrinsics::kNone);
5479*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage()) {
5480*795d594fSAndroid Build Coastguard Worker MethodReference target_method = invoke->GetResolvedMethodReference();
5481*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_idx = target_method.dex_file->GetMethodId(target_method.index).class_idx_;
5482*795d594fSAndroid Build Coastguard Worker LoadTypeForBootImageIntrinsic(reg, TypeReference(target_method.dex_file, type_idx));
5483*795d594fSAndroid Build Coastguard Worker } else {
5484*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = GetBootImageOffsetOfIntrinsicDeclaringClass(invoke);
5485*795d594fSAndroid Build Coastguard Worker LoadBootImageAddress(reg, boot_image_offset);
5486*795d594fSAndroid Build Coastguard Worker }
5487*795d594fSAndroid Build Coastguard Worker }
5488*795d594fSAndroid Build Coastguard Worker
LoadClassRootForIntrinsic(vixl::aarch64::Register reg,ClassRoot class_root)5489*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::LoadClassRootForIntrinsic(vixl::aarch64::Register reg,
5490*795d594fSAndroid Build Coastguard Worker ClassRoot class_root) {
5491*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage()) {
5492*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
5493*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = GetClassRoot(class_root);
5494*795d594fSAndroid Build Coastguard Worker TypeReference target_type(&klass->GetDexFile(), klass->GetDexTypeIndex());
5495*795d594fSAndroid Build Coastguard Worker LoadTypeForBootImageIntrinsic(reg, target_type);
5496*795d594fSAndroid Build Coastguard Worker } else {
5497*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = GetBootImageOffset(class_root);
5498*795d594fSAndroid Build Coastguard Worker LoadBootImageAddress(reg, boot_image_offset);
5499*795d594fSAndroid Build Coastguard Worker }
5500*795d594fSAndroid Build Coastguard Worker }
5501*795d594fSAndroid Build Coastguard Worker
5502*795d594fSAndroid Build Coastguard Worker template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo> & infos,ArenaVector<linker::LinkerPatch> * linker_patches)5503*795d594fSAndroid Build Coastguard Worker inline void CodeGeneratorARM64::EmitPcRelativeLinkerPatches(
5504*795d594fSAndroid Build Coastguard Worker const ArenaDeque<PcRelativePatchInfo>& infos,
5505*795d594fSAndroid Build Coastguard Worker ArenaVector<linker::LinkerPatch>* linker_patches) {
5506*795d594fSAndroid Build Coastguard Worker for (const PcRelativePatchInfo& info : infos) {
5507*795d594fSAndroid Build Coastguard Worker linker_patches->push_back(Factory(info.label.GetLocation(),
5508*795d594fSAndroid Build Coastguard Worker info.target_dex_file,
5509*795d594fSAndroid Build Coastguard Worker info.pc_insn_label->GetLocation(),
5510*795d594fSAndroid Build Coastguard Worker info.offset_or_index));
5511*795d594fSAndroid Build Coastguard Worker }
5512*795d594fSAndroid Build Coastguard Worker }
5513*795d594fSAndroid Build Coastguard Worker
5514*795d594fSAndroid Build Coastguard Worker template <linker::LinkerPatch (*Factory)(size_t, uint32_t, uint32_t)>
NoDexFileAdapter(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t boot_image_offset)5515*795d594fSAndroid Build Coastguard Worker linker::LinkerPatch NoDexFileAdapter(size_t literal_offset,
5516*795d594fSAndroid Build Coastguard Worker const DexFile* target_dex_file,
5517*795d594fSAndroid Build Coastguard Worker uint32_t pc_insn_offset,
5518*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset) {
5519*795d594fSAndroid Build Coastguard Worker DCHECK(target_dex_file == nullptr); // Unused for these patches, should be null.
5520*795d594fSAndroid Build Coastguard Worker return Factory(literal_offset, pc_insn_offset, boot_image_offset);
5521*795d594fSAndroid Build Coastguard Worker }
5522*795d594fSAndroid Build Coastguard Worker
EmitLinkerPatches(ArenaVector<linker::LinkerPatch> * linker_patches)5523*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
5524*795d594fSAndroid Build Coastguard Worker DCHECK(linker_patches->empty());
5525*795d594fSAndroid Build Coastguard Worker size_t size =
5526*795d594fSAndroid Build Coastguard Worker boot_image_method_patches_.size() +
5527*795d594fSAndroid Build Coastguard Worker app_image_method_patches_.size() +
5528*795d594fSAndroid Build Coastguard Worker method_bss_entry_patches_.size() +
5529*795d594fSAndroid Build Coastguard Worker boot_image_type_patches_.size() +
5530*795d594fSAndroid Build Coastguard Worker app_image_type_patches_.size() +
5531*795d594fSAndroid Build Coastguard Worker type_bss_entry_patches_.size() +
5532*795d594fSAndroid Build Coastguard Worker public_type_bss_entry_patches_.size() +
5533*795d594fSAndroid Build Coastguard Worker package_type_bss_entry_patches_.size() +
5534*795d594fSAndroid Build Coastguard Worker boot_image_string_patches_.size() +
5535*795d594fSAndroid Build Coastguard Worker string_bss_entry_patches_.size() +
5536*795d594fSAndroid Build Coastguard Worker method_type_bss_entry_patches_.size() +
5537*795d594fSAndroid Build Coastguard Worker boot_image_jni_entrypoint_patches_.size() +
5538*795d594fSAndroid Build Coastguard Worker boot_image_other_patches_.size() +
5539*795d594fSAndroid Build Coastguard Worker call_entrypoint_patches_.size() +
5540*795d594fSAndroid Build Coastguard Worker baker_read_barrier_patches_.size();
5541*795d594fSAndroid Build Coastguard Worker linker_patches->reserve(size);
5542*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
5543*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
5544*795d594fSAndroid Build Coastguard Worker boot_image_method_patches_, linker_patches);
5545*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
5546*795d594fSAndroid Build Coastguard Worker boot_image_type_patches_, linker_patches);
5547*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
5548*795d594fSAndroid Build Coastguard Worker boot_image_string_patches_, linker_patches);
5549*795d594fSAndroid Build Coastguard Worker } else {
5550*795d594fSAndroid Build Coastguard Worker DCHECK(boot_image_method_patches_.empty());
5551*795d594fSAndroid Build Coastguard Worker DCHECK(boot_image_type_patches_.empty());
5552*795d594fSAndroid Build Coastguard Worker DCHECK(boot_image_string_patches_.empty());
5553*795d594fSAndroid Build Coastguard Worker }
5554*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!GetCompilerOptions().IsAppImage(), app_image_method_patches_.empty());
5555*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!GetCompilerOptions().IsAppImage(), app_image_type_patches_.empty());
5556*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().IsBootImage()) {
5557*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::IntrinsicReferencePatch>>(
5558*795d594fSAndroid Build Coastguard Worker boot_image_other_patches_, linker_patches);
5559*795d594fSAndroid Build Coastguard Worker } else {
5560*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::BootImageRelRoPatch>>(
5561*795d594fSAndroid Build Coastguard Worker boot_image_other_patches_, linker_patches);
5562*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodAppImageRelRoPatch>(
5563*795d594fSAndroid Build Coastguard Worker app_image_method_patches_, linker_patches);
5564*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeAppImageRelRoPatch>(
5565*795d594fSAndroid Build Coastguard Worker app_image_type_patches_, linker_patches);
5566*795d594fSAndroid Build Coastguard Worker }
5567*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
5568*795d594fSAndroid Build Coastguard Worker method_bss_entry_patches_, linker_patches);
5569*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
5570*795d594fSAndroid Build Coastguard Worker type_bss_entry_patches_, linker_patches);
5571*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::PublicTypeBssEntryPatch>(
5572*795d594fSAndroid Build Coastguard Worker public_type_bss_entry_patches_, linker_patches);
5573*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::PackageTypeBssEntryPatch>(
5574*795d594fSAndroid Build Coastguard Worker package_type_bss_entry_patches_, linker_patches);
5575*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
5576*795d594fSAndroid Build Coastguard Worker string_bss_entry_patches_, linker_patches);
5577*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodTypeBssEntryPatch>(
5578*795d594fSAndroid Build Coastguard Worker method_type_bss_entry_patches_, linker_patches);
5579*795d594fSAndroid Build Coastguard Worker EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeJniEntrypointPatch>(
5580*795d594fSAndroid Build Coastguard Worker boot_image_jni_entrypoint_patches_, linker_patches);
5581*795d594fSAndroid Build Coastguard Worker for (const PatchInfo<vixl::aarch64::Label>& info : call_entrypoint_patches_) {
5582*795d594fSAndroid Build Coastguard Worker DCHECK(info.target_dex_file == nullptr);
5583*795d594fSAndroid Build Coastguard Worker linker_patches->push_back(linker::LinkerPatch::CallEntrypointPatch(
5584*795d594fSAndroid Build Coastguard Worker info.label.GetLocation(), info.offset_or_index));
5585*795d594fSAndroid Build Coastguard Worker }
5586*795d594fSAndroid Build Coastguard Worker for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
5587*795d594fSAndroid Build Coastguard Worker linker_patches->push_back(linker::LinkerPatch::BakerReadBarrierBranchPatch(
5588*795d594fSAndroid Build Coastguard Worker info.label.GetLocation(), info.custom_data));
5589*795d594fSAndroid Build Coastguard Worker }
5590*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(size, linker_patches->size());
5591*795d594fSAndroid Build Coastguard Worker }
5592*795d594fSAndroid Build Coastguard Worker
NeedsThunkCode(const linker::LinkerPatch & patch) const5593*795d594fSAndroid Build Coastguard Worker bool CodeGeneratorARM64::NeedsThunkCode(const linker::LinkerPatch& patch) const {
5594*795d594fSAndroid Build Coastguard Worker return patch.GetType() == linker::LinkerPatch::Type::kCallEntrypoint ||
5595*795d594fSAndroid Build Coastguard Worker patch.GetType() == linker::LinkerPatch::Type::kBakerReadBarrierBranch ||
5596*795d594fSAndroid Build Coastguard Worker patch.GetType() == linker::LinkerPatch::Type::kCallRelative;
5597*795d594fSAndroid Build Coastguard Worker }
5598*795d594fSAndroid Build Coastguard Worker
EmitThunkCode(const linker::LinkerPatch & patch,ArenaVector<uint8_t> * code,std::string * debug_name)5599*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::EmitThunkCode(const linker::LinkerPatch& patch,
5600*795d594fSAndroid Build Coastguard Worker /*out*/ ArenaVector<uint8_t>* code,
5601*795d594fSAndroid Build Coastguard Worker /*out*/ std::string* debug_name) {
5602*795d594fSAndroid Build Coastguard Worker Arm64Assembler assembler(GetGraph()->GetAllocator());
5603*795d594fSAndroid Build Coastguard Worker switch (patch.GetType()) {
5604*795d594fSAndroid Build Coastguard Worker case linker::LinkerPatch::Type::kCallRelative: {
5605*795d594fSAndroid Build Coastguard Worker // The thunk just uses the entry point in the ArtMethod. This works even for calls
5606*795d594fSAndroid Build Coastguard Worker // to the generic JNI and interpreter trampolines.
5607*795d594fSAndroid Build Coastguard Worker Offset offset(ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5608*795d594fSAndroid Build Coastguard Worker kArm64PointerSize).Int32Value());
5609*795d594fSAndroid Build Coastguard Worker assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
5610*795d594fSAndroid Build Coastguard Worker if (debug_name != nullptr && GetCompilerOptions().GenerateAnyDebugInfo()) {
5611*795d594fSAndroid Build Coastguard Worker *debug_name = "MethodCallThunk";
5612*795d594fSAndroid Build Coastguard Worker }
5613*795d594fSAndroid Build Coastguard Worker break;
5614*795d594fSAndroid Build Coastguard Worker }
5615*795d594fSAndroid Build Coastguard Worker case linker::LinkerPatch::Type::kCallEntrypoint: {
5616*795d594fSAndroid Build Coastguard Worker Offset offset(patch.EntrypointOffset());
5617*795d594fSAndroid Build Coastguard Worker assembler.JumpTo(ManagedRegister(arm64::TR), offset, ManagedRegister(arm64::IP0));
5618*795d594fSAndroid Build Coastguard Worker if (debug_name != nullptr && GetCompilerOptions().GenerateAnyDebugInfo()) {
5619*795d594fSAndroid Build Coastguard Worker *debug_name = "EntrypointCallThunk_" + std::to_string(offset.Uint32Value());
5620*795d594fSAndroid Build Coastguard Worker }
5621*795d594fSAndroid Build Coastguard Worker break;
5622*795d594fSAndroid Build Coastguard Worker }
5623*795d594fSAndroid Build Coastguard Worker case linker::LinkerPatch::Type::kBakerReadBarrierBranch: {
5624*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(patch.GetBakerCustomValue2(), 0u);
5625*795d594fSAndroid Build Coastguard Worker CompileBakerReadBarrierThunk(assembler, patch.GetBakerCustomValue1(), debug_name);
5626*795d594fSAndroid Build Coastguard Worker break;
5627*795d594fSAndroid Build Coastguard Worker }
5628*795d594fSAndroid Build Coastguard Worker default:
5629*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected patch type " << patch.GetType();
5630*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
5631*795d594fSAndroid Build Coastguard Worker }
5632*795d594fSAndroid Build Coastguard Worker
5633*795d594fSAndroid Build Coastguard Worker // Ensure we emit the literal pool if any.
5634*795d594fSAndroid Build Coastguard Worker assembler.FinalizeCode();
5635*795d594fSAndroid Build Coastguard Worker code->resize(assembler.CodeSize());
5636*795d594fSAndroid Build Coastguard Worker MemoryRegion code_region(code->data(), code->size());
5637*795d594fSAndroid Build Coastguard Worker assembler.CopyInstructions(code_region);
5638*795d594fSAndroid Build Coastguard Worker }
5639*795d594fSAndroid Build Coastguard Worker
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)5640*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
5641*795d594fSAndroid Build Coastguard Worker // Explicit clinit checks triggered by static invokes must have been pruned by
5642*795d594fSAndroid Build Coastguard Worker // art::PrepareForRegisterAllocation.
5643*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
5644*795d594fSAndroid Build Coastguard Worker
5645*795d594fSAndroid Build Coastguard Worker if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5646*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5647*795d594fSAndroid Build Coastguard Worker return;
5648*795d594fSAndroid Build Coastguard Worker }
5649*795d594fSAndroid Build Coastguard Worker
5650*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5651*795d594fSAndroid Build Coastguard Worker codegen_->GenerateStaticOrDirectCall(
5652*795d594fSAndroid Build Coastguard Worker invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
5653*795d594fSAndroid Build Coastguard Worker
5654*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5655*795d594fSAndroid Build Coastguard Worker }
5656*795d594fSAndroid Build Coastguard Worker
VisitInvokeVirtual(HInvokeVirtual * invoke)5657*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
5658*795d594fSAndroid Build Coastguard Worker if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5659*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5660*795d594fSAndroid Build Coastguard Worker return;
5661*795d594fSAndroid Build Coastguard Worker }
5662*795d594fSAndroid Build Coastguard Worker
5663*795d594fSAndroid Build Coastguard Worker codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
5664*795d594fSAndroid Build Coastguard Worker DCHECK(!codegen_->IsLeafMethod());
5665*795d594fSAndroid Build Coastguard Worker
5666*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5667*795d594fSAndroid Build Coastguard Worker }
5668*795d594fSAndroid Build Coastguard Worker
GetSupportedLoadClassKind(HLoadClass::LoadKind desired_class_load_kind)5669*795d594fSAndroid Build Coastguard Worker HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind(
5670*795d594fSAndroid Build Coastguard Worker HLoadClass::LoadKind desired_class_load_kind) {
5671*795d594fSAndroid Build Coastguard Worker switch (desired_class_load_kind) {
5672*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kInvalid:
5673*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "UNREACHABLE";
5674*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
5675*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kReferrersClass:
5676*795d594fSAndroid Build Coastguard Worker break;
5677*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5678*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBootImageRelRo:
5679*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kAppImageRelRo:
5680*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntry:
5681*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPublic:
5682*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPackage:
5683*795d594fSAndroid Build Coastguard Worker DCHECK(!GetCompilerOptions().IsJitCompiler());
5684*795d594fSAndroid Build Coastguard Worker break;
5685*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kJitBootImageAddress:
5686*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kJitTableAddress:
5687*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsJitCompiler());
5688*795d594fSAndroid Build Coastguard Worker break;
5689*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kRuntimeCall:
5690*795d594fSAndroid Build Coastguard Worker break;
5691*795d594fSAndroid Build Coastguard Worker }
5692*795d594fSAndroid Build Coastguard Worker return desired_class_load_kind;
5693*795d594fSAndroid Build Coastguard Worker }
5694*795d594fSAndroid Build Coastguard Worker
VisitLoadClass(HLoadClass * cls)5695*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
5696*795d594fSAndroid Build Coastguard Worker HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5697*795d594fSAndroid Build Coastguard Worker if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
5698*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
5699*795d594fSAndroid Build Coastguard Worker CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
5700*795d594fSAndroid Build Coastguard Worker cls,
5701*795d594fSAndroid Build Coastguard Worker LocationFrom(calling_convention.GetRegisterAt(0)),
5702*795d594fSAndroid Build Coastguard Worker LocationFrom(vixl::aarch64::x0));
5703*795d594fSAndroid Build Coastguard Worker DCHECK(calling_convention.GetRegisterAt(0).Is(vixl::aarch64::x0));
5704*795d594fSAndroid Build Coastguard Worker return;
5705*795d594fSAndroid Build Coastguard Worker }
5706*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cls->NeedsAccessCheck(),
5707*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
5708*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPackage);
5709*795d594fSAndroid Build Coastguard Worker
5710*795d594fSAndroid Build Coastguard Worker const bool requires_read_barrier = !cls->IsInImage() && codegen_->EmitReadBarrier();
5711*795d594fSAndroid Build Coastguard Worker LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
5712*795d594fSAndroid Build Coastguard Worker ? LocationSummary::kCallOnSlowPath
5713*795d594fSAndroid Build Coastguard Worker : LocationSummary::kNoCall;
5714*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
5715*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
5716*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
5717*795d594fSAndroid Build Coastguard Worker }
5718*795d594fSAndroid Build Coastguard Worker
5719*795d594fSAndroid Build Coastguard Worker if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
5720*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
5721*795d594fSAndroid Build Coastguard Worker }
5722*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5723*795d594fSAndroid Build Coastguard Worker if (load_kind == HLoadClass::LoadKind::kBssEntry ||
5724*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
5725*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPackage) {
5726*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
5727*795d594fSAndroid Build Coastguard Worker // For non-Baker read barrier we have a temp-clobbering call.
5728*795d594fSAndroid Build Coastguard Worker } else {
5729*795d594fSAndroid Build Coastguard Worker // Rely on the type resolution or initialization and marking to save everything we need.
5730*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
5731*795d594fSAndroid Build Coastguard Worker }
5732*795d594fSAndroid Build Coastguard Worker }
5733*795d594fSAndroid Build Coastguard Worker }
5734*795d594fSAndroid Build Coastguard Worker
5735*795d594fSAndroid Build Coastguard Worker // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5736*795d594fSAndroid Build Coastguard Worker // move.
VisitLoadClass(HLoadClass * cls)5737*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
5738*795d594fSAndroid Build Coastguard Worker HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5739*795d594fSAndroid Build Coastguard Worker if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
5740*795d594fSAndroid Build Coastguard Worker codegen_->GenerateLoadClassRuntimeCall(cls);
5741*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5742*795d594fSAndroid Build Coastguard Worker return;
5743*795d594fSAndroid Build Coastguard Worker }
5744*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cls->NeedsAccessCheck(),
5745*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
5746*795d594fSAndroid Build Coastguard Worker load_kind == HLoadClass::LoadKind::kBssEntryPackage);
5747*795d594fSAndroid Build Coastguard Worker
5748*795d594fSAndroid Build Coastguard Worker Location out_loc = cls->GetLocations()->Out();
5749*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(cls);
5750*795d594fSAndroid Build Coastguard Worker
5751*795d594fSAndroid Build Coastguard Worker const ReadBarrierOption read_barrier_option =
5752*795d594fSAndroid Build Coastguard Worker cls->IsInImage() ? kWithoutReadBarrier : codegen_->GetCompilerReadBarrierOption();
5753*795d594fSAndroid Build Coastguard Worker bool generate_null_check = false;
5754*795d594fSAndroid Build Coastguard Worker switch (load_kind) {
5755*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kReferrersClass: {
5756*795d594fSAndroid Build Coastguard Worker DCHECK(!cls->CanCallRuntime());
5757*795d594fSAndroid Build Coastguard Worker DCHECK(!cls->MustGenerateClinitCheck());
5758*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5759*795d594fSAndroid Build Coastguard Worker Register current_method = InputRegisterAt(cls, 0);
5760*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(cls,
5761*795d594fSAndroid Build Coastguard Worker out_loc,
5762*795d594fSAndroid Build Coastguard Worker current_method,
5763*795d594fSAndroid Build Coastguard Worker ArtMethod::DeclaringClassOffset().Int32Value(),
5764*795d594fSAndroid Build Coastguard Worker /* fixup_label= */ nullptr,
5765*795d594fSAndroid Build Coastguard Worker read_barrier_option);
5766*795d594fSAndroid Build Coastguard Worker break;
5767*795d594fSAndroid Build Coastguard Worker }
5768*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5769*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
5770*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerOptions().IsBootImageExtension());
5771*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5772*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative type patch.
5773*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = cls->GetDexFile();
5774*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index = cls->GetTypeIndex();
5775*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewBootImageTypePatch(dex_file, type_index);
5776*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
5777*795d594fSAndroid Build Coastguard Worker // Add ADD with its PC-relative type patch.
5778*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label =
5779*795d594fSAndroid Build Coastguard Worker codegen_->NewBootImageTypePatch(dex_file, type_index, adrp_label);
5780*795d594fSAndroid Build Coastguard Worker codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
5781*795d594fSAndroid Build Coastguard Worker break;
5782*795d594fSAndroid Build Coastguard Worker }
5783*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBootImageRelRo: {
5784*795d594fSAndroid Build Coastguard Worker DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5785*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = CodeGenerator::GetBootImageOffset(cls);
5786*795d594fSAndroid Build Coastguard Worker codegen_->LoadBootImageRelRoEntry(out.W(), boot_image_offset);
5787*795d594fSAndroid Build Coastguard Worker break;
5788*795d594fSAndroid Build Coastguard Worker }
5789*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kAppImageRelRo: {
5790*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->GetCompilerOptions().IsAppImage());
5791*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5792*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative type patch.
5793*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = cls->GetDexFile();
5794*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_index = cls->GetTypeIndex();
5795*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewAppImageTypePatch(dex_file, type_index);
5796*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
5797*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative type patch.
5798*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label =
5799*795d594fSAndroid Build Coastguard Worker codegen_->NewAppImageTypePatch(dex_file, type_index, adrp_label);
5800*795d594fSAndroid Build Coastguard Worker codegen_->EmitLdrOffsetPlaceholder(ldr_label, out.W(), out.X());
5801*795d594fSAndroid Build Coastguard Worker break;
5802*795d594fSAndroid Build Coastguard Worker }
5803*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntry:
5804*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPublic:
5805*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kBssEntryPackage: {
5806*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative Class .bss entry patch.
5807*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register temp = XRegisterFrom(out_loc);
5808*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewBssEntryTypePatch(cls);
5809*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, temp);
5810*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative Class .bss entry patch.
5811*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label = codegen_->NewBssEntryTypePatch(cls, adrp_label);
5812*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::Class> */ out = *(base_address + offset) /* PC-relative */
5813*795d594fSAndroid Build Coastguard Worker // All aligned loads are implicitly atomic consume operations on ARM64.
5814*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(cls,
5815*795d594fSAndroid Build Coastguard Worker out_loc,
5816*795d594fSAndroid Build Coastguard Worker temp,
5817*795d594fSAndroid Build Coastguard Worker /* offset placeholder */ 0u,
5818*795d594fSAndroid Build Coastguard Worker ldr_label,
5819*795d594fSAndroid Build Coastguard Worker read_barrier_option);
5820*795d594fSAndroid Build Coastguard Worker generate_null_check = true;
5821*795d594fSAndroid Build Coastguard Worker break;
5822*795d594fSAndroid Build Coastguard Worker }
5823*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kJitBootImageAddress: {
5824*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5825*795d594fSAndroid Build Coastguard Worker uint32_t address = reinterpret_cast32<uint32_t>(cls->GetClass().Get());
5826*795d594fSAndroid Build Coastguard Worker DCHECK_NE(address, 0u);
5827*795d594fSAndroid Build Coastguard Worker __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(address));
5828*795d594fSAndroid Build Coastguard Worker break;
5829*795d594fSAndroid Build Coastguard Worker }
5830*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kJitTableAddress: {
5831*795d594fSAndroid Build Coastguard Worker __ Ldr(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
5832*795d594fSAndroid Build Coastguard Worker cls->GetTypeIndex(),
5833*795d594fSAndroid Build Coastguard Worker cls->GetClass()));
5834*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(cls,
5835*795d594fSAndroid Build Coastguard Worker out_loc,
5836*795d594fSAndroid Build Coastguard Worker out.X(),
5837*795d594fSAndroid Build Coastguard Worker /* offset= */ 0,
5838*795d594fSAndroid Build Coastguard Worker /* fixup_label= */ nullptr,
5839*795d594fSAndroid Build Coastguard Worker read_barrier_option);
5840*795d594fSAndroid Build Coastguard Worker break;
5841*795d594fSAndroid Build Coastguard Worker }
5842*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kRuntimeCall:
5843*795d594fSAndroid Build Coastguard Worker case HLoadClass::LoadKind::kInvalid:
5844*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "UNREACHABLE";
5845*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
5846*795d594fSAndroid Build Coastguard Worker }
5847*795d594fSAndroid Build Coastguard Worker
5848*795d594fSAndroid Build Coastguard Worker bool do_clinit = cls->MustGenerateClinitCheck();
5849*795d594fSAndroid Build Coastguard Worker if (generate_null_check || do_clinit) {
5850*795d594fSAndroid Build Coastguard Worker DCHECK(cls->CanCallRuntime());
5851*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
5852*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) LoadClassSlowPathARM64(cls, cls);
5853*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
5854*795d594fSAndroid Build Coastguard Worker if (generate_null_check) {
5855*795d594fSAndroid Build Coastguard Worker __ Cbz(out, slow_path->GetEntryLabel());
5856*795d594fSAndroid Build Coastguard Worker }
5857*795d594fSAndroid Build Coastguard Worker if (cls->MustGenerateClinitCheck()) {
5858*795d594fSAndroid Build Coastguard Worker GenerateClassInitializationCheck(slow_path, out);
5859*795d594fSAndroid Build Coastguard Worker } else {
5860*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
5861*795d594fSAndroid Build Coastguard Worker }
5862*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
5863*795d594fSAndroid Build Coastguard Worker }
5864*795d594fSAndroid Build Coastguard Worker }
5865*795d594fSAndroid Build Coastguard Worker
VisitLoadMethodHandle(HLoadMethodHandle * load)5866*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
5867*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
5868*795d594fSAndroid Build Coastguard Worker Location location = LocationFrom(calling_convention.GetRegisterAt(0));
5869*795d594fSAndroid Build Coastguard Worker CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
5870*795d594fSAndroid Build Coastguard Worker }
5871*795d594fSAndroid Build Coastguard Worker
VisitLoadMethodHandle(HLoadMethodHandle * load)5872*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
5873*795d594fSAndroid Build Coastguard Worker codegen_->GenerateLoadMethodHandleRuntimeCall(load);
5874*795d594fSAndroid Build Coastguard Worker }
5875*795d594fSAndroid Build Coastguard Worker
VisitLoadMethodType(HLoadMethodType * load)5876*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) {
5877*795d594fSAndroid Build Coastguard Worker if (load->GetLoadKind() == HLoadMethodType::LoadKind::kRuntimeCall) {
5878*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
5879*795d594fSAndroid Build Coastguard Worker Location location = LocationFrom(calling_convention.GetRegisterAt(0));
5880*795d594fSAndroid Build Coastguard Worker CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
5881*795d594fSAndroid Build Coastguard Worker } else {
5882*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5883*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
5884*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5885*795d594fSAndroid Build Coastguard Worker if (load->GetLoadKind() == HLoadMethodType::LoadKind::kBssEntry) {
5886*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
5887*795d594fSAndroid Build Coastguard Worker // For non-Baker read barrier we have a temp-clobbering call.
5888*795d594fSAndroid Build Coastguard Worker } else {
5889*795d594fSAndroid Build Coastguard Worker // Rely on the pResolveMethodType to save everything.
5890*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
5891*795d594fSAndroid Build Coastguard Worker }
5892*795d594fSAndroid Build Coastguard Worker }
5893*795d594fSAndroid Build Coastguard Worker }
5894*795d594fSAndroid Build Coastguard Worker }
5895*795d594fSAndroid Build Coastguard Worker
VisitLoadMethodType(HLoadMethodType * load)5896*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLoadMethodType(HLoadMethodType* load) {
5897*795d594fSAndroid Build Coastguard Worker Location out_loc = load->GetLocations()->Out();
5898*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(load);
5899*795d594fSAndroid Build Coastguard Worker
5900*795d594fSAndroid Build Coastguard Worker switch (load->GetLoadKind()) {
5901*795d594fSAndroid Build Coastguard Worker case HLoadMethodType::LoadKind::kBssEntry: {
5902*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative Class .bss entry patch.
5903*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register temp = XRegisterFrom(out_loc);
5904*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewMethodTypeBssEntryPatch(load);
5905*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, temp);
5906*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative MethodType .bss entry patch.
5907*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label = codegen_->NewMethodTypeBssEntryPatch(load, adrp_label);
5908*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::MethodType> */ out = *(base_address + offset) /* PC-relative */
5909*795d594fSAndroid Build Coastguard Worker // All aligned loads are implicitly atomic consume operations on ARM64.
5910*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(load,
5911*795d594fSAndroid Build Coastguard Worker out_loc,
5912*795d594fSAndroid Build Coastguard Worker temp,
5913*795d594fSAndroid Build Coastguard Worker /* offset placeholder */ 0u,
5914*795d594fSAndroid Build Coastguard Worker ldr_label,
5915*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerReadBarrierOption());
5916*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
5917*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) LoadMethodTypeSlowPathARM64(load);
5918*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
5919*795d594fSAndroid Build Coastguard Worker __ Cbz(out, slow_path->GetEntryLabel());
5920*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
5921*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code = */ __LINE__);
5922*795d594fSAndroid Build Coastguard Worker return;
5923*795d594fSAndroid Build Coastguard Worker }
5924*795d594fSAndroid Build Coastguard Worker case HLoadMethodType::LoadKind::kJitTableAddress: {
5925*795d594fSAndroid Build Coastguard Worker __ Ldr(out, codegen_->DeduplicateJitMethodTypeLiteral(load->GetDexFile(),
5926*795d594fSAndroid Build Coastguard Worker load->GetProtoIndex(),
5927*795d594fSAndroid Build Coastguard Worker load->GetMethodType()));
5928*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(load,
5929*795d594fSAndroid Build Coastguard Worker out_loc,
5930*795d594fSAndroid Build Coastguard Worker out.X(),
5931*795d594fSAndroid Build Coastguard Worker /* offset= */ 0,
5932*795d594fSAndroid Build Coastguard Worker /* fixup_label= */ nullptr,
5933*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerReadBarrierOption());
5934*795d594fSAndroid Build Coastguard Worker return;
5935*795d594fSAndroid Build Coastguard Worker }
5936*795d594fSAndroid Build Coastguard Worker default:
5937*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(load->GetLoadKind(), HLoadMethodType::LoadKind::kRuntimeCall);
5938*795d594fSAndroid Build Coastguard Worker codegen_->GenerateLoadMethodTypeRuntimeCall(load);
5939*795d594fSAndroid Build Coastguard Worker break;
5940*795d594fSAndroid Build Coastguard Worker }
5941*795d594fSAndroid Build Coastguard Worker }
5942*795d594fSAndroid Build Coastguard Worker
GetExceptionTlsAddress()5943*795d594fSAndroid Build Coastguard Worker static MemOperand GetExceptionTlsAddress() {
5944*795d594fSAndroid Build Coastguard Worker return MemOperand(tr, Thread::ExceptionOffset<kArm64PointerSize>().Int32Value());
5945*795d594fSAndroid Build Coastguard Worker }
5946*795d594fSAndroid Build Coastguard Worker
VisitLoadException(HLoadException * load)5947*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
5948*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5949*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
5950*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5951*795d594fSAndroid Build Coastguard Worker }
5952*795d594fSAndroid Build Coastguard Worker
VisitLoadException(HLoadException * instruction)5953*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
5954*795d594fSAndroid Build Coastguard Worker __ Ldr(OutputRegister(instruction), GetExceptionTlsAddress());
5955*795d594fSAndroid Build Coastguard Worker }
5956*795d594fSAndroid Build Coastguard Worker
VisitClearException(HClearException * clear)5957*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitClearException(HClearException* clear) {
5958*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
5959*795d594fSAndroid Build Coastguard Worker }
5960*795d594fSAndroid Build Coastguard Worker
VisitClearException(HClearException * clear)5961*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitClearException([[maybe_unused]] HClearException* clear) {
5962*795d594fSAndroid Build Coastguard Worker __ Str(wzr, GetExceptionTlsAddress());
5963*795d594fSAndroid Build Coastguard Worker }
5964*795d594fSAndroid Build Coastguard Worker
GetSupportedLoadStringKind(HLoadString::LoadKind desired_string_load_kind)5965*795d594fSAndroid Build Coastguard Worker HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
5966*795d594fSAndroid Build Coastguard Worker HLoadString::LoadKind desired_string_load_kind) {
5967*795d594fSAndroid Build Coastguard Worker switch (desired_string_load_kind) {
5968*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5969*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBootImageRelRo:
5970*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBssEntry:
5971*795d594fSAndroid Build Coastguard Worker DCHECK(!GetCompilerOptions().IsJitCompiler());
5972*795d594fSAndroid Build Coastguard Worker break;
5973*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kJitBootImageAddress:
5974*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kJitTableAddress:
5975*795d594fSAndroid Build Coastguard Worker DCHECK(GetCompilerOptions().IsJitCompiler());
5976*795d594fSAndroid Build Coastguard Worker break;
5977*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kRuntimeCall:
5978*795d594fSAndroid Build Coastguard Worker break;
5979*795d594fSAndroid Build Coastguard Worker }
5980*795d594fSAndroid Build Coastguard Worker return desired_string_load_kind;
5981*795d594fSAndroid Build Coastguard Worker }
5982*795d594fSAndroid Build Coastguard Worker
VisitLoadString(HLoadString * load)5983*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
5984*795d594fSAndroid Build Coastguard Worker LocationSummary::CallKind call_kind = codegen_->GetLoadStringCallKind(load);
5985*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
5986*795d594fSAndroid Build Coastguard Worker if (load->GetLoadKind() == HLoadString::LoadKind::kRuntimeCall) {
5987*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
5988*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
5989*795d594fSAndroid Build Coastguard Worker } else {
5990*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5991*795d594fSAndroid Build Coastguard Worker if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) {
5992*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
5993*795d594fSAndroid Build Coastguard Worker // For non-Baker read barrier we have a temp-clobbering call.
5994*795d594fSAndroid Build Coastguard Worker } else {
5995*795d594fSAndroid Build Coastguard Worker // Rely on the pResolveString and marking to save everything we need.
5996*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
5997*795d594fSAndroid Build Coastguard Worker }
5998*795d594fSAndroid Build Coastguard Worker }
5999*795d594fSAndroid Build Coastguard Worker }
6000*795d594fSAndroid Build Coastguard Worker }
6001*795d594fSAndroid Build Coastguard Worker
6002*795d594fSAndroid Build Coastguard Worker // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6003*795d594fSAndroid Build Coastguard Worker // move.
VisitLoadString(HLoadString * load)6004*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
6005*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(load);
6006*795d594fSAndroid Build Coastguard Worker Location out_loc = load->GetLocations()->Out();
6007*795d594fSAndroid Build Coastguard Worker
6008*795d594fSAndroid Build Coastguard Worker switch (load->GetLoadKind()) {
6009*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
6010*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
6011*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerOptions().IsBootImageExtension());
6012*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative String patch.
6013*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = load->GetDexFile();
6014*795d594fSAndroid Build Coastguard Worker const dex::StringIndex string_index = load->GetStringIndex();
6015*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewBootImageStringPatch(dex_file, string_index);
6016*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
6017*795d594fSAndroid Build Coastguard Worker // Add ADD with its PC-relative String patch.
6018*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* add_label =
6019*795d594fSAndroid Build Coastguard Worker codegen_->NewBootImageStringPatch(dex_file, string_index, adrp_label);
6020*795d594fSAndroid Build Coastguard Worker codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
6021*795d594fSAndroid Build Coastguard Worker return;
6022*795d594fSAndroid Build Coastguard Worker }
6023*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBootImageRelRo: {
6024*795d594fSAndroid Build Coastguard Worker DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
6025*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = CodeGenerator::GetBootImageOffset(load);
6026*795d594fSAndroid Build Coastguard Worker codegen_->LoadBootImageRelRoEntry(out.W(), boot_image_offset);
6027*795d594fSAndroid Build Coastguard Worker return;
6028*795d594fSAndroid Build Coastguard Worker }
6029*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kBssEntry: {
6030*795d594fSAndroid Build Coastguard Worker // Add ADRP with its PC-relative String .bss entry patch.
6031*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file = load->GetDexFile();
6032*795d594fSAndroid Build Coastguard Worker const dex::StringIndex string_index = load->GetStringIndex();
6033*795d594fSAndroid Build Coastguard Worker Register temp = XRegisterFrom(out_loc);
6034*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* adrp_label = codegen_->NewStringBssEntryPatch(dex_file, string_index);
6035*795d594fSAndroid Build Coastguard Worker codegen_->EmitAdrpPlaceholder(adrp_label, temp);
6036*795d594fSAndroid Build Coastguard Worker // Add LDR with its PC-relative String .bss entry patch.
6037*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* ldr_label =
6038*795d594fSAndroid Build Coastguard Worker codegen_->NewStringBssEntryPatch(dex_file, string_index, adrp_label);
6039*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::String> */ out = *(base_address + offset) /* PC-relative */
6040*795d594fSAndroid Build Coastguard Worker // All aligned loads are implicitly atomic consume operations on ARM64.
6041*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(load,
6042*795d594fSAndroid Build Coastguard Worker out_loc,
6043*795d594fSAndroid Build Coastguard Worker temp,
6044*795d594fSAndroid Build Coastguard Worker /* offset placeholder */ 0u,
6045*795d594fSAndroid Build Coastguard Worker ldr_label,
6046*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerReadBarrierOption());
6047*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
6048*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) LoadStringSlowPathARM64(load);
6049*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
6050*795d594fSAndroid Build Coastguard Worker __ Cbz(out.X(), slow_path->GetEntryLabel());
6051*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
6052*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6053*795d594fSAndroid Build Coastguard Worker return;
6054*795d594fSAndroid Build Coastguard Worker }
6055*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kJitBootImageAddress: {
6056*795d594fSAndroid Build Coastguard Worker uint32_t address = reinterpret_cast32<uint32_t>(load->GetString().Get());
6057*795d594fSAndroid Build Coastguard Worker DCHECK_NE(address, 0u);
6058*795d594fSAndroid Build Coastguard Worker __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(address));
6059*795d594fSAndroid Build Coastguard Worker return;
6060*795d594fSAndroid Build Coastguard Worker }
6061*795d594fSAndroid Build Coastguard Worker case HLoadString::LoadKind::kJitTableAddress: {
6062*795d594fSAndroid Build Coastguard Worker __ Ldr(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
6063*795d594fSAndroid Build Coastguard Worker load->GetStringIndex(),
6064*795d594fSAndroid Build Coastguard Worker load->GetString()));
6065*795d594fSAndroid Build Coastguard Worker codegen_->GenerateGcRootFieldLoad(load,
6066*795d594fSAndroid Build Coastguard Worker out_loc,
6067*795d594fSAndroid Build Coastguard Worker out.X(),
6068*795d594fSAndroid Build Coastguard Worker /* offset= */ 0,
6069*795d594fSAndroid Build Coastguard Worker /* fixup_label= */ nullptr,
6070*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerReadBarrierOption());
6071*795d594fSAndroid Build Coastguard Worker return;
6072*795d594fSAndroid Build Coastguard Worker }
6073*795d594fSAndroid Build Coastguard Worker default:
6074*795d594fSAndroid Build Coastguard Worker break;
6075*795d594fSAndroid Build Coastguard Worker }
6076*795d594fSAndroid Build Coastguard Worker
6077*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6078*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(), out.GetCode());
6079*795d594fSAndroid Build Coastguard Worker __ Mov(calling_convention.GetRegisterAt(0).W(), load->GetStringIndex().index_);
6080*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6081*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
6082*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6083*795d594fSAndroid Build Coastguard Worker }
6084*795d594fSAndroid Build Coastguard Worker
VisitLongConstant(HLongConstant * constant)6085*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
6086*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
6087*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::ConstantLocation(constant));
6088*795d594fSAndroid Build Coastguard Worker }
6089*795d594fSAndroid Build Coastguard Worker
VisitLongConstant(HLongConstant * constant)6090*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitLongConstant([[maybe_unused]] HLongConstant* constant) {
6091*795d594fSAndroid Build Coastguard Worker // Will be generated at use site.
6092*795d594fSAndroid Build Coastguard Worker }
6093*795d594fSAndroid Build Coastguard Worker
VisitMonitorOperation(HMonitorOperation * instruction)6094*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
6095*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6096*795d594fSAndroid Build Coastguard Worker instruction, LocationSummary::kCallOnMainOnly);
6097*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6098*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
6099*795d594fSAndroid Build Coastguard Worker }
6100*795d594fSAndroid Build Coastguard Worker
VisitMonitorOperation(HMonitorOperation * instruction)6101*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
6102*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
6103*795d594fSAndroid Build Coastguard Worker instruction,
6104*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc());
6105*795d594fSAndroid Build Coastguard Worker if (instruction->IsEnter()) {
6106*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6107*795d594fSAndroid Build Coastguard Worker } else {
6108*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6109*795d594fSAndroid Build Coastguard Worker }
6110*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6111*795d594fSAndroid Build Coastguard Worker }
6112*795d594fSAndroid Build Coastguard Worker
VisitMul(HMul * mul)6113*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMul(HMul* mul) {
6114*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
6115*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
6116*795d594fSAndroid Build Coastguard Worker switch (mul->GetResultType()) {
6117*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6118*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6119*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6120*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
6121*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6122*795d594fSAndroid Build Coastguard Worker break;
6123*795d594fSAndroid Build Coastguard Worker
6124*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6125*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6126*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
6127*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
6128*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6129*795d594fSAndroid Build Coastguard Worker break;
6130*795d594fSAndroid Build Coastguard Worker
6131*795d594fSAndroid Build Coastguard Worker default:
6132*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
6133*795d594fSAndroid Build Coastguard Worker }
6134*795d594fSAndroid Build Coastguard Worker }
6135*795d594fSAndroid Build Coastguard Worker
VisitMul(HMul * mul)6136*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
6137*795d594fSAndroid Build Coastguard Worker switch (mul->GetResultType()) {
6138*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6139*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6140*795d594fSAndroid Build Coastguard Worker __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
6141*795d594fSAndroid Build Coastguard Worker break;
6142*795d594fSAndroid Build Coastguard Worker
6143*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6144*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6145*795d594fSAndroid Build Coastguard Worker __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
6146*795d594fSAndroid Build Coastguard Worker break;
6147*795d594fSAndroid Build Coastguard Worker
6148*795d594fSAndroid Build Coastguard Worker default:
6149*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
6150*795d594fSAndroid Build Coastguard Worker }
6151*795d594fSAndroid Build Coastguard Worker }
6152*795d594fSAndroid Build Coastguard Worker
VisitNeg(HNeg * neg)6153*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
6154*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
6155*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
6156*795d594fSAndroid Build Coastguard Worker switch (neg->GetResultType()) {
6157*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6158*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6159*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, ARM64EncodableConstantOrRegister(neg->InputAt(0), neg));
6160*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6161*795d594fSAndroid Build Coastguard Worker break;
6162*795d594fSAndroid Build Coastguard Worker
6163*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6164*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6165*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
6166*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6167*795d594fSAndroid Build Coastguard Worker break;
6168*795d594fSAndroid Build Coastguard Worker
6169*795d594fSAndroid Build Coastguard Worker default:
6170*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
6171*795d594fSAndroid Build Coastguard Worker }
6172*795d594fSAndroid Build Coastguard Worker }
6173*795d594fSAndroid Build Coastguard Worker
VisitNeg(HNeg * neg)6174*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
6175*795d594fSAndroid Build Coastguard Worker switch (neg->GetResultType()) {
6176*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6177*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6178*795d594fSAndroid Build Coastguard Worker __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
6179*795d594fSAndroid Build Coastguard Worker break;
6180*795d594fSAndroid Build Coastguard Worker
6181*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6182*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6183*795d594fSAndroid Build Coastguard Worker __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
6184*795d594fSAndroid Build Coastguard Worker break;
6185*795d594fSAndroid Build Coastguard Worker
6186*795d594fSAndroid Build Coastguard Worker default:
6187*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
6188*795d594fSAndroid Build Coastguard Worker }
6189*795d594fSAndroid Build Coastguard Worker }
6190*795d594fSAndroid Build Coastguard Worker
VisitNewArray(HNewArray * instruction)6191*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
6192*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6193*795d594fSAndroid Build Coastguard Worker instruction, LocationSummary::kCallOnMainOnly);
6194*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6195*795d594fSAndroid Build Coastguard Worker locations->SetOut(LocationFrom(x0));
6196*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
6197*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
6198*795d594fSAndroid Build Coastguard Worker }
6199*795d594fSAndroid Build Coastguard Worker
VisitNewArray(HNewArray * instruction)6200*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
6201*795d594fSAndroid Build Coastguard Worker // Note: if heap poisoning is enabled, the entry point takes care of poisoning the reference.
6202*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum entrypoint = CodeGenerator::GetArrayAllocationEntrypoint(instruction);
6203*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
6204*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
6205*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6206*795d594fSAndroid Build Coastguard Worker }
6207*795d594fSAndroid Build Coastguard Worker
VisitNewInstance(HNewInstance * instruction)6208*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
6209*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6210*795d594fSAndroid Build Coastguard Worker instruction, LocationSummary::kCallOnMainOnly);
6211*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6212*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
6213*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
6214*795d594fSAndroid Build Coastguard Worker }
6215*795d594fSAndroid Build Coastguard Worker
VisitNewInstance(HNewInstance * instruction)6216*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
6217*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
6218*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
6219*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6220*795d594fSAndroid Build Coastguard Worker }
6221*795d594fSAndroid Build Coastguard Worker
VisitNot(HNot * instruction)6222*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNot(HNot* instruction) {
6223*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6224*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6225*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6226*795d594fSAndroid Build Coastguard Worker }
6227*795d594fSAndroid Build Coastguard Worker
VisitNot(HNot * instruction)6228*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
6229*795d594fSAndroid Build Coastguard Worker switch (instruction->GetResultType()) {
6230*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6231*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6232*795d594fSAndroid Build Coastguard Worker __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
6233*795d594fSAndroid Build Coastguard Worker break;
6234*795d594fSAndroid Build Coastguard Worker
6235*795d594fSAndroid Build Coastguard Worker default:
6236*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
6237*795d594fSAndroid Build Coastguard Worker }
6238*795d594fSAndroid Build Coastguard Worker }
6239*795d594fSAndroid Build Coastguard Worker
VisitBooleanNot(HBooleanNot * instruction)6240*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitBooleanNot(HBooleanNot* instruction) {
6241*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6242*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6243*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6244*795d594fSAndroid Build Coastguard Worker }
6245*795d594fSAndroid Build Coastguard Worker
VisitBooleanNot(HBooleanNot * instruction)6246*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitBooleanNot(HBooleanNot* instruction) {
6247*795d594fSAndroid Build Coastguard Worker __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), vixl::aarch64::Operand(1));
6248*795d594fSAndroid Build Coastguard Worker }
6249*795d594fSAndroid Build Coastguard Worker
VisitNullCheck(HNullCheck * instruction)6250*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
6251*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
6252*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6253*795d594fSAndroid Build Coastguard Worker }
6254*795d594fSAndroid Build Coastguard Worker
GenerateImplicitNullCheck(HNullCheck * instruction)6255*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
6256*795d594fSAndroid Build Coastguard Worker if (CanMoveNullCheckToUser(instruction)) {
6257*795d594fSAndroid Build Coastguard Worker return;
6258*795d594fSAndroid Build Coastguard Worker }
6259*795d594fSAndroid Build Coastguard Worker {
6260*795d594fSAndroid Build Coastguard Worker // Ensure that between load and RecordPcInfo there are no pools emitted.
6261*795d594fSAndroid Build Coastguard Worker EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
6262*795d594fSAndroid Build Coastguard Worker Location obj = instruction->GetLocations()->InAt(0);
6263*795d594fSAndroid Build Coastguard Worker __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
6264*795d594fSAndroid Build Coastguard Worker RecordPcInfo(instruction, instruction->GetDexPc());
6265*795d594fSAndroid Build Coastguard Worker }
6266*795d594fSAndroid Build Coastguard Worker }
6267*795d594fSAndroid Build Coastguard Worker
GenerateExplicitNullCheck(HNullCheck * instruction)6268*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
6269*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = new (GetScopedAllocator()) NullCheckSlowPathARM64(instruction);
6270*795d594fSAndroid Build Coastguard Worker AddSlowPath(slow_path);
6271*795d594fSAndroid Build Coastguard Worker
6272*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
6273*795d594fSAndroid Build Coastguard Worker Location obj = locations->InAt(0);
6274*795d594fSAndroid Build Coastguard Worker
6275*795d594fSAndroid Build Coastguard Worker __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
6276*795d594fSAndroid Build Coastguard Worker }
6277*795d594fSAndroid Build Coastguard Worker
VisitNullCheck(HNullCheck * instruction)6278*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
6279*795d594fSAndroid Build Coastguard Worker codegen_->GenerateNullCheck(instruction);
6280*795d594fSAndroid Build Coastguard Worker }
6281*795d594fSAndroid Build Coastguard Worker
VisitOr(HOr * instruction)6282*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitOr(HOr* instruction) {
6283*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6284*795d594fSAndroid Build Coastguard Worker }
6285*795d594fSAndroid Build Coastguard Worker
VisitOr(HOr * instruction)6286*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
6287*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6288*795d594fSAndroid Build Coastguard Worker }
6289*795d594fSAndroid Build Coastguard Worker
VisitParallelMove(HParallelMove * instruction)6290*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitParallelMove([[maybe_unused]] HParallelMove* instruction) {
6291*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
6292*795d594fSAndroid Build Coastguard Worker }
6293*795d594fSAndroid Build Coastguard Worker
VisitParallelMove(HParallelMove * instruction)6294*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
6295*795d594fSAndroid Build Coastguard Worker if (instruction->GetNext()->IsSuspendCheck() &&
6296*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetLoopInformation() != nullptr) {
6297*795d594fSAndroid Build Coastguard Worker HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
6298*795d594fSAndroid Build Coastguard Worker // The back edge will generate the suspend check.
6299*795d594fSAndroid Build Coastguard Worker codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
6300*795d594fSAndroid Build Coastguard Worker }
6301*795d594fSAndroid Build Coastguard Worker
6302*795d594fSAndroid Build Coastguard Worker codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6303*795d594fSAndroid Build Coastguard Worker }
6304*795d594fSAndroid Build Coastguard Worker
VisitParameterValue(HParameterValue * instruction)6305*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
6306*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6307*795d594fSAndroid Build Coastguard Worker Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
6308*795d594fSAndroid Build Coastguard Worker if (location.IsStackSlot()) {
6309*795d594fSAndroid Build Coastguard Worker location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
6310*795d594fSAndroid Build Coastguard Worker } else if (location.IsDoubleStackSlot()) {
6311*795d594fSAndroid Build Coastguard Worker location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
6312*795d594fSAndroid Build Coastguard Worker }
6313*795d594fSAndroid Build Coastguard Worker locations->SetOut(location);
6314*795d594fSAndroid Build Coastguard Worker }
6315*795d594fSAndroid Build Coastguard Worker
VisitParameterValue(HParameterValue * instruction)6316*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitParameterValue(
6317*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] HParameterValue* instruction) {
6318*795d594fSAndroid Build Coastguard Worker // Nothing to do, the parameter is already at its location.
6319*795d594fSAndroid Build Coastguard Worker }
6320*795d594fSAndroid Build Coastguard Worker
VisitCurrentMethod(HCurrentMethod * instruction)6321*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitCurrentMethod(HCurrentMethod* instruction) {
6322*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
6323*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
6324*795d594fSAndroid Build Coastguard Worker locations->SetOut(LocationFrom(kArtMethodRegister));
6325*795d594fSAndroid Build Coastguard Worker }
6326*795d594fSAndroid Build Coastguard Worker
VisitCurrentMethod(HCurrentMethod * instruction)6327*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitCurrentMethod(
6328*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] HCurrentMethod* instruction) {
6329*795d594fSAndroid Build Coastguard Worker // Nothing to do, the method is already at its location.
6330*795d594fSAndroid Build Coastguard Worker }
6331*795d594fSAndroid Build Coastguard Worker
VisitPhi(HPhi * instruction)6332*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
6333*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6334*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
6335*795d594fSAndroid Build Coastguard Worker locations->SetInAt(i, Location::Any());
6336*795d594fSAndroid Build Coastguard Worker }
6337*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::Any());
6338*795d594fSAndroid Build Coastguard Worker }
6339*795d594fSAndroid Build Coastguard Worker
VisitPhi(HPhi * instruction)6340*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitPhi([[maybe_unused]] HPhi* instruction) {
6341*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
6342*795d594fSAndroid Build Coastguard Worker }
6343*795d594fSAndroid Build Coastguard Worker
VisitRem(HRem * rem)6344*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitRem(HRem* rem) {
6345*795d594fSAndroid Build Coastguard Worker DataType::Type type = rem->GetResultType();
6346*795d594fSAndroid Build Coastguard Worker LocationSummary::CallKind call_kind =
6347*795d594fSAndroid Build Coastguard Worker DataType::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
6348*795d594fSAndroid Build Coastguard Worker : LocationSummary::kNoCall;
6349*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind);
6350*795d594fSAndroid Build Coastguard Worker
6351*795d594fSAndroid Build Coastguard Worker switch (type) {
6352*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6353*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6354*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6355*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
6356*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6357*795d594fSAndroid Build Coastguard Worker break;
6358*795d594fSAndroid Build Coastguard Worker
6359*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6360*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
6361*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6362*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
6363*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
6364*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(type));
6365*795d594fSAndroid Build Coastguard Worker
6366*795d594fSAndroid Build Coastguard Worker break;
6367*795d594fSAndroid Build Coastguard Worker }
6368*795d594fSAndroid Build Coastguard Worker
6369*795d594fSAndroid Build Coastguard Worker default:
6370*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected rem type " << type;
6371*795d594fSAndroid Build Coastguard Worker }
6372*795d594fSAndroid Build Coastguard Worker }
6373*795d594fSAndroid Build Coastguard Worker
GenerateIntRemForPower2Denom(HRem * instruction)6374*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntRemForPower2Denom(HRem *instruction) {
6375*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
6376*795d594fSAndroid Build Coastguard Worker uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm));
6377*795d594fSAndroid Build Coastguard Worker DCHECK(IsPowerOfTwo(abs_imm)) << abs_imm;
6378*795d594fSAndroid Build Coastguard Worker
6379*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
6380*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
6381*795d594fSAndroid Build Coastguard Worker
6382*795d594fSAndroid Build Coastguard Worker if (HasNonNegativeOrMinIntInputAt(instruction, 0)) {
6383*795d594fSAndroid Build Coastguard Worker // No need to adjust the result for non-negative dividends or the INT32_MIN/INT64_MIN dividends.
6384*795d594fSAndroid Build Coastguard Worker // NOTE: The generated code for HRem correctly works for the INT32_MIN/INT64_MIN dividends.
6385*795d594fSAndroid Build Coastguard Worker // INT*_MIN % imm must be 0 for any imm of power 2. 'and' works only with bits
6386*795d594fSAndroid Build Coastguard Worker // 0..30 (Int32 case)/0..62 (Int64 case) of a dividend. For INT32_MIN/INT64_MIN they are zeros.
6387*795d594fSAndroid Build Coastguard Worker // So 'and' always produces zero.
6388*795d594fSAndroid Build Coastguard Worker __ And(out, dividend, abs_imm - 1);
6389*795d594fSAndroid Build Coastguard Worker } else {
6390*795d594fSAndroid Build Coastguard Worker if (abs_imm == 2) {
6391*795d594fSAndroid Build Coastguard Worker __ Cmp(dividend, 0);
6392*795d594fSAndroid Build Coastguard Worker __ And(out, dividend, 1);
6393*795d594fSAndroid Build Coastguard Worker __ Csneg(out, out, out, ge);
6394*795d594fSAndroid Build Coastguard Worker } else {
6395*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
6396*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
6397*795d594fSAndroid Build Coastguard Worker
6398*795d594fSAndroid Build Coastguard Worker __ Negs(temp, dividend);
6399*795d594fSAndroid Build Coastguard Worker __ And(out, dividend, abs_imm - 1);
6400*795d594fSAndroid Build Coastguard Worker __ And(temp, temp, abs_imm - 1);
6401*795d594fSAndroid Build Coastguard Worker __ Csneg(out, out, temp, mi);
6402*795d594fSAndroid Build Coastguard Worker }
6403*795d594fSAndroid Build Coastguard Worker }
6404*795d594fSAndroid Build Coastguard Worker }
6405*795d594fSAndroid Build Coastguard Worker
GenerateIntRemForConstDenom(HRem * instruction)6406*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntRemForConstDenom(HRem *instruction) {
6407*795d594fSAndroid Build Coastguard Worker int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
6408*795d594fSAndroid Build Coastguard Worker
6409*795d594fSAndroid Build Coastguard Worker if (imm == 0) {
6410*795d594fSAndroid Build Coastguard Worker // Do not generate anything.
6411*795d594fSAndroid Build Coastguard Worker // DivZeroCheck would prevent any code to be executed.
6412*795d594fSAndroid Build Coastguard Worker return;
6413*795d594fSAndroid Build Coastguard Worker }
6414*795d594fSAndroid Build Coastguard Worker
6415*795d594fSAndroid Build Coastguard Worker if (IsPowerOfTwo(AbsOrMin(imm))) {
6416*795d594fSAndroid Build Coastguard Worker // Cases imm == -1 or imm == 1 are handled in constant folding by
6417*795d594fSAndroid Build Coastguard Worker // InstructionWithAbsorbingInputSimplifier.
6418*795d594fSAndroid Build Coastguard Worker // If the cases have survided till code generation they are handled in
6419*795d594fSAndroid Build Coastguard Worker // GenerateIntRemForPower2Denom becauses -1 and 1 are the power of 2 (2^0).
6420*795d594fSAndroid Build Coastguard Worker // The correct code is generated for them, just more instructions.
6421*795d594fSAndroid Build Coastguard Worker GenerateIntRemForPower2Denom(instruction);
6422*795d594fSAndroid Build Coastguard Worker } else {
6423*795d594fSAndroid Build Coastguard Worker DCHECK(imm < -2 || imm > 2) << imm;
6424*795d594fSAndroid Build Coastguard Worker GenerateDivRemWithAnyConstant(instruction, imm);
6425*795d594fSAndroid Build Coastguard Worker }
6426*795d594fSAndroid Build Coastguard Worker }
6427*795d594fSAndroid Build Coastguard Worker
GenerateIntRem(HRem * instruction)6428*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateIntRem(HRem* instruction) {
6429*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsIntOrLongType(instruction->GetResultType()))
6430*795d594fSAndroid Build Coastguard Worker << instruction->GetResultType();
6431*795d594fSAndroid Build Coastguard Worker
6432*795d594fSAndroid Build Coastguard Worker if (instruction->GetLocations()->InAt(1).IsConstant()) {
6433*795d594fSAndroid Build Coastguard Worker GenerateIntRemForConstDenom(instruction);
6434*795d594fSAndroid Build Coastguard Worker } else {
6435*795d594fSAndroid Build Coastguard Worker Register out = OutputRegister(instruction);
6436*795d594fSAndroid Build Coastguard Worker Register dividend = InputRegisterAt(instruction, 0);
6437*795d594fSAndroid Build Coastguard Worker Register divisor = InputRegisterAt(instruction, 1);
6438*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
6439*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireSameSizeAs(out);
6440*795d594fSAndroid Build Coastguard Worker __ Sdiv(temp, dividend, divisor);
6441*795d594fSAndroid Build Coastguard Worker __ Msub(out, temp, divisor, dividend);
6442*795d594fSAndroid Build Coastguard Worker }
6443*795d594fSAndroid Build Coastguard Worker }
6444*795d594fSAndroid Build Coastguard Worker
VisitRem(HRem * rem)6445*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
6446*795d594fSAndroid Build Coastguard Worker DataType::Type type = rem->GetResultType();
6447*795d594fSAndroid Build Coastguard Worker
6448*795d594fSAndroid Build Coastguard Worker switch (type) {
6449*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6450*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
6451*795d594fSAndroid Build Coastguard Worker GenerateIntRem(rem);
6452*795d594fSAndroid Build Coastguard Worker break;
6453*795d594fSAndroid Build Coastguard Worker }
6454*795d594fSAndroid Build Coastguard Worker
6455*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6456*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
6457*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum entrypoint =
6458*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kFloat32) ? kQuickFmodf : kQuickFmod;
6459*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(entrypoint, rem, rem->GetDexPc());
6460*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat32) {
6461*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickFmodf, float, float, float>();
6462*795d594fSAndroid Build Coastguard Worker } else {
6463*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickFmod, double, double, double>();
6464*795d594fSAndroid Build Coastguard Worker }
6465*795d594fSAndroid Build Coastguard Worker break;
6466*795d594fSAndroid Build Coastguard Worker }
6467*795d594fSAndroid Build Coastguard Worker
6468*795d594fSAndroid Build Coastguard Worker default:
6469*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected rem type " << type;
6470*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
6471*795d594fSAndroid Build Coastguard Worker }
6472*795d594fSAndroid Build Coastguard Worker }
6473*795d594fSAndroid Build Coastguard Worker
VisitMin(HMin * min)6474*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMin(HMin* min) {
6475*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(min);
6476*795d594fSAndroid Build Coastguard Worker }
6477*795d594fSAndroid Build Coastguard Worker
VisitMin(HMin * min)6478*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMin(HMin* min) {
6479*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(min);
6480*795d594fSAndroid Build Coastguard Worker }
6481*795d594fSAndroid Build Coastguard Worker
VisitMax(HMax * max)6482*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMax(HMax* max) {
6483*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(max);
6484*795d594fSAndroid Build Coastguard Worker }
6485*795d594fSAndroid Build Coastguard Worker
VisitMax(HMax * max)6486*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMax(HMax* max) {
6487*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(max);
6488*795d594fSAndroid Build Coastguard Worker }
6489*795d594fSAndroid Build Coastguard Worker
VisitAbs(HAbs * abs)6490*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitAbs(HAbs* abs) {
6491*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs);
6492*795d594fSAndroid Build Coastguard Worker switch (abs->GetResultType()) {
6493*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6494*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
6495*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6496*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6497*795d594fSAndroid Build Coastguard Worker break;
6498*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6499*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6500*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
6501*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6502*795d594fSAndroid Build Coastguard Worker break;
6503*795d594fSAndroid Build Coastguard Worker default:
6504*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for abs operation " << abs->GetResultType();
6505*795d594fSAndroid Build Coastguard Worker }
6506*795d594fSAndroid Build Coastguard Worker }
6507*795d594fSAndroid Build Coastguard Worker
VisitAbs(HAbs * abs)6508*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitAbs(HAbs* abs) {
6509*795d594fSAndroid Build Coastguard Worker switch (abs->GetResultType()) {
6510*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
6511*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64: {
6512*795d594fSAndroid Build Coastguard Worker Register in_reg = InputRegisterAt(abs, 0);
6513*795d594fSAndroid Build Coastguard Worker Register out_reg = OutputRegister(abs);
6514*795d594fSAndroid Build Coastguard Worker __ Cmp(in_reg, Operand(0));
6515*795d594fSAndroid Build Coastguard Worker __ Cneg(out_reg, in_reg, lt);
6516*795d594fSAndroid Build Coastguard Worker break;
6517*795d594fSAndroid Build Coastguard Worker }
6518*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6519*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64: {
6520*795d594fSAndroid Build Coastguard Worker VRegister in_reg = InputFPRegisterAt(abs, 0);
6521*795d594fSAndroid Build Coastguard Worker VRegister out_reg = OutputFPRegister(abs);
6522*795d594fSAndroid Build Coastguard Worker __ Fabs(out_reg, in_reg);
6523*795d594fSAndroid Build Coastguard Worker break;
6524*795d594fSAndroid Build Coastguard Worker }
6525*795d594fSAndroid Build Coastguard Worker default:
6526*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type for abs operation " << abs->GetResultType();
6527*795d594fSAndroid Build Coastguard Worker }
6528*795d594fSAndroid Build Coastguard Worker }
6529*795d594fSAndroid Build Coastguard Worker
VisitConstructorFence(HConstructorFence * constructor_fence)6530*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitConstructorFence(HConstructorFence* constructor_fence) {
6531*795d594fSAndroid Build Coastguard Worker constructor_fence->SetLocations(nullptr);
6532*795d594fSAndroid Build Coastguard Worker }
6533*795d594fSAndroid Build Coastguard Worker
VisitConstructorFence(HConstructorFence * constructor_fence)6534*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitConstructorFence(
6535*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] HConstructorFence* constructor_fence) {
6536*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
6537*795d594fSAndroid Build Coastguard Worker }
6538*795d594fSAndroid Build Coastguard Worker
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)6539*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
6540*795d594fSAndroid Build Coastguard Worker memory_barrier->SetLocations(nullptr);
6541*795d594fSAndroid Build Coastguard Worker }
6542*795d594fSAndroid Build Coastguard Worker
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)6543*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
6544*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
6545*795d594fSAndroid Build Coastguard Worker }
6546*795d594fSAndroid Build Coastguard Worker
VisitReturn(HReturn * instruction)6547*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
6548*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6549*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = instruction->InputAt(0)->GetType();
6550*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, ARM64ReturnLocation(return_type));
6551*795d594fSAndroid Build Coastguard Worker }
6552*795d594fSAndroid Build Coastguard Worker
VisitReturn(HReturn * ret)6553*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitReturn(HReturn* ret) {
6554*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsCompilingOsr()) {
6555*795d594fSAndroid Build Coastguard Worker // To simplify callers of an OSR method, we put the return value in both
6556*795d594fSAndroid Build Coastguard Worker // floating point and core register.
6557*795d594fSAndroid Build Coastguard Worker switch (ret->InputAt(0)->GetType()) {
6558*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
6559*795d594fSAndroid Build Coastguard Worker __ Fmov(w0, s0);
6560*795d594fSAndroid Build Coastguard Worker break;
6561*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
6562*795d594fSAndroid Build Coastguard Worker __ Fmov(x0, d0);
6563*795d594fSAndroid Build Coastguard Worker break;
6564*795d594fSAndroid Build Coastguard Worker default:
6565*795d594fSAndroid Build Coastguard Worker break;
6566*795d594fSAndroid Build Coastguard Worker }
6567*795d594fSAndroid Build Coastguard Worker }
6568*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFrameExit();
6569*795d594fSAndroid Build Coastguard Worker }
6570*795d594fSAndroid Build Coastguard Worker
VisitReturnVoid(HReturnVoid * instruction)6571*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
6572*795d594fSAndroid Build Coastguard Worker instruction->SetLocations(nullptr);
6573*795d594fSAndroid Build Coastguard Worker }
6574*795d594fSAndroid Build Coastguard Worker
VisitReturnVoid(HReturnVoid * instruction)6575*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitReturnVoid([[maybe_unused]] HReturnVoid* instruction) {
6576*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFrameExit();
6577*795d594fSAndroid Build Coastguard Worker }
6578*795d594fSAndroid Build Coastguard Worker
VisitRol(HRol * rol)6579*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitRol(HRol* rol) {
6580*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(rol);
6581*795d594fSAndroid Build Coastguard Worker }
6582*795d594fSAndroid Build Coastguard Worker
VisitRol(HRol * rol)6583*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitRol(HRol* rol) {
6584*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(rol);
6585*795d594fSAndroid Build Coastguard Worker }
6586*795d594fSAndroid Build Coastguard Worker
VisitRor(HRor * ror)6587*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitRor(HRor* ror) {
6588*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(ror);
6589*795d594fSAndroid Build Coastguard Worker }
6590*795d594fSAndroid Build Coastguard Worker
VisitRor(HRor * ror)6591*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitRor(HRor* ror) {
6592*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(ror);
6593*795d594fSAndroid Build Coastguard Worker }
6594*795d594fSAndroid Build Coastguard Worker
VisitShl(HShl * shl)6595*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitShl(HShl* shl) {
6596*795d594fSAndroid Build Coastguard Worker HandleShift(shl);
6597*795d594fSAndroid Build Coastguard Worker }
6598*795d594fSAndroid Build Coastguard Worker
VisitShl(HShl * shl)6599*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
6600*795d594fSAndroid Build Coastguard Worker HandleShift(shl);
6601*795d594fSAndroid Build Coastguard Worker }
6602*795d594fSAndroid Build Coastguard Worker
VisitShr(HShr * shr)6603*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitShr(HShr* shr) {
6604*795d594fSAndroid Build Coastguard Worker HandleShift(shr);
6605*795d594fSAndroid Build Coastguard Worker }
6606*795d594fSAndroid Build Coastguard Worker
VisitShr(HShr * shr)6607*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
6608*795d594fSAndroid Build Coastguard Worker HandleShift(shr);
6609*795d594fSAndroid Build Coastguard Worker }
6610*795d594fSAndroid Build Coastguard Worker
VisitSub(HSub * instruction)6611*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitSub(HSub* instruction) {
6612*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6613*795d594fSAndroid Build Coastguard Worker }
6614*795d594fSAndroid Build Coastguard Worker
VisitSub(HSub * instruction)6615*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
6616*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6617*795d594fSAndroid Build Coastguard Worker }
6618*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldGet(HStaticFieldGet * instruction)6619*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6620*795d594fSAndroid Build Coastguard Worker HandleFieldGet(instruction, instruction->GetFieldInfo());
6621*795d594fSAndroid Build Coastguard Worker }
6622*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldGet(HStaticFieldGet * instruction)6623*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6624*795d594fSAndroid Build Coastguard Worker HandleFieldGet(instruction, instruction->GetFieldInfo());
6625*795d594fSAndroid Build Coastguard Worker }
6626*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldSet(HStaticFieldSet * instruction)6627*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6628*795d594fSAndroid Build Coastguard Worker HandleFieldSet(instruction);
6629*795d594fSAndroid Build Coastguard Worker }
6630*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldSet(HStaticFieldSet * instruction)6631*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6632*795d594fSAndroid Build Coastguard Worker HandleFieldSet(instruction,
6633*795d594fSAndroid Build Coastguard Worker instruction->GetFieldInfo(),
6634*795d594fSAndroid Build Coastguard Worker instruction->GetValueCanBeNull(),
6635*795d594fSAndroid Build Coastguard Worker instruction->GetWriteBarrierKind());
6636*795d594fSAndroid Build Coastguard Worker }
6637*795d594fSAndroid Build Coastguard Worker
VisitStringBuilderAppend(HStringBuilderAppend * instruction)6638*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6639*795d594fSAndroid Build Coastguard Worker codegen_->CreateStringBuilderAppendLocations(instruction, LocationFrom(x0));
6640*795d594fSAndroid Build Coastguard Worker }
6641*795d594fSAndroid Build Coastguard Worker
VisitStringBuilderAppend(HStringBuilderAppend * instruction)6642*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6643*795d594fSAndroid Build Coastguard Worker __ Mov(w0, instruction->GetFormat()->GetValue());
6644*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickStringBuilderAppend, instruction, instruction->GetDexPc());
6645*795d594fSAndroid Build Coastguard Worker }
6646*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)6647*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitUnresolvedInstanceFieldGet(
6648*795d594fSAndroid Build Coastguard Worker HUnresolvedInstanceFieldGet* instruction) {
6649*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6650*795d594fSAndroid Build Coastguard Worker codegen_->CreateUnresolvedFieldLocationSummary(
6651*795d594fSAndroid Build Coastguard Worker instruction, instruction->GetFieldType(), calling_convention);
6652*795d594fSAndroid Build Coastguard Worker }
6653*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)6654*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitUnresolvedInstanceFieldGet(
6655*795d594fSAndroid Build Coastguard Worker HUnresolvedInstanceFieldGet* instruction) {
6656*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6657*795d594fSAndroid Build Coastguard Worker codegen_->GenerateUnresolvedFieldAccess(instruction,
6658*795d594fSAndroid Build Coastguard Worker instruction->GetFieldType(),
6659*795d594fSAndroid Build Coastguard Worker instruction->GetFieldIndex(),
6660*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc(),
6661*795d594fSAndroid Build Coastguard Worker calling_convention);
6662*795d594fSAndroid Build Coastguard Worker }
6663*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)6664*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitUnresolvedInstanceFieldSet(
6665*795d594fSAndroid Build Coastguard Worker HUnresolvedInstanceFieldSet* instruction) {
6666*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6667*795d594fSAndroid Build Coastguard Worker codegen_->CreateUnresolvedFieldLocationSummary(
6668*795d594fSAndroid Build Coastguard Worker instruction, instruction->GetFieldType(), calling_convention);
6669*795d594fSAndroid Build Coastguard Worker }
6670*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)6671*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitUnresolvedInstanceFieldSet(
6672*795d594fSAndroid Build Coastguard Worker HUnresolvedInstanceFieldSet* instruction) {
6673*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6674*795d594fSAndroid Build Coastguard Worker codegen_->GenerateUnresolvedFieldAccess(instruction,
6675*795d594fSAndroid Build Coastguard Worker instruction->GetFieldType(),
6676*795d594fSAndroid Build Coastguard Worker instruction->GetFieldIndex(),
6677*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc(),
6678*795d594fSAndroid Build Coastguard Worker calling_convention);
6679*795d594fSAndroid Build Coastguard Worker }
6680*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)6681*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitUnresolvedStaticFieldGet(
6682*795d594fSAndroid Build Coastguard Worker HUnresolvedStaticFieldGet* instruction) {
6683*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6684*795d594fSAndroid Build Coastguard Worker codegen_->CreateUnresolvedFieldLocationSummary(
6685*795d594fSAndroid Build Coastguard Worker instruction, instruction->GetFieldType(), calling_convention);
6686*795d594fSAndroid Build Coastguard Worker }
6687*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)6688*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitUnresolvedStaticFieldGet(
6689*795d594fSAndroid Build Coastguard Worker HUnresolvedStaticFieldGet* instruction) {
6690*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6691*795d594fSAndroid Build Coastguard Worker codegen_->GenerateUnresolvedFieldAccess(instruction,
6692*795d594fSAndroid Build Coastguard Worker instruction->GetFieldType(),
6693*795d594fSAndroid Build Coastguard Worker instruction->GetFieldIndex(),
6694*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc(),
6695*795d594fSAndroid Build Coastguard Worker calling_convention);
6696*795d594fSAndroid Build Coastguard Worker }
6697*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)6698*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitUnresolvedStaticFieldSet(
6699*795d594fSAndroid Build Coastguard Worker HUnresolvedStaticFieldSet* instruction) {
6700*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6701*795d594fSAndroid Build Coastguard Worker codegen_->CreateUnresolvedFieldLocationSummary(
6702*795d594fSAndroid Build Coastguard Worker instruction, instruction->GetFieldType(), calling_convention);
6703*795d594fSAndroid Build Coastguard Worker }
6704*795d594fSAndroid Build Coastguard Worker
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)6705*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitUnresolvedStaticFieldSet(
6706*795d594fSAndroid Build Coastguard Worker HUnresolvedStaticFieldSet* instruction) {
6707*795d594fSAndroid Build Coastguard Worker FieldAccessCallingConventionARM64 calling_convention;
6708*795d594fSAndroid Build Coastguard Worker codegen_->GenerateUnresolvedFieldAccess(instruction,
6709*795d594fSAndroid Build Coastguard Worker instruction->GetFieldType(),
6710*795d594fSAndroid Build Coastguard Worker instruction->GetFieldIndex(),
6711*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc(),
6712*795d594fSAndroid Build Coastguard Worker calling_convention);
6713*795d594fSAndroid Build Coastguard Worker }
6714*795d594fSAndroid Build Coastguard Worker
VisitSuspendCheck(HSuspendCheck * instruction)6715*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
6716*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6717*795d594fSAndroid Build Coastguard Worker instruction, LocationSummary::kCallOnSlowPath);
6718*795d594fSAndroid Build Coastguard Worker // In suspend check slow path, usually there are no caller-save registers at all.
6719*795d594fSAndroid Build Coastguard Worker // If SIMD instructions are present, however, we force spilling all live SIMD
6720*795d594fSAndroid Build Coastguard Worker // registers in full width (since the runtime only saves/restores lower part).
6721*795d594fSAndroid Build Coastguard Worker // Note that only a suspend check can see live SIMD registers. In the
6722*795d594fSAndroid Build Coastguard Worker // loop optimization, we make sure this does not happen for any other slow
6723*795d594fSAndroid Build Coastguard Worker // path.
6724*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(
6725*795d594fSAndroid Build Coastguard Worker GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
6726*795d594fSAndroid Build Coastguard Worker }
6727*795d594fSAndroid Build Coastguard Worker
VisitSuspendCheck(HSuspendCheck * instruction)6728*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
6729*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
6730*795d594fSAndroid Build Coastguard Worker if (block->GetLoopInformation() != nullptr) {
6731*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6732*795d594fSAndroid Build Coastguard Worker // The back edge will generate the suspend check.
6733*795d594fSAndroid Build Coastguard Worker return;
6734*795d594fSAndroid Build Coastguard Worker }
6735*795d594fSAndroid Build Coastguard Worker if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6736*795d594fSAndroid Build Coastguard Worker // The goto will generate the suspend check.
6737*795d594fSAndroid Build Coastguard Worker return;
6738*795d594fSAndroid Build Coastguard Worker }
6739*795d594fSAndroid Build Coastguard Worker GenerateSuspendCheck(instruction, nullptr);
6740*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
6741*795d594fSAndroid Build Coastguard Worker }
6742*795d594fSAndroid Build Coastguard Worker
VisitThrow(HThrow * instruction)6743*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
6744*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6745*795d594fSAndroid Build Coastguard Worker instruction, LocationSummary::kCallOnMainOnly);
6746*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
6747*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
6748*795d594fSAndroid Build Coastguard Worker }
6749*795d594fSAndroid Build Coastguard Worker
VisitThrow(HThrow * instruction)6750*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
6751*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
6752*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
6753*795d594fSAndroid Build Coastguard Worker }
6754*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * conversion)6755*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
6756*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
6757*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(conversion, LocationSummary::kNoCall);
6758*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = conversion->GetInputType();
6759*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = conversion->GetResultType();
6760*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
6761*795d594fSAndroid Build Coastguard Worker << input_type << " -> " << result_type;
6762*795d594fSAndroid Build Coastguard Worker if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
6763*795d594fSAndroid Build Coastguard Worker (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
6764*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
6765*795d594fSAndroid Build Coastguard Worker }
6766*795d594fSAndroid Build Coastguard Worker
6767*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(input_type)) {
6768*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
6769*795d594fSAndroid Build Coastguard Worker } else {
6770*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6771*795d594fSAndroid Build Coastguard Worker }
6772*795d594fSAndroid Build Coastguard Worker
6773*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(result_type)) {
6774*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6775*795d594fSAndroid Build Coastguard Worker } else {
6776*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6777*795d594fSAndroid Build Coastguard Worker }
6778*795d594fSAndroid Build Coastguard Worker }
6779*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * conversion)6780*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
6781*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = conversion->GetResultType();
6782*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = conversion->GetInputType();
6783*795d594fSAndroid Build Coastguard Worker
6784*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
6785*795d594fSAndroid Build Coastguard Worker << input_type << " -> " << result_type;
6786*795d594fSAndroid Build Coastguard Worker
6787*795d594fSAndroid Build Coastguard Worker if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
6788*795d594fSAndroid Build Coastguard Worker int result_size = DataType::Size(result_type);
6789*795d594fSAndroid Build Coastguard Worker int input_size = DataType::Size(input_type);
6790*795d594fSAndroid Build Coastguard Worker int min_size = std::min(result_size, input_size);
6791*795d594fSAndroid Build Coastguard Worker Register output = OutputRegister(conversion);
6792*795d594fSAndroid Build Coastguard Worker Register source = InputRegisterAt(conversion, 0);
6793*795d594fSAndroid Build Coastguard Worker if (result_type == DataType::Type::kInt32 && input_type == DataType::Type::kInt64) {
6794*795d594fSAndroid Build Coastguard Worker // 'int' values are used directly as W registers, discarding the top
6795*795d594fSAndroid Build Coastguard Worker // bits, so we don't need to sign-extend and can just perform a move.
6796*795d594fSAndroid Build Coastguard Worker // We do not pass the `kDiscardForSameWReg` argument to force clearing the
6797*795d594fSAndroid Build Coastguard Worker // top 32 bits of the target register. We theoretically could leave those
6798*795d594fSAndroid Build Coastguard Worker // bits unchanged, but we would have to make sure that no code uses a
6799*795d594fSAndroid Build Coastguard Worker // 32bit input value as a 64bit value assuming that the top 32 bits are
6800*795d594fSAndroid Build Coastguard Worker // zero.
6801*795d594fSAndroid Build Coastguard Worker __ Mov(output.W(), source.W());
6802*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsUnsignedType(result_type) ||
6803*795d594fSAndroid Build Coastguard Worker (DataType::IsUnsignedType(input_type) && input_size < result_size)) {
6804*795d594fSAndroid Build Coastguard Worker __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, result_size * kBitsPerByte);
6805*795d594fSAndroid Build Coastguard Worker } else {
6806*795d594fSAndroid Build Coastguard Worker __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
6807*795d594fSAndroid Build Coastguard Worker }
6808*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
6809*795d594fSAndroid Build Coastguard Worker __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
6810*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
6811*795d594fSAndroid Build Coastguard Worker CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
6812*795d594fSAndroid Build Coastguard Worker __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
6813*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsFloatingPointType(result_type) &&
6814*795d594fSAndroid Build Coastguard Worker DataType::IsFloatingPointType(input_type)) {
6815*795d594fSAndroid Build Coastguard Worker __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
6816*795d594fSAndroid Build Coastguard Worker } else {
6817*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
6818*795d594fSAndroid Build Coastguard Worker << " to " << result_type;
6819*795d594fSAndroid Build Coastguard Worker }
6820*795d594fSAndroid Build Coastguard Worker }
6821*795d594fSAndroid Build Coastguard Worker
VisitUShr(HUShr * ushr)6822*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
6823*795d594fSAndroid Build Coastguard Worker HandleShift(ushr);
6824*795d594fSAndroid Build Coastguard Worker }
6825*795d594fSAndroid Build Coastguard Worker
VisitUShr(HUShr * ushr)6826*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
6827*795d594fSAndroid Build Coastguard Worker HandleShift(ushr);
6828*795d594fSAndroid Build Coastguard Worker }
6829*795d594fSAndroid Build Coastguard Worker
VisitXor(HXor * instruction)6830*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitXor(HXor* instruction) {
6831*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6832*795d594fSAndroid Build Coastguard Worker }
6833*795d594fSAndroid Build Coastguard Worker
VisitXor(HXor * instruction)6834*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
6835*795d594fSAndroid Build Coastguard Worker HandleBinaryOp(instruction);
6836*795d594fSAndroid Build Coastguard Worker }
6837*795d594fSAndroid Build Coastguard Worker
VisitBoundType(HBoundType * instruction)6838*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitBoundType([[maybe_unused]] HBoundType* instruction) {
6839*795d594fSAndroid Build Coastguard Worker // Nothing to do, this should be removed during prepare for register allocator.
6840*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
6841*795d594fSAndroid Build Coastguard Worker }
6842*795d594fSAndroid Build Coastguard Worker
VisitBoundType(HBoundType * instruction)6843*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitBoundType([[maybe_unused]] HBoundType* instruction) {
6844*795d594fSAndroid Build Coastguard Worker // Nothing to do, this should be removed during prepare for register allocator.
6845*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
6846*795d594fSAndroid Build Coastguard Worker }
6847*795d594fSAndroid Build Coastguard Worker
6848*795d594fSAndroid Build Coastguard Worker // Simple implementation of packed switch - generate cascaded compare/jumps.
VisitPackedSwitch(HPackedSwitch * switch_instr)6849*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6850*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
6851*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6852*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
6853*795d594fSAndroid Build Coastguard Worker }
6854*795d594fSAndroid Build Coastguard Worker
VisitPackedSwitch(HPackedSwitch * switch_instr)6855*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6856*795d594fSAndroid Build Coastguard Worker int32_t lower_bound = switch_instr->GetStartValue();
6857*795d594fSAndroid Build Coastguard Worker uint32_t num_entries = switch_instr->GetNumEntries();
6858*795d594fSAndroid Build Coastguard Worker Register value_reg = InputRegisterAt(switch_instr, 0);
6859*795d594fSAndroid Build Coastguard Worker HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6860*795d594fSAndroid Build Coastguard Worker
6861*795d594fSAndroid Build Coastguard Worker if (num_entries <= kPackedSwitchCompareJumpThreshold) {
6862*795d594fSAndroid Build Coastguard Worker // Create a series of compare/jumps.
6863*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
6864*795d594fSAndroid Build Coastguard Worker Register temp = temps.AcquireW();
6865*795d594fSAndroid Build Coastguard Worker __ Subs(temp, value_reg, Operand(lower_bound));
6866*795d594fSAndroid Build Coastguard Worker
6867*795d594fSAndroid Build Coastguard Worker const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6868*795d594fSAndroid Build Coastguard Worker // Jump to successors[0] if value == lower_bound.
6869*795d594fSAndroid Build Coastguard Worker __ B(eq, codegen_->GetLabelOf(successors[0]));
6870*795d594fSAndroid Build Coastguard Worker int32_t last_index = 0;
6871*795d594fSAndroid Build Coastguard Worker for (; num_entries - last_index > 2; last_index += 2) {
6872*795d594fSAndroid Build Coastguard Worker __ Subs(temp, temp, Operand(2));
6873*795d594fSAndroid Build Coastguard Worker // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6874*795d594fSAndroid Build Coastguard Worker __ B(lo, codegen_->GetLabelOf(successors[last_index + 1]));
6875*795d594fSAndroid Build Coastguard Worker // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6876*795d594fSAndroid Build Coastguard Worker __ B(eq, codegen_->GetLabelOf(successors[last_index + 2]));
6877*795d594fSAndroid Build Coastguard Worker }
6878*795d594fSAndroid Build Coastguard Worker if (num_entries - last_index == 2) {
6879*795d594fSAndroid Build Coastguard Worker // The last missing case_value.
6880*795d594fSAndroid Build Coastguard Worker __ Cmp(temp, Operand(1));
6881*795d594fSAndroid Build Coastguard Worker __ B(eq, codegen_->GetLabelOf(successors[last_index + 1]));
6882*795d594fSAndroid Build Coastguard Worker }
6883*795d594fSAndroid Build Coastguard Worker
6884*795d594fSAndroid Build Coastguard Worker // And the default for any other value.
6885*795d594fSAndroid Build Coastguard Worker if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6886*795d594fSAndroid Build Coastguard Worker __ B(codegen_->GetLabelOf(default_block));
6887*795d594fSAndroid Build Coastguard Worker }
6888*795d594fSAndroid Build Coastguard Worker } else {
6889*795d594fSAndroid Build Coastguard Worker JumpTableARM64* jump_table = codegen_->CreateJumpTable(switch_instr);
6890*795d594fSAndroid Build Coastguard Worker
6891*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
6892*795d594fSAndroid Build Coastguard Worker
6893*795d594fSAndroid Build Coastguard Worker // Below instructions should use at most one blocked register. Since there are two blocked
6894*795d594fSAndroid Build Coastguard Worker // registers, we are free to block one.
6895*795d594fSAndroid Build Coastguard Worker Register temp_w = temps.AcquireW();
6896*795d594fSAndroid Build Coastguard Worker Register index;
6897*795d594fSAndroid Build Coastguard Worker // Remove the bias.
6898*795d594fSAndroid Build Coastguard Worker if (lower_bound != 0) {
6899*795d594fSAndroid Build Coastguard Worker index = temp_w;
6900*795d594fSAndroid Build Coastguard Worker __ Sub(index, value_reg, Operand(lower_bound));
6901*795d594fSAndroid Build Coastguard Worker } else {
6902*795d594fSAndroid Build Coastguard Worker index = value_reg;
6903*795d594fSAndroid Build Coastguard Worker }
6904*795d594fSAndroid Build Coastguard Worker
6905*795d594fSAndroid Build Coastguard Worker // Jump to default block if index is out of the range.
6906*795d594fSAndroid Build Coastguard Worker __ Cmp(index, Operand(num_entries));
6907*795d594fSAndroid Build Coastguard Worker __ B(hs, codegen_->GetLabelOf(default_block));
6908*795d594fSAndroid Build Coastguard Worker
6909*795d594fSAndroid Build Coastguard Worker // In current VIXL implementation, it won't require any blocked registers to encode the
6910*795d594fSAndroid Build Coastguard Worker // immediate value for Adr. So we are free to use both VIXL blocked registers to reduce the
6911*795d594fSAndroid Build Coastguard Worker // register pressure.
6912*795d594fSAndroid Build Coastguard Worker Register table_base = temps.AcquireX();
6913*795d594fSAndroid Build Coastguard Worker
6914*795d594fSAndroid Build Coastguard Worker const size_t jump_size = switch_instr->GetNumEntries() * sizeof(int32_t);
6915*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope scope(codegen_->GetVIXLAssembler(),
6916*795d594fSAndroid Build Coastguard Worker kInstructionSize * 4 + jump_size,
6917*795d594fSAndroid Build Coastguard Worker CodeBufferCheckScope::kExactSize);
6918*795d594fSAndroid Build Coastguard Worker
6919*795d594fSAndroid Build Coastguard Worker // Load jump offset from the table.
6920*795d594fSAndroid Build Coastguard Worker // Note: the table start address is always in range as the table is emitted immediately
6921*795d594fSAndroid Build Coastguard Worker // after these 4 instructions.
6922*795d594fSAndroid Build Coastguard Worker __ adr(table_base, jump_table->GetTableStartLabel());
6923*795d594fSAndroid Build Coastguard Worker Register jump_offset = temp_w;
6924*795d594fSAndroid Build Coastguard Worker __ ldr(jump_offset, MemOperand(table_base, index, UXTW, 2));
6925*795d594fSAndroid Build Coastguard Worker
6926*795d594fSAndroid Build Coastguard Worker // Jump to target block by branching to table_base(pc related) + offset.
6927*795d594fSAndroid Build Coastguard Worker Register target_address = table_base;
6928*795d594fSAndroid Build Coastguard Worker __ add(target_address, table_base, Operand(jump_offset, SXTW));
6929*795d594fSAndroid Build Coastguard Worker __ br(target_address);
6930*795d594fSAndroid Build Coastguard Worker
6931*795d594fSAndroid Build Coastguard Worker jump_table->EmitTable(codegen_);
6932*795d594fSAndroid Build Coastguard Worker }
6933*795d594fSAndroid Build Coastguard Worker }
6934*795d594fSAndroid Build Coastguard Worker
GenerateReferenceLoadOneRegister(HInstruction * instruction,Location out,uint32_t offset,Location maybe_temp,ReadBarrierOption read_barrier_option)6935*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateReferenceLoadOneRegister(
6936*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
6937*795d594fSAndroid Build Coastguard Worker Location out,
6938*795d594fSAndroid Build Coastguard Worker uint32_t offset,
6939*795d594fSAndroid Build Coastguard Worker Location maybe_temp,
6940*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option) {
6941*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Type::kReference;
6942*795d594fSAndroid Build Coastguard Worker Register out_reg = RegisterFrom(out, type);
6943*795d594fSAndroid Build Coastguard Worker if (read_barrier_option == kWithReadBarrier) {
6944*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->EmitReadBarrier());
6945*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
6946*795d594fSAndroid Build Coastguard Worker // Load with fast path based Baker's read barrier.
6947*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(out + offset)
6948*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6949*795d594fSAndroid Build Coastguard Worker out,
6950*795d594fSAndroid Build Coastguard Worker out_reg,
6951*795d594fSAndroid Build Coastguard Worker offset,
6952*795d594fSAndroid Build Coastguard Worker maybe_temp,
6953*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ false,
6954*795d594fSAndroid Build Coastguard Worker /* use_load_acquire= */ false);
6955*795d594fSAndroid Build Coastguard Worker } else {
6956*795d594fSAndroid Build Coastguard Worker // Load with slow path based read barrier.
6957*795d594fSAndroid Build Coastguard Worker // Save the value of `out` into `maybe_temp` before overwriting it
6958*795d594fSAndroid Build Coastguard Worker // in the following move operation, as we will need it for the
6959*795d594fSAndroid Build Coastguard Worker // read barrier below.
6960*795d594fSAndroid Build Coastguard Worker Register temp_reg = RegisterFrom(maybe_temp, type);
6961*795d594fSAndroid Build Coastguard Worker __ Mov(temp_reg, out_reg);
6962*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(out + offset)
6963*795d594fSAndroid Build Coastguard Worker __ Ldr(out_reg, HeapOperand(out_reg, offset));
6964*795d594fSAndroid Build Coastguard Worker codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6965*795d594fSAndroid Build Coastguard Worker }
6966*795d594fSAndroid Build Coastguard Worker } else {
6967*795d594fSAndroid Build Coastguard Worker // Plain load with no read barrier.
6968*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(out + offset)
6969*795d594fSAndroid Build Coastguard Worker __ Ldr(out_reg, HeapOperand(out_reg, offset));
6970*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(out_reg);
6971*795d594fSAndroid Build Coastguard Worker }
6972*795d594fSAndroid Build Coastguard Worker }
6973*795d594fSAndroid Build Coastguard Worker
GenerateReferenceLoadTwoRegisters(HInstruction * instruction,Location out,Location obj,uint32_t offset,Location maybe_temp,ReadBarrierOption read_barrier_option)6974*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::GenerateReferenceLoadTwoRegisters(
6975*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
6976*795d594fSAndroid Build Coastguard Worker Location out,
6977*795d594fSAndroid Build Coastguard Worker Location obj,
6978*795d594fSAndroid Build Coastguard Worker uint32_t offset,
6979*795d594fSAndroid Build Coastguard Worker Location maybe_temp,
6980*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option) {
6981*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Type::kReference;
6982*795d594fSAndroid Build Coastguard Worker Register out_reg = RegisterFrom(out, type);
6983*795d594fSAndroid Build Coastguard Worker Register obj_reg = RegisterFrom(obj, type);
6984*795d594fSAndroid Build Coastguard Worker if (read_barrier_option == kWithReadBarrier) {
6985*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_->EmitReadBarrier());
6986*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
6987*795d594fSAndroid Build Coastguard Worker // Load with fast path based Baker's read barrier.
6988*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(obj + offset)
6989*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6990*795d594fSAndroid Build Coastguard Worker out,
6991*795d594fSAndroid Build Coastguard Worker obj_reg,
6992*795d594fSAndroid Build Coastguard Worker offset,
6993*795d594fSAndroid Build Coastguard Worker maybe_temp,
6994*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ false,
6995*795d594fSAndroid Build Coastguard Worker /* use_load_acquire= */ false);
6996*795d594fSAndroid Build Coastguard Worker } else {
6997*795d594fSAndroid Build Coastguard Worker // Load with slow path based read barrier.
6998*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(obj + offset)
6999*795d594fSAndroid Build Coastguard Worker __ Ldr(out_reg, HeapOperand(obj_reg, offset));
7000*795d594fSAndroid Build Coastguard Worker codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
7001*795d594fSAndroid Build Coastguard Worker }
7002*795d594fSAndroid Build Coastguard Worker } else {
7003*795d594fSAndroid Build Coastguard Worker // Plain load with no read barrier.
7004*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Object> */ out = *(obj + offset)
7005*795d594fSAndroid Build Coastguard Worker __ Ldr(out_reg, HeapOperand(obj_reg, offset));
7006*795d594fSAndroid Build Coastguard Worker GetAssembler()->MaybeUnpoisonHeapReference(out_reg);
7007*795d594fSAndroid Build Coastguard Worker }
7008*795d594fSAndroid Build Coastguard Worker }
7009*795d594fSAndroid Build Coastguard Worker
GenerateGcRootFieldLoad(HInstruction * instruction,Location root,Register obj,uint32_t offset,vixl::aarch64::Label * fixup_label,ReadBarrierOption read_barrier_option)7010*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateGcRootFieldLoad(
7011*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
7012*795d594fSAndroid Build Coastguard Worker Location root,
7013*795d594fSAndroid Build Coastguard Worker Register obj,
7014*795d594fSAndroid Build Coastguard Worker uint32_t offset,
7015*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* fixup_label,
7016*795d594fSAndroid Build Coastguard Worker ReadBarrierOption read_barrier_option) {
7017*795d594fSAndroid Build Coastguard Worker DCHECK(fixup_label == nullptr || offset == 0u);
7018*795d594fSAndroid Build Coastguard Worker Register root_reg = RegisterFrom(root, DataType::Type::kReference);
7019*795d594fSAndroid Build Coastguard Worker if (read_barrier_option == kWithReadBarrier) {
7020*795d594fSAndroid Build Coastguard Worker DCHECK(EmitReadBarrier());
7021*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
7022*795d594fSAndroid Build Coastguard Worker // Fast path implementation of art::ReadBarrier::BarrierForRoot when
7023*795d594fSAndroid Build Coastguard Worker // Baker's read barrier are used.
7024*795d594fSAndroid Build Coastguard Worker
7025*795d594fSAndroid Build Coastguard Worker // Query `art::Thread::Current()->GetIsGcMarking()` (stored in
7026*795d594fSAndroid Build Coastguard Worker // the Marking Register) to decide whether we need to enter
7027*795d594fSAndroid Build Coastguard Worker // the slow path to mark the GC root.
7028*795d594fSAndroid Build Coastguard Worker //
7029*795d594fSAndroid Build Coastguard Worker // We use shared thunks for the slow path; shared within the method
7030*795d594fSAndroid Build Coastguard Worker // for JIT, across methods for AOT. That thunk checks the reference
7031*795d594fSAndroid Build Coastguard Worker // and jumps to the entrypoint if needed.
7032*795d594fSAndroid Build Coastguard Worker //
7033*795d594fSAndroid Build Coastguard Worker // lr = &return_address;
7034*795d594fSAndroid Build Coastguard Worker // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
7035*795d594fSAndroid Build Coastguard Worker // if (mr) { // Thread::Current()->GetIsGcMarking()
7036*795d594fSAndroid Build Coastguard Worker // goto gc_root_thunk<root_reg>(lr)
7037*795d594fSAndroid Build Coastguard Worker // }
7038*795d594fSAndroid Build Coastguard Worker // return_address:
7039*795d594fSAndroid Build Coastguard Worker
7040*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
7041*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip0));
7042*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip1));
7043*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7044*795d594fSAndroid Build Coastguard Worker uint32_t custom_data = EncodeBakerReadBarrierGcRootData(root_reg.GetCode());
7045*795d594fSAndroid Build Coastguard Worker
7046*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope guard(GetVIXLAssembler(), 3 * vixl::aarch64::kInstructionSize);
7047*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_address;
7048*795d594fSAndroid Build Coastguard Worker __ adr(lr, &return_address);
7049*795d594fSAndroid Build Coastguard Worker if (fixup_label != nullptr) {
7050*795d594fSAndroid Build Coastguard Worker __ bind(fixup_label);
7051*795d594fSAndroid Build Coastguard Worker }
7052*795d594fSAndroid Build Coastguard Worker static_assert(BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET == -8,
7053*795d594fSAndroid Build Coastguard Worker "GC root LDR must be 2 instructions (8B) before the return address label.");
7054*795d594fSAndroid Build Coastguard Worker __ ldr(root_reg, MemOperand(obj.X(), offset));
7055*795d594fSAndroid Build Coastguard Worker EmitBakerReadBarrierCbnz(custom_data);
7056*795d594fSAndroid Build Coastguard Worker __ bind(&return_address);
7057*795d594fSAndroid Build Coastguard Worker } else {
7058*795d594fSAndroid Build Coastguard Worker // GC root loaded through a slow path for read barriers other
7059*795d594fSAndroid Build Coastguard Worker // than Baker's.
7060*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::Object>* */ root = obj + offset
7061*795d594fSAndroid Build Coastguard Worker if (fixup_label == nullptr) {
7062*795d594fSAndroid Build Coastguard Worker __ Add(root_reg.X(), obj.X(), offset);
7063*795d594fSAndroid Build Coastguard Worker } else {
7064*795d594fSAndroid Build Coastguard Worker EmitAddPlaceholder(fixup_label, root_reg.X(), obj.X());
7065*795d594fSAndroid Build Coastguard Worker }
7066*795d594fSAndroid Build Coastguard Worker // /* mirror::Object* */ root = root->Read()
7067*795d594fSAndroid Build Coastguard Worker GenerateReadBarrierForRootSlow(instruction, root, root);
7068*795d594fSAndroid Build Coastguard Worker }
7069*795d594fSAndroid Build Coastguard Worker } else {
7070*795d594fSAndroid Build Coastguard Worker // Plain GC root load with no read barrier.
7071*795d594fSAndroid Build Coastguard Worker // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7072*795d594fSAndroid Build Coastguard Worker if (fixup_label == nullptr) {
7073*795d594fSAndroid Build Coastguard Worker __ Ldr(root_reg, MemOperand(obj, offset));
7074*795d594fSAndroid Build Coastguard Worker } else {
7075*795d594fSAndroid Build Coastguard Worker EmitLdrOffsetPlaceholder(fixup_label, root_reg, obj.X());
7076*795d594fSAndroid Build Coastguard Worker }
7077*795d594fSAndroid Build Coastguard Worker // Note that GC roots are not affected by heap poisoning, thus we
7078*795d594fSAndroid Build Coastguard Worker // do not have to unpoison `root_reg` here.
7079*795d594fSAndroid Build Coastguard Worker }
7080*795d594fSAndroid Build Coastguard Worker MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__);
7081*795d594fSAndroid Build Coastguard Worker }
7082*795d594fSAndroid Build Coastguard Worker
GenerateIntrinsicMoveWithBakerReadBarrier(vixl::aarch64::Register marked_old_value,vixl::aarch64::Register old_value)7083*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateIntrinsicMoveWithBakerReadBarrier(
7084*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register marked_old_value,
7085*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register old_value) {
7086*795d594fSAndroid Build Coastguard Worker DCHECK(EmitBakerReadBarrier());
7087*795d594fSAndroid Build Coastguard Worker
7088*795d594fSAndroid Build Coastguard Worker // Similar to the Baker RB path in GenerateGcRootFieldLoad(), with a MOV instead of LDR.
7089*795d594fSAndroid Build Coastguard Worker uint32_t custom_data = EncodeBakerReadBarrierGcRootData(marked_old_value.GetCode());
7090*795d594fSAndroid Build Coastguard Worker
7091*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope guard(GetVIXLAssembler(), 3 * vixl::aarch64::kInstructionSize);
7092*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_address;
7093*795d594fSAndroid Build Coastguard Worker __ adr(lr, &return_address);
7094*795d594fSAndroid Build Coastguard Worker static_assert(BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET == -8,
7095*795d594fSAndroid Build Coastguard Worker "GC root LDR must be 2 instructions (8B) before the return address label.");
7096*795d594fSAndroid Build Coastguard Worker __ mov(marked_old_value, old_value);
7097*795d594fSAndroid Build Coastguard Worker EmitBakerReadBarrierCbnz(custom_data);
7098*795d594fSAndroid Build Coastguard Worker __ bind(&return_address);
7099*795d594fSAndroid Build Coastguard Worker }
7100*795d594fSAndroid Build Coastguard Worker
GenerateFieldLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,vixl::aarch64::Register obj,const vixl::aarch64::MemOperand & src,bool needs_null_check,bool use_load_acquire)7101*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7102*795d594fSAndroid Build Coastguard Worker Location ref,
7103*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register obj,
7104*795d594fSAndroid Build Coastguard Worker const vixl::aarch64::MemOperand& src,
7105*795d594fSAndroid Build Coastguard Worker bool needs_null_check,
7106*795d594fSAndroid Build Coastguard Worker bool use_load_acquire) {
7107*795d594fSAndroid Build Coastguard Worker DCHECK(EmitBakerReadBarrier());
7108*795d594fSAndroid Build Coastguard Worker
7109*795d594fSAndroid Build Coastguard Worker // Query `art::Thread::Current()->GetIsGcMarking()` (stored in the
7110*795d594fSAndroid Build Coastguard Worker // Marking Register) to decide whether we need to enter the slow
7111*795d594fSAndroid Build Coastguard Worker // path to mark the reference. Then, in the slow path, check the
7112*795d594fSAndroid Build Coastguard Worker // gray bit in the lock word of the reference's holder (`obj`) to
7113*795d594fSAndroid Build Coastguard Worker // decide whether to mark `ref` or not.
7114*795d594fSAndroid Build Coastguard Worker //
7115*795d594fSAndroid Build Coastguard Worker // We use shared thunks for the slow path; shared within the method
7116*795d594fSAndroid Build Coastguard Worker // for JIT, across methods for AOT. That thunk checks the holder
7117*795d594fSAndroid Build Coastguard Worker // and jumps to the entrypoint if needed. If the holder is not gray,
7118*795d594fSAndroid Build Coastguard Worker // it creates a fake dependency and returns to the LDR instruction.
7119*795d594fSAndroid Build Coastguard Worker //
7120*795d594fSAndroid Build Coastguard Worker // lr = &gray_return_address;
7121*795d594fSAndroid Build Coastguard Worker // if (mr) { // Thread::Current()->GetIsGcMarking()
7122*795d594fSAndroid Build Coastguard Worker // goto field_thunk<holder_reg, base_reg, use_load_acquire>(lr)
7123*795d594fSAndroid Build Coastguard Worker // }
7124*795d594fSAndroid Build Coastguard Worker // not_gray_return_address:
7125*795d594fSAndroid Build Coastguard Worker // // Original reference load. If the offset is too large to fit
7126*795d594fSAndroid Build Coastguard Worker // // into LDR, we use an adjusted base register here.
7127*795d594fSAndroid Build Coastguard Worker // HeapReference<mirror::Object> reference = *(obj+offset);
7128*795d594fSAndroid Build Coastguard Worker // gray_return_address:
7129*795d594fSAndroid Build Coastguard Worker
7130*795d594fSAndroid Build Coastguard Worker DCHECK(src.GetAddrMode() == vixl::aarch64::Offset);
7131*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(src.GetOffset(), sizeof(mirror::HeapReference<mirror::Object>));
7132*795d594fSAndroid Build Coastguard Worker
7133*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
7134*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip0));
7135*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip1));
7136*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7137*795d594fSAndroid Build Coastguard Worker uint32_t custom_data = use_load_acquire
7138*795d594fSAndroid Build Coastguard Worker ? EncodeBakerReadBarrierAcquireData(src.GetBaseRegister().GetCode(), obj.GetCode())
7139*795d594fSAndroid Build Coastguard Worker : EncodeBakerReadBarrierFieldData(src.GetBaseRegister().GetCode(), obj.GetCode());
7140*795d594fSAndroid Build Coastguard Worker
7141*795d594fSAndroid Build Coastguard Worker {
7142*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope guard(GetVIXLAssembler(),
7143*795d594fSAndroid Build Coastguard Worker (kPoisonHeapReferences ? 4u : 3u) * vixl::aarch64::kInstructionSize);
7144*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_address;
7145*795d594fSAndroid Build Coastguard Worker __ adr(lr, &return_address);
7146*795d594fSAndroid Build Coastguard Worker EmitBakerReadBarrierCbnz(custom_data);
7147*795d594fSAndroid Build Coastguard Worker static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
7148*795d594fSAndroid Build Coastguard Worker "Field LDR must be 1 instruction (4B) before the return address label; "
7149*795d594fSAndroid Build Coastguard Worker " 2 instructions (8B) for heap poisoning.");
7150*795d594fSAndroid Build Coastguard Worker Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
7151*795d594fSAndroid Build Coastguard Worker if (use_load_acquire) {
7152*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(src.GetOffset(), 0);
7153*795d594fSAndroid Build Coastguard Worker __ ldar(ref_reg, src);
7154*795d594fSAndroid Build Coastguard Worker } else {
7155*795d594fSAndroid Build Coastguard Worker __ ldr(ref_reg, src);
7156*795d594fSAndroid Build Coastguard Worker }
7157*795d594fSAndroid Build Coastguard Worker if (needs_null_check) {
7158*795d594fSAndroid Build Coastguard Worker MaybeRecordImplicitNullCheck(instruction);
7159*795d594fSAndroid Build Coastguard Worker }
7160*795d594fSAndroid Build Coastguard Worker // Unpoison the reference explicitly if needed. MaybeUnpoisonHeapReference() uses
7161*795d594fSAndroid Build Coastguard Worker // macro instructions disallowed in ExactAssemblyScope.
7162*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences) {
7163*795d594fSAndroid Build Coastguard Worker __ neg(ref_reg, Operand(ref_reg));
7164*795d594fSAndroid Build Coastguard Worker }
7165*795d594fSAndroid Build Coastguard Worker __ bind(&return_address);
7166*795d594fSAndroid Build Coastguard Worker }
7167*795d594fSAndroid Build Coastguard Worker MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__, /* temp_loc= */ LocationFrom(ip1));
7168*795d594fSAndroid Build Coastguard Worker }
7169*795d594fSAndroid Build Coastguard Worker
GenerateFieldLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t offset,Location maybe_temp,bool needs_null_check,bool use_load_acquire)7170*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7171*795d594fSAndroid Build Coastguard Worker Location ref,
7172*795d594fSAndroid Build Coastguard Worker Register obj,
7173*795d594fSAndroid Build Coastguard Worker uint32_t offset,
7174*795d594fSAndroid Build Coastguard Worker Location maybe_temp,
7175*795d594fSAndroid Build Coastguard Worker bool needs_null_check,
7176*795d594fSAndroid Build Coastguard Worker bool use_load_acquire) {
7177*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>));
7178*795d594fSAndroid Build Coastguard Worker Register base = obj;
7179*795d594fSAndroid Build Coastguard Worker if (use_load_acquire) {
7180*795d594fSAndroid Build Coastguard Worker DCHECK(maybe_temp.IsRegister());
7181*795d594fSAndroid Build Coastguard Worker base = WRegisterFrom(maybe_temp);
7182*795d594fSAndroid Build Coastguard Worker __ Add(base, obj, offset);
7183*795d594fSAndroid Build Coastguard Worker offset = 0u;
7184*795d594fSAndroid Build Coastguard Worker } else if (offset >= kReferenceLoadMinFarOffset) {
7185*795d594fSAndroid Build Coastguard Worker DCHECK(maybe_temp.IsRegister());
7186*795d594fSAndroid Build Coastguard Worker base = WRegisterFrom(maybe_temp);
7187*795d594fSAndroid Build Coastguard Worker static_assert(IsPowerOfTwo(kReferenceLoadMinFarOffset), "Expecting a power of 2.");
7188*795d594fSAndroid Build Coastguard Worker __ Add(base, obj, Operand(offset & ~(kReferenceLoadMinFarOffset - 1u)));
7189*795d594fSAndroid Build Coastguard Worker offset &= (kReferenceLoadMinFarOffset - 1u);
7190*795d594fSAndroid Build Coastguard Worker }
7191*795d594fSAndroid Build Coastguard Worker MemOperand src(base.X(), offset);
7192*795d594fSAndroid Build Coastguard Worker GenerateFieldLoadWithBakerReadBarrier(
7193*795d594fSAndroid Build Coastguard Worker instruction, ref, obj, src, needs_null_check, use_load_acquire);
7194*795d594fSAndroid Build Coastguard Worker }
7195*795d594fSAndroid Build Coastguard Worker
GenerateArrayLoadWithBakerReadBarrier(HArrayGet * instruction,Location ref,Register obj,uint32_t data_offset,Location index,bool needs_null_check)7196*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
7197*795d594fSAndroid Build Coastguard Worker Location ref,
7198*795d594fSAndroid Build Coastguard Worker Register obj,
7199*795d594fSAndroid Build Coastguard Worker uint32_t data_offset,
7200*795d594fSAndroid Build Coastguard Worker Location index,
7201*795d594fSAndroid Build Coastguard Worker bool needs_null_check) {
7202*795d594fSAndroid Build Coastguard Worker DCHECK(EmitBakerReadBarrier());
7203*795d594fSAndroid Build Coastguard Worker
7204*795d594fSAndroid Build Coastguard Worker static_assert(
7205*795d594fSAndroid Build Coastguard Worker sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
7206*795d594fSAndroid Build Coastguard Worker "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
7207*795d594fSAndroid Build Coastguard Worker size_t scale_factor = DataType::SizeShift(DataType::Type::kReference);
7208*795d594fSAndroid Build Coastguard Worker
7209*795d594fSAndroid Build Coastguard Worker // Query `art::Thread::Current()->GetIsGcMarking()` (stored in the
7210*795d594fSAndroid Build Coastguard Worker // Marking Register) to decide whether we need to enter the slow
7211*795d594fSAndroid Build Coastguard Worker // path to mark the reference. Then, in the slow path, check the
7212*795d594fSAndroid Build Coastguard Worker // gray bit in the lock word of the reference's holder (`obj`) to
7213*795d594fSAndroid Build Coastguard Worker // decide whether to mark `ref` or not.
7214*795d594fSAndroid Build Coastguard Worker //
7215*795d594fSAndroid Build Coastguard Worker // We use shared thunks for the slow path; shared within the method
7216*795d594fSAndroid Build Coastguard Worker // for JIT, across methods for AOT. That thunk checks the holder
7217*795d594fSAndroid Build Coastguard Worker // and jumps to the entrypoint if needed. If the holder is not gray,
7218*795d594fSAndroid Build Coastguard Worker // it creates a fake dependency and returns to the LDR instruction.
7219*795d594fSAndroid Build Coastguard Worker //
7220*795d594fSAndroid Build Coastguard Worker // lr = &gray_return_address;
7221*795d594fSAndroid Build Coastguard Worker // if (mr) { // Thread::Current()->GetIsGcMarking()
7222*795d594fSAndroid Build Coastguard Worker // goto array_thunk<base_reg>(lr)
7223*795d594fSAndroid Build Coastguard Worker // }
7224*795d594fSAndroid Build Coastguard Worker // not_gray_return_address:
7225*795d594fSAndroid Build Coastguard Worker // // Original reference load. If the offset is too large to fit
7226*795d594fSAndroid Build Coastguard Worker // // into LDR, we use an adjusted base register here.
7227*795d594fSAndroid Build Coastguard Worker // HeapReference<mirror::Object> reference = data[index];
7228*795d594fSAndroid Build Coastguard Worker // gray_return_address:
7229*795d594fSAndroid Build Coastguard Worker
7230*795d594fSAndroid Build Coastguard Worker DCHECK(index.IsValid());
7231*795d594fSAndroid Build Coastguard Worker Register index_reg = RegisterFrom(index, DataType::Type::kInt32);
7232*795d594fSAndroid Build Coastguard Worker Register ref_reg = RegisterFrom(ref, DataType::Type::kReference);
7233*795d594fSAndroid Build Coastguard Worker
7234*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
7235*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip0));
7236*795d594fSAndroid Build Coastguard Worker DCHECK(temps.IsAvailable(ip1));
7237*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7238*795d594fSAndroid Build Coastguard Worker
7239*795d594fSAndroid Build Coastguard Worker Register temp;
7240*795d594fSAndroid Build Coastguard Worker if (instruction->GetArray()->IsIntermediateAddress()) {
7241*795d594fSAndroid Build Coastguard Worker // We do not need to compute the intermediate address from the array: the
7242*795d594fSAndroid Build Coastguard Worker // input instruction has done it already. See the comment in
7243*795d594fSAndroid Build Coastguard Worker // `TryExtractArrayAccessAddress()`.
7244*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
7245*795d594fSAndroid Build Coastguard Worker HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
7246*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
7247*795d594fSAndroid Build Coastguard Worker }
7248*795d594fSAndroid Build Coastguard Worker temp = obj;
7249*795d594fSAndroid Build Coastguard Worker } else {
7250*795d594fSAndroid Build Coastguard Worker temp = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
7251*795d594fSAndroid Build Coastguard Worker __ Add(temp.X(), obj.X(), Operand(data_offset));
7252*795d594fSAndroid Build Coastguard Worker }
7253*795d594fSAndroid Build Coastguard Worker
7254*795d594fSAndroid Build Coastguard Worker uint32_t custom_data = EncodeBakerReadBarrierArrayData(temp.GetCode());
7255*795d594fSAndroid Build Coastguard Worker
7256*795d594fSAndroid Build Coastguard Worker {
7257*795d594fSAndroid Build Coastguard Worker ExactAssemblyScope guard(GetVIXLAssembler(),
7258*795d594fSAndroid Build Coastguard Worker (kPoisonHeapReferences ? 4u : 3u) * vixl::aarch64::kInstructionSize);
7259*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_address;
7260*795d594fSAndroid Build Coastguard Worker __ adr(lr, &return_address);
7261*795d594fSAndroid Build Coastguard Worker EmitBakerReadBarrierCbnz(custom_data);
7262*795d594fSAndroid Build Coastguard Worker static_assert(BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
7263*795d594fSAndroid Build Coastguard Worker "Array LDR must be 1 instruction (4B) before the return address label; "
7264*795d594fSAndroid Build Coastguard Worker " 2 instructions (8B) for heap poisoning.");
7265*795d594fSAndroid Build Coastguard Worker __ ldr(ref_reg, MemOperand(temp.X(), index_reg.X(), LSL, scale_factor));
7266*795d594fSAndroid Build Coastguard Worker DCHECK(!needs_null_check); // The thunk cannot handle the null check.
7267*795d594fSAndroid Build Coastguard Worker // Unpoison the reference explicitly if needed. MaybeUnpoisonHeapReference() uses
7268*795d594fSAndroid Build Coastguard Worker // macro instructions disallowed in ExactAssemblyScope.
7269*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences) {
7270*795d594fSAndroid Build Coastguard Worker __ neg(ref_reg, Operand(ref_reg));
7271*795d594fSAndroid Build Coastguard Worker }
7272*795d594fSAndroid Build Coastguard Worker __ bind(&return_address);
7273*795d594fSAndroid Build Coastguard Worker }
7274*795d594fSAndroid Build Coastguard Worker MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__, /* temp_loc= */ LocationFrom(ip1));
7275*795d594fSAndroid Build Coastguard Worker }
7276*795d594fSAndroid Build Coastguard Worker
MaybeGenerateMarkingRegisterCheck(int code,Location temp_loc)7277*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck(int code, Location temp_loc) {
7278*795d594fSAndroid Build Coastguard Worker // The following condition is a compile-time one, so it does not have a run-time cost.
7279*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild && EmitBakerReadBarrier()) {
7280*795d594fSAndroid Build Coastguard Worker // The following condition is a run-time one; it is executed after the
7281*795d594fSAndroid Build Coastguard Worker // previous compile-time test, to avoid penalizing non-debug builds.
7282*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().EmitRunTimeChecksInDebugMode()) {
7283*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(GetVIXLAssembler());
7284*795d594fSAndroid Build Coastguard Worker Register temp = temp_loc.IsValid() ? WRegisterFrom(temp_loc) : temps.AcquireW();
7285*795d594fSAndroid Build Coastguard Worker GetAssembler()->GenerateMarkingRegisterCheck(temp, code);
7286*795d594fSAndroid Build Coastguard Worker }
7287*795d594fSAndroid Build Coastguard Worker }
7288*795d594fSAndroid Build Coastguard Worker }
7289*795d594fSAndroid Build Coastguard Worker
AddReadBarrierSlowPath(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)7290*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* CodeGeneratorARM64::AddReadBarrierSlowPath(HInstruction* instruction,
7291*795d594fSAndroid Build Coastguard Worker Location out,
7292*795d594fSAndroid Build Coastguard Worker Location ref,
7293*795d594fSAndroid Build Coastguard Worker Location obj,
7294*795d594fSAndroid Build Coastguard Worker uint32_t offset,
7295*795d594fSAndroid Build Coastguard Worker Location index) {
7296*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = new (GetScopedAllocator())
7297*795d594fSAndroid Build Coastguard Worker ReadBarrierForHeapReferenceSlowPathARM64(instruction, out, ref, obj, offset, index);
7298*795d594fSAndroid Build Coastguard Worker AddSlowPath(slow_path);
7299*795d594fSAndroid Build Coastguard Worker return slow_path;
7300*795d594fSAndroid Build Coastguard Worker }
7301*795d594fSAndroid Build Coastguard Worker
GenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)7302*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateReadBarrierSlow(HInstruction* instruction,
7303*795d594fSAndroid Build Coastguard Worker Location out,
7304*795d594fSAndroid Build Coastguard Worker Location ref,
7305*795d594fSAndroid Build Coastguard Worker Location obj,
7306*795d594fSAndroid Build Coastguard Worker uint32_t offset,
7307*795d594fSAndroid Build Coastguard Worker Location index) {
7308*795d594fSAndroid Build Coastguard Worker DCHECK(EmitReadBarrier());
7309*795d594fSAndroid Build Coastguard Worker
7310*795d594fSAndroid Build Coastguard Worker // Insert a slow path based read barrier *after* the reference load.
7311*795d594fSAndroid Build Coastguard Worker //
7312*795d594fSAndroid Build Coastguard Worker // If heap poisoning is enabled, the unpoisoning of the loaded
7313*795d594fSAndroid Build Coastguard Worker // reference will be carried out by the runtime within the slow
7314*795d594fSAndroid Build Coastguard Worker // path.
7315*795d594fSAndroid Build Coastguard Worker //
7316*795d594fSAndroid Build Coastguard Worker // Note that `ref` currently does not get unpoisoned (when heap
7317*795d594fSAndroid Build Coastguard Worker // poisoning is enabled), which is alright as the `ref` argument is
7318*795d594fSAndroid Build Coastguard Worker // not used by the artReadBarrierSlow entry point.
7319*795d594fSAndroid Build Coastguard Worker //
7320*795d594fSAndroid Build Coastguard Worker // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
7321*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path = AddReadBarrierSlowPath(instruction, out, ref, obj, offset, index);
7322*795d594fSAndroid Build Coastguard Worker
7323*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
7324*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
7325*795d594fSAndroid Build Coastguard Worker }
7326*795d594fSAndroid Build Coastguard Worker
MaybeGenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)7327*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7328*795d594fSAndroid Build Coastguard Worker Location out,
7329*795d594fSAndroid Build Coastguard Worker Location ref,
7330*795d594fSAndroid Build Coastguard Worker Location obj,
7331*795d594fSAndroid Build Coastguard Worker uint32_t offset,
7332*795d594fSAndroid Build Coastguard Worker Location index) {
7333*795d594fSAndroid Build Coastguard Worker if (EmitReadBarrier()) {
7334*795d594fSAndroid Build Coastguard Worker // Baker's read barriers shall be handled by the fast path
7335*795d594fSAndroid Build Coastguard Worker // (CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier).
7336*795d594fSAndroid Build Coastguard Worker DCHECK(!kUseBakerReadBarrier);
7337*795d594fSAndroid Build Coastguard Worker // If heap poisoning is enabled, unpoisoning will be taken care of
7338*795d594fSAndroid Build Coastguard Worker // by the runtime within the slow path.
7339*795d594fSAndroid Build Coastguard Worker GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
7340*795d594fSAndroid Build Coastguard Worker } else if (kPoisonHeapReferences) {
7341*795d594fSAndroid Build Coastguard Worker GetAssembler()->UnpoisonHeapReference(WRegisterFrom(out));
7342*795d594fSAndroid Build Coastguard Worker }
7343*795d594fSAndroid Build Coastguard Worker }
7344*795d594fSAndroid Build Coastguard Worker
GenerateReadBarrierForRootSlow(HInstruction * instruction,Location out,Location root)7345*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7346*795d594fSAndroid Build Coastguard Worker Location out,
7347*795d594fSAndroid Build Coastguard Worker Location root) {
7348*795d594fSAndroid Build Coastguard Worker DCHECK(EmitReadBarrier());
7349*795d594fSAndroid Build Coastguard Worker
7350*795d594fSAndroid Build Coastguard Worker // Insert a slow path based read barrier *after* the GC root load.
7351*795d594fSAndroid Build Coastguard Worker //
7352*795d594fSAndroid Build Coastguard Worker // Note that GC roots are not affected by heap poisoning, so we do
7353*795d594fSAndroid Build Coastguard Worker // not need to do anything special for this here.
7354*795d594fSAndroid Build Coastguard Worker SlowPathCodeARM64* slow_path =
7355*795d594fSAndroid Build Coastguard Worker new (GetScopedAllocator()) ReadBarrierForRootSlowPathARM64(instruction, out, root);
7356*795d594fSAndroid Build Coastguard Worker AddSlowPath(slow_path);
7357*795d594fSAndroid Build Coastguard Worker
7358*795d594fSAndroid Build Coastguard Worker __ B(slow_path->GetEntryLabel());
7359*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
7360*795d594fSAndroid Build Coastguard Worker }
7361*795d594fSAndroid Build Coastguard Worker
VisitClassTableGet(HClassTableGet * instruction)7362*795d594fSAndroid Build Coastguard Worker void LocationsBuilderARM64::VisitClassTableGet(HClassTableGet* instruction) {
7363*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
7364*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
7365*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
7366*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
7367*795d594fSAndroid Build Coastguard Worker }
7368*795d594fSAndroid Build Coastguard Worker
VisitClassTableGet(HClassTableGet * instruction)7369*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorARM64::VisitClassTableGet(HClassTableGet* instruction) {
7370*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
7371*795d594fSAndroid Build Coastguard Worker if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
7372*795d594fSAndroid Build Coastguard Worker uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7373*795d594fSAndroid Build Coastguard Worker instruction->GetIndex(), kArm64PointerSize).SizeValue();
7374*795d594fSAndroid Build Coastguard Worker __ Ldr(XRegisterFrom(locations->Out()),
7375*795d594fSAndroid Build Coastguard Worker MemOperand(XRegisterFrom(locations->InAt(0)), method_offset));
7376*795d594fSAndroid Build Coastguard Worker } else {
7377*795d594fSAndroid Build Coastguard Worker uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
7378*795d594fSAndroid Build Coastguard Worker instruction->GetIndex(), kArm64PointerSize));
7379*795d594fSAndroid Build Coastguard Worker __ Ldr(XRegisterFrom(locations->Out()), MemOperand(XRegisterFrom(locations->InAt(0)),
7380*795d594fSAndroid Build Coastguard Worker mirror::Class::ImtPtrOffset(kArm64PointerSize).Uint32Value()));
7381*795d594fSAndroid Build Coastguard Worker __ Ldr(XRegisterFrom(locations->Out()),
7382*795d594fSAndroid Build Coastguard Worker MemOperand(XRegisterFrom(locations->Out()), method_offset));
7383*795d594fSAndroid Build Coastguard Worker }
7384*795d594fSAndroid Build Coastguard Worker }
7385*795d594fSAndroid Build Coastguard Worker
VecNEONAddress(HVecMemoryOperation * instruction,UseScratchRegisterScope * temps_scope,size_t size,bool is_string_char_at,Register * scratch)7386*795d594fSAndroid Build Coastguard Worker MemOperand InstructionCodeGeneratorARM64::VecNEONAddress(
7387*795d594fSAndroid Build Coastguard Worker HVecMemoryOperation* instruction,
7388*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope* temps_scope,
7389*795d594fSAndroid Build Coastguard Worker size_t size,
7390*795d594fSAndroid Build Coastguard Worker bool is_string_char_at,
7391*795d594fSAndroid Build Coastguard Worker /*out*/ Register* scratch) {
7392*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
7393*795d594fSAndroid Build Coastguard Worker Register base = InputRegisterAt(instruction, 0);
7394*795d594fSAndroid Build Coastguard Worker
7395*795d594fSAndroid Build Coastguard Worker if (instruction->InputAt(1)->IsIntermediateAddressIndex()) {
7396*795d594fSAndroid Build Coastguard Worker DCHECK(!is_string_char_at);
7397*795d594fSAndroid Build Coastguard Worker return MemOperand(base.X(), InputRegisterAt(instruction, 1).X());
7398*795d594fSAndroid Build Coastguard Worker }
7399*795d594fSAndroid Build Coastguard Worker
7400*795d594fSAndroid Build Coastguard Worker Location index = locations->InAt(1);
7401*795d594fSAndroid Build Coastguard Worker uint32_t offset = is_string_char_at
7402*795d594fSAndroid Build Coastguard Worker ? mirror::String::ValueOffset().Uint32Value()
7403*795d594fSAndroid Build Coastguard Worker : mirror::Array::DataOffset(size).Uint32Value();
7404*795d594fSAndroid Build Coastguard Worker size_t shift = ComponentSizeShiftWidth(size);
7405*795d594fSAndroid Build Coastguard Worker
7406*795d594fSAndroid Build Coastguard Worker // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
7407*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
7408*795d594fSAndroid Build Coastguard Worker
7409*795d594fSAndroid Build Coastguard Worker if (index.IsConstant()) {
7410*795d594fSAndroid Build Coastguard Worker offset += Int64FromLocation(index) << shift;
7411*795d594fSAndroid Build Coastguard Worker return HeapOperand(base, offset);
7412*795d594fSAndroid Build Coastguard Worker } else {
7413*795d594fSAndroid Build Coastguard Worker *scratch = temps_scope->AcquireSameSizeAs(base);
7414*795d594fSAndroid Build Coastguard Worker __ Add(*scratch, base, Operand(WRegisterFrom(index), LSL, shift));
7415*795d594fSAndroid Build Coastguard Worker return HeapOperand(*scratch, offset);
7416*795d594fSAndroid Build Coastguard Worker }
7417*795d594fSAndroid Build Coastguard Worker }
7418*795d594fSAndroid Build Coastguard Worker
VecSVEAddress(HVecMemoryOperation * instruction,UseScratchRegisterScope * temps_scope,size_t size,bool is_string_char_at,Register * scratch)7419*795d594fSAndroid Build Coastguard Worker SVEMemOperand InstructionCodeGeneratorARM64::VecSVEAddress(
7420*795d594fSAndroid Build Coastguard Worker HVecMemoryOperation* instruction,
7421*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope* temps_scope,
7422*795d594fSAndroid Build Coastguard Worker size_t size,
7423*795d594fSAndroid Build Coastguard Worker bool is_string_char_at,
7424*795d594fSAndroid Build Coastguard Worker /*out*/ Register* scratch) {
7425*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction->GetLocations();
7426*795d594fSAndroid Build Coastguard Worker Register base = InputRegisterAt(instruction, 0);
7427*795d594fSAndroid Build Coastguard Worker Location index = locations->InAt(1);
7428*795d594fSAndroid Build Coastguard Worker
7429*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->InputAt(1)->IsIntermediateAddressIndex());
7430*795d594fSAndroid Build Coastguard Worker DCHECK(!index.IsConstant());
7431*795d594fSAndroid Build Coastguard Worker
7432*795d594fSAndroid Build Coastguard Worker uint32_t offset = is_string_char_at
7433*795d594fSAndroid Build Coastguard Worker ? mirror::String::ValueOffset().Uint32Value()
7434*795d594fSAndroid Build Coastguard Worker : mirror::Array::DataOffset(size).Uint32Value();
7435*795d594fSAndroid Build Coastguard Worker size_t shift = ComponentSizeShiftWidth(size);
7436*795d594fSAndroid Build Coastguard Worker
7437*795d594fSAndroid Build Coastguard Worker if (instruction->InputAt(0)->IsIntermediateAddress()) {
7438*795d594fSAndroid Build Coastguard Worker return SVEMemOperand(base.X(), XRegisterFrom(index), LSL, shift);
7439*795d594fSAndroid Build Coastguard Worker }
7440*795d594fSAndroid Build Coastguard Worker
7441*795d594fSAndroid Build Coastguard Worker *scratch = temps_scope->AcquireSameSizeAs(base);
7442*795d594fSAndroid Build Coastguard Worker __ Add(*scratch, base, offset);
7443*795d594fSAndroid Build Coastguard Worker return SVEMemOperand(scratch->X(), XRegisterFrom(index), LSL, shift);
7444*795d594fSAndroid Build Coastguard Worker }
7445*795d594fSAndroid Build Coastguard Worker
7446*795d594fSAndroid Build Coastguard Worker #undef __
7447*795d594fSAndroid Build Coastguard Worker #undef QUICK_ENTRY_POINT
7448*795d594fSAndroid Build Coastguard Worker
7449*795d594fSAndroid Build Coastguard Worker #define __ assembler.GetVIXLAssembler()->
7450*795d594fSAndroid Build Coastguard Worker
EmitGrayCheckAndFastPath(arm64::Arm64Assembler & assembler,vixl::aarch64::Register base_reg,vixl::aarch64::MemOperand & lock_word,vixl::aarch64::Label * slow_path,vixl::aarch64::Label * throw_npe=nullptr)7451*795d594fSAndroid Build Coastguard Worker static void EmitGrayCheckAndFastPath(arm64::Arm64Assembler& assembler,
7452*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register base_reg,
7453*795d594fSAndroid Build Coastguard Worker vixl::aarch64::MemOperand& lock_word,
7454*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* slow_path,
7455*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* throw_npe = nullptr) {
7456*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label throw_npe_cont;
7457*795d594fSAndroid Build Coastguard Worker // Load the lock word containing the rb_state.
7458*795d594fSAndroid Build Coastguard Worker __ Ldr(ip0.W(), lock_word);
7459*795d594fSAndroid Build Coastguard Worker // Given the numeric representation, it's enough to check the low bit of the rb_state.
7460*795d594fSAndroid Build Coastguard Worker static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
7461*795d594fSAndroid Build Coastguard Worker static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
7462*795d594fSAndroid Build Coastguard Worker __ Tbnz(ip0.W(), LockWord::kReadBarrierStateShift, slow_path);
7463*795d594fSAndroid Build Coastguard Worker static_assert(
7464*795d594fSAndroid Build Coastguard Worker BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET == BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET,
7465*795d594fSAndroid Build Coastguard Worker "Field and array LDR offsets must be the same to reuse the same code.");
7466*795d594fSAndroid Build Coastguard Worker // To throw NPE, we return to the fast path; the artificial dependence below does not matter.
7467*795d594fSAndroid Build Coastguard Worker if (throw_npe != nullptr) {
7468*795d594fSAndroid Build Coastguard Worker __ Bind(&throw_npe_cont);
7469*795d594fSAndroid Build Coastguard Worker }
7470*795d594fSAndroid Build Coastguard Worker // Adjust the return address back to the LDR (1 instruction; 2 for heap poisoning).
7471*795d594fSAndroid Build Coastguard Worker static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
7472*795d594fSAndroid Build Coastguard Worker "Field LDR must be 1 instruction (4B) before the return address label; "
7473*795d594fSAndroid Build Coastguard Worker " 2 instructions (8B) for heap poisoning.");
7474*795d594fSAndroid Build Coastguard Worker __ Add(lr, lr, BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET);
7475*795d594fSAndroid Build Coastguard Worker // Introduce a dependency on the lock_word including rb_state,
7476*795d594fSAndroid Build Coastguard Worker // to prevent load-load reordering, and without using
7477*795d594fSAndroid Build Coastguard Worker // a memory barrier (which would be more expensive).
7478*795d594fSAndroid Build Coastguard Worker __ Add(base_reg, base_reg, Operand(ip0, LSR, 32));
7479*795d594fSAndroid Build Coastguard Worker __ Br(lr); // And return back to the function.
7480*795d594fSAndroid Build Coastguard Worker if (throw_npe != nullptr) {
7481*795d594fSAndroid Build Coastguard Worker // Clear IP0 before returning to the fast path.
7482*795d594fSAndroid Build Coastguard Worker __ Bind(throw_npe);
7483*795d594fSAndroid Build Coastguard Worker __ Mov(ip0.X(), xzr);
7484*795d594fSAndroid Build Coastguard Worker __ B(&throw_npe_cont);
7485*795d594fSAndroid Build Coastguard Worker }
7486*795d594fSAndroid Build Coastguard Worker // Note: The fake dependency is unnecessary for the slow path.
7487*795d594fSAndroid Build Coastguard Worker }
7488*795d594fSAndroid Build Coastguard Worker
7489*795d594fSAndroid Build Coastguard Worker // Load the read barrier introspection entrypoint in register `entrypoint`.
LoadReadBarrierMarkIntrospectionEntrypoint(arm64::Arm64Assembler & assembler,vixl::aarch64::Register entrypoint)7490*795d594fSAndroid Build Coastguard Worker static void LoadReadBarrierMarkIntrospectionEntrypoint(arm64::Arm64Assembler& assembler,
7491*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Register entrypoint) {
7492*795d594fSAndroid Build Coastguard Worker // entrypoint = Thread::Current()->pReadBarrierMarkReg16, i.e. pReadBarrierMarkIntrospection.
7493*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ip0.GetCode(), 16u);
7494*795d594fSAndroid Build Coastguard Worker const int32_t entry_point_offset =
7495*795d594fSAndroid Build Coastguard Worker Thread::ReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(ip0.GetCode());
7496*795d594fSAndroid Build Coastguard Worker __ Ldr(entrypoint, MemOperand(tr, entry_point_offset));
7497*795d594fSAndroid Build Coastguard Worker }
7498*795d594fSAndroid Build Coastguard Worker
CompileBakerReadBarrierThunk(Arm64Assembler & assembler,uint32_t encoded_data,std::string * debug_name)7499*795d594fSAndroid Build Coastguard Worker void CodeGeneratorARM64::CompileBakerReadBarrierThunk(Arm64Assembler& assembler,
7500*795d594fSAndroid Build Coastguard Worker uint32_t encoded_data,
7501*795d594fSAndroid Build Coastguard Worker /*out*/ std::string* debug_name) {
7502*795d594fSAndroid Build Coastguard Worker BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data);
7503*795d594fSAndroid Build Coastguard Worker switch (kind) {
7504*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kField:
7505*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kAcquire: {
7506*795d594fSAndroid Build Coastguard Worker Register base_reg =
7507*795d594fSAndroid Build Coastguard Worker vixl::aarch64::XRegister(BakerReadBarrierFirstRegField::Decode(encoded_data));
7508*795d594fSAndroid Build Coastguard Worker CheckValidReg(base_reg.GetCode());
7509*795d594fSAndroid Build Coastguard Worker Register holder_reg =
7510*795d594fSAndroid Build Coastguard Worker vixl::aarch64::XRegister(BakerReadBarrierSecondRegField::Decode(encoded_data));
7511*795d594fSAndroid Build Coastguard Worker CheckValidReg(holder_reg.GetCode());
7512*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
7513*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7514*795d594fSAndroid Build Coastguard Worker // In the case of a field load (with relaxed semantic), if `base_reg` differs from
7515*795d594fSAndroid Build Coastguard Worker // `holder_reg`, the offset was too large and we must have emitted (during the construction
7516*795d594fSAndroid Build Coastguard Worker // of the HIR graph, see `art::HInstructionBuilder::BuildInstanceFieldAccess`) and preserved
7517*795d594fSAndroid Build Coastguard Worker // (see `art::PrepareForRegisterAllocation::VisitNullCheck`) an explicit null check before
7518*795d594fSAndroid Build Coastguard Worker // the load. Otherwise, for implicit null checks, we need to null-check the holder as we do
7519*795d594fSAndroid Build Coastguard Worker // not necessarily do that check before going to the thunk.
7520*795d594fSAndroid Build Coastguard Worker //
7521*795d594fSAndroid Build Coastguard Worker // In the case of a field load with load-acquire semantics (where `base_reg` always differs
7522*795d594fSAndroid Build Coastguard Worker // from `holder_reg`), we also need an explicit null check when implicit null checks are
7523*795d594fSAndroid Build Coastguard Worker // allowed, as we do not emit one before going to the thunk.
7524*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label throw_npe_label;
7525*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label* throw_npe = nullptr;
7526*795d594fSAndroid Build Coastguard Worker if (GetCompilerOptions().GetImplicitNullChecks() &&
7527*795d594fSAndroid Build Coastguard Worker (holder_reg.Is(base_reg) || (kind == BakerReadBarrierKind::kAcquire))) {
7528*795d594fSAndroid Build Coastguard Worker throw_npe = &throw_npe_label;
7529*795d594fSAndroid Build Coastguard Worker __ Cbz(holder_reg.W(), throw_npe);
7530*795d594fSAndroid Build Coastguard Worker }
7531*795d594fSAndroid Build Coastguard Worker // Check if the holder is gray and, if not, add fake dependency to the base register
7532*795d594fSAndroid Build Coastguard Worker // and return to the LDR instruction to load the reference. Otherwise, use introspection
7533*795d594fSAndroid Build Coastguard Worker // to load the reference and call the entrypoint that performs further checks on the
7534*795d594fSAndroid Build Coastguard Worker // reference and marks it if needed.
7535*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label slow_path;
7536*795d594fSAndroid Build Coastguard Worker MemOperand lock_word(holder_reg, mirror::Object::MonitorOffset().Int32Value());
7537*795d594fSAndroid Build Coastguard Worker EmitGrayCheckAndFastPath(assembler, base_reg, lock_word, &slow_path, throw_npe);
7538*795d594fSAndroid Build Coastguard Worker __ Bind(&slow_path);
7539*795d594fSAndroid Build Coastguard Worker if (kind == BakerReadBarrierKind::kField) {
7540*795d594fSAndroid Build Coastguard Worker MemOperand ldr_address(lr, BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET);
7541*795d594fSAndroid Build Coastguard Worker __ Ldr(ip0.W(), ldr_address); // Load the LDR (immediate) unsigned offset.
7542*795d594fSAndroid Build Coastguard Worker LoadReadBarrierMarkIntrospectionEntrypoint(assembler, ip1);
7543*795d594fSAndroid Build Coastguard Worker __ Ubfx(ip0.W(), ip0.W(), 10, 12); // Extract the offset.
7544*795d594fSAndroid Build Coastguard Worker __ Ldr(ip0.W(), MemOperand(base_reg, ip0, LSL, 2)); // Load the reference.
7545*795d594fSAndroid Build Coastguard Worker } else {
7546*795d594fSAndroid Build Coastguard Worker DCHECK(kind == BakerReadBarrierKind::kAcquire);
7547*795d594fSAndroid Build Coastguard Worker DCHECK(!base_reg.Is(holder_reg));
7548*795d594fSAndroid Build Coastguard Worker LoadReadBarrierMarkIntrospectionEntrypoint(assembler, ip1);
7549*795d594fSAndroid Build Coastguard Worker __ Ldar(ip0.W(), MemOperand(base_reg));
7550*795d594fSAndroid Build Coastguard Worker }
7551*795d594fSAndroid Build Coastguard Worker // Do not unpoison. With heap poisoning enabled, the entrypoint expects a poisoned reference.
7552*795d594fSAndroid Build Coastguard Worker __ Br(ip1); // Jump to the entrypoint.
7553*795d594fSAndroid Build Coastguard Worker break;
7554*795d594fSAndroid Build Coastguard Worker }
7555*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kArray: {
7556*795d594fSAndroid Build Coastguard Worker Register base_reg =
7557*795d594fSAndroid Build Coastguard Worker vixl::aarch64::XRegister(BakerReadBarrierFirstRegField::Decode(encoded_data));
7558*795d594fSAndroid Build Coastguard Worker CheckValidReg(base_reg.GetCode());
7559*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kBakerReadBarrierInvalidEncodedReg,
7560*795d594fSAndroid Build Coastguard Worker BakerReadBarrierSecondRegField::Decode(encoded_data));
7561*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
7562*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7563*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label slow_path;
7564*795d594fSAndroid Build Coastguard Worker int32_t data_offset =
7565*795d594fSAndroid Build Coastguard Worker mirror::Array::DataOffset(Primitive::ComponentSize(Primitive::kPrimNot)).Int32Value();
7566*795d594fSAndroid Build Coastguard Worker MemOperand lock_word(base_reg, mirror::Object::MonitorOffset().Int32Value() - data_offset);
7567*795d594fSAndroid Build Coastguard Worker DCHECK_LT(lock_word.GetOffset(), 0);
7568*795d594fSAndroid Build Coastguard Worker EmitGrayCheckAndFastPath(assembler, base_reg, lock_word, &slow_path);
7569*795d594fSAndroid Build Coastguard Worker __ Bind(&slow_path);
7570*795d594fSAndroid Build Coastguard Worker MemOperand ldr_address(lr, BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET);
7571*795d594fSAndroid Build Coastguard Worker __ Ldr(ip0.W(), ldr_address); // Load the LDR (register) unsigned offset.
7572*795d594fSAndroid Build Coastguard Worker LoadReadBarrierMarkIntrospectionEntrypoint(assembler, ip1);
7573*795d594fSAndroid Build Coastguard Worker __ Ubfx(ip0, ip0, 16, 6); // Extract the index register, plus 32 (bit 21 is set).
7574*795d594fSAndroid Build Coastguard Worker __ Bfi(ip1, ip0, 3, 6); // Insert ip0 to the entrypoint address to create
7575*795d594fSAndroid Build Coastguard Worker // a switch case target based on the index register.
7576*795d594fSAndroid Build Coastguard Worker __ Mov(ip0, base_reg); // Move the base register to ip0.
7577*795d594fSAndroid Build Coastguard Worker __ Br(ip1); // Jump to the entrypoint's array switch case.
7578*795d594fSAndroid Build Coastguard Worker break;
7579*795d594fSAndroid Build Coastguard Worker }
7580*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kGcRoot: {
7581*795d594fSAndroid Build Coastguard Worker // Check if the reference needs to be marked and if so (i.e. not null, not marked yet
7582*795d594fSAndroid Build Coastguard Worker // and it does not have a forwarding address), call the correct introspection entrypoint;
7583*795d594fSAndroid Build Coastguard Worker // otherwise return the reference (or the extracted forwarding address).
7584*795d594fSAndroid Build Coastguard Worker // There is no gray bit check for GC roots.
7585*795d594fSAndroid Build Coastguard Worker Register root_reg =
7586*795d594fSAndroid Build Coastguard Worker vixl::aarch64::WRegister(BakerReadBarrierFirstRegField::Decode(encoded_data));
7587*795d594fSAndroid Build Coastguard Worker CheckValidReg(root_reg.GetCode());
7588*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kBakerReadBarrierInvalidEncodedReg,
7589*795d594fSAndroid Build Coastguard Worker BakerReadBarrierSecondRegField::Decode(encoded_data));
7590*795d594fSAndroid Build Coastguard Worker UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
7591*795d594fSAndroid Build Coastguard Worker temps.Exclude(ip0, ip1);
7592*795d594fSAndroid Build Coastguard Worker vixl::aarch64::Label return_label, not_marked, forwarding_address;
7593*795d594fSAndroid Build Coastguard Worker __ Cbz(root_reg, &return_label);
7594*795d594fSAndroid Build Coastguard Worker MemOperand lock_word(root_reg.X(), mirror::Object::MonitorOffset().Int32Value());
7595*795d594fSAndroid Build Coastguard Worker __ Ldr(ip0.W(), lock_word);
7596*795d594fSAndroid Build Coastguard Worker __ Tbz(ip0.W(), LockWord::kMarkBitStateShift, ¬_marked);
7597*795d594fSAndroid Build Coastguard Worker __ Bind(&return_label);
7598*795d594fSAndroid Build Coastguard Worker __ Br(lr);
7599*795d594fSAndroid Build Coastguard Worker __ Bind(¬_marked);
7600*795d594fSAndroid Build Coastguard Worker __ Tst(ip0.W(), Operand(ip0.W(), LSL, 1));
7601*795d594fSAndroid Build Coastguard Worker __ B(&forwarding_address, mi);
7602*795d594fSAndroid Build Coastguard Worker LoadReadBarrierMarkIntrospectionEntrypoint(assembler, ip1);
7603*795d594fSAndroid Build Coastguard Worker // Adjust the art_quick_read_barrier_mark_introspection address in IP1 to
7604*795d594fSAndroid Build Coastguard Worker // art_quick_read_barrier_mark_introspection_gc_roots.
7605*795d594fSAndroid Build Coastguard Worker __ Add(ip1, ip1, Operand(BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRYPOINT_OFFSET));
7606*795d594fSAndroid Build Coastguard Worker __ Mov(ip0.W(), root_reg);
7607*795d594fSAndroid Build Coastguard Worker __ Br(ip1);
7608*795d594fSAndroid Build Coastguard Worker __ Bind(&forwarding_address);
7609*795d594fSAndroid Build Coastguard Worker __ Lsl(root_reg, ip0.W(), LockWord::kForwardingAddressShift);
7610*795d594fSAndroid Build Coastguard Worker __ Br(lr);
7611*795d594fSAndroid Build Coastguard Worker break;
7612*795d594fSAndroid Build Coastguard Worker }
7613*795d594fSAndroid Build Coastguard Worker default:
7614*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected kind: " << static_cast<uint32_t>(kind);
7615*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
7616*795d594fSAndroid Build Coastguard Worker }
7617*795d594fSAndroid Build Coastguard Worker
7618*795d594fSAndroid Build Coastguard Worker // For JIT, the slow path is considered part of the compiled method,
7619*795d594fSAndroid Build Coastguard Worker // so JIT should pass null as `debug_name`.
7620*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(GetCompilerOptions().IsJitCompiler(), debug_name == nullptr);
7621*795d594fSAndroid Build Coastguard Worker if (debug_name != nullptr && GetCompilerOptions().GenerateAnyDebugInfo()) {
7622*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
7623*795d594fSAndroid Build Coastguard Worker oss << "BakerReadBarrierThunk";
7624*795d594fSAndroid Build Coastguard Worker switch (kind) {
7625*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kField:
7626*795d594fSAndroid Build Coastguard Worker oss << "Field_r" << BakerReadBarrierFirstRegField::Decode(encoded_data)
7627*795d594fSAndroid Build Coastguard Worker << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data);
7628*795d594fSAndroid Build Coastguard Worker break;
7629*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kAcquire:
7630*795d594fSAndroid Build Coastguard Worker oss << "Acquire_r" << BakerReadBarrierFirstRegField::Decode(encoded_data)
7631*795d594fSAndroid Build Coastguard Worker << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data);
7632*795d594fSAndroid Build Coastguard Worker break;
7633*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kArray:
7634*795d594fSAndroid Build Coastguard Worker oss << "Array_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
7635*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kBakerReadBarrierInvalidEncodedReg,
7636*795d594fSAndroid Build Coastguard Worker BakerReadBarrierSecondRegField::Decode(encoded_data));
7637*795d594fSAndroid Build Coastguard Worker break;
7638*795d594fSAndroid Build Coastguard Worker case BakerReadBarrierKind::kGcRoot:
7639*795d594fSAndroid Build Coastguard Worker oss << "GcRoot_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
7640*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(kBakerReadBarrierInvalidEncodedReg,
7641*795d594fSAndroid Build Coastguard Worker BakerReadBarrierSecondRegField::Decode(encoded_data));
7642*795d594fSAndroid Build Coastguard Worker break;
7643*795d594fSAndroid Build Coastguard Worker }
7644*795d594fSAndroid Build Coastguard Worker *debug_name = oss.str();
7645*795d594fSAndroid Build Coastguard Worker }
7646*795d594fSAndroid Build Coastguard Worker }
7647*795d594fSAndroid Build Coastguard Worker
7648*795d594fSAndroid Build Coastguard Worker #undef __
7649*795d594fSAndroid Build Coastguard Worker
7650*795d594fSAndroid Build Coastguard Worker } // namespace arm64
7651*795d594fSAndroid Build Coastguard Worker } // namespace art
7652