xref: /aosp_15_r20/art/compiler/optimizing/intrinsics_arm64.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 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 "intrinsics_arm64.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/callee_save_frame_arm64.h"
20*795d594fSAndroid Build Coastguard Worker #include "arch/arm64/instruction_set_features_arm64.h"
21*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
23*795d594fSAndroid Build Coastguard Worker #include "code_generator_arm64.h"
24*795d594fSAndroid Build Coastguard Worker #include "common_arm64.h"
25*795d594fSAndroid Build Coastguard Worker #include "data_type-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
27*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
28*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
29*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
30*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
31*795d594fSAndroid Build Coastguard Worker #include "lock_word.h"
32*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "mirror/method_handle_impl.h"
34*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-inl.h"
35*795d594fSAndroid Build Coastguard Worker #include "mirror/reference.h"
36*795d594fSAndroid Build Coastguard Worker #include "mirror/string-inl.h"
37*795d594fSAndroid Build Coastguard Worker #include "mirror/var_handle.h"
38*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
39*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
40*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
41*795d594fSAndroid Build Coastguard Worker #include "utils/arm64/assembler_arm64.h"
42*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker using namespace vixl::aarch64;  // NOLINT(build/namespaces)
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Make VIXL compile cleanly with -Wshadow, -Wdeprecated-declarations.
47*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic push
48*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wshadow"
49*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
50*795d594fSAndroid Build Coastguard Worker #include "aarch64/disasm-aarch64.h"
51*795d594fSAndroid Build Coastguard Worker #include "aarch64/macro-assembler-aarch64.h"
52*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker namespace arm64 {
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker using helpers::CPURegisterFrom;
59*795d594fSAndroid Build Coastguard Worker using helpers::DRegisterFrom;
60*795d594fSAndroid Build Coastguard Worker using helpers::HeapOperand;
61*795d594fSAndroid Build Coastguard Worker using helpers::LocationFrom;
62*795d594fSAndroid Build Coastguard Worker using helpers::Int64FromLocation;
63*795d594fSAndroid Build Coastguard Worker using helpers::InputCPURegisterAt;
64*795d594fSAndroid Build Coastguard Worker using helpers::InputCPURegisterOrZeroRegAt;
65*795d594fSAndroid Build Coastguard Worker using helpers::OperandFrom;
66*795d594fSAndroid Build Coastguard Worker using helpers::RegisterFrom;
67*795d594fSAndroid Build Coastguard Worker using helpers::SRegisterFrom;
68*795d594fSAndroid Build Coastguard Worker using helpers::WRegisterFrom;
69*795d594fSAndroid Build Coastguard Worker using helpers::XRegisterFrom;
70*795d594fSAndroid Build Coastguard Worker using helpers::HRegisterFrom;
71*795d594fSAndroid Build Coastguard Worker using helpers::InputRegisterAt;
72*795d594fSAndroid Build Coastguard Worker using helpers::OutputRegister;
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker namespace {
75*795d594fSAndroid Build Coastguard Worker 
AbsoluteHeapOperandFrom(Location location,size_t offset=0)76*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE inline MemOperand AbsoluteHeapOperandFrom(Location location, size_t offset = 0) {
77*795d594fSAndroid Build Coastguard Worker   return MemOperand(XRegisterFrom(location), offset);
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker }  // namespace
81*795d594fSAndroid Build Coastguard Worker 
GetVIXLAssembler()82*795d594fSAndroid Build Coastguard Worker MacroAssembler* IntrinsicCodeGeneratorARM64::GetVIXLAssembler() {
83*795d594fSAndroid Build Coastguard Worker   return codegen_->GetVIXLAssembler();
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker 
GetAllocator()86*795d594fSAndroid Build Coastguard Worker ArenaAllocator* IntrinsicCodeGeneratorARM64::GetAllocator() {
87*795d594fSAndroid Build Coastguard Worker   return codegen_->GetGraph()->GetAllocator();
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker using IntrinsicSlowPathARM64 = IntrinsicSlowPath<InvokeDexCallingConventionVisitorARM64,
91*795d594fSAndroid Build Coastguard Worker                                                  SlowPathCodeARM64,
92*795d594fSAndroid Build Coastguard Worker                                                  Arm64Assembler>;
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker #define __ codegen->GetVIXLAssembler()->
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker // Slow path implementing the SystemArrayCopy intrinsic copy loop with read barriers.
97*795d594fSAndroid Build Coastguard Worker class ReadBarrierSystemArrayCopySlowPathARM64 : public SlowPathCodeARM64 {
98*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierSystemArrayCopySlowPathARM64(HInstruction * instruction,Location tmp)99*795d594fSAndroid Build Coastguard Worker   ReadBarrierSystemArrayCopySlowPathARM64(HInstruction* instruction, Location tmp)
100*795d594fSAndroid Build Coastguard Worker       : SlowPathCodeARM64(instruction), tmp_(tmp) {
101*795d594fSAndroid Build Coastguard Worker   }
102*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen_in)103*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen_in) override {
104*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen_in->EmitBakerReadBarrier());
105*795d594fSAndroid Build Coastguard Worker     CodeGeneratorARM64* codegen = down_cast<CodeGeneratorARM64*>(codegen_in);
106*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
107*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
108*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsInvokeStaticOrDirect())
109*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier arraycopy slow path: "
110*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
111*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->GetLocations()->Intrinsified());
112*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker     const int32_t element_size = DataType::Size(DataType::Type::kReference);
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker     Register src_curr_addr = XRegisterFrom(locations->GetTemp(0));
117*795d594fSAndroid Build Coastguard Worker     Register dst_curr_addr = XRegisterFrom(locations->GetTemp(1));
118*795d594fSAndroid Build Coastguard Worker     Register src_stop_addr = XRegisterFrom(locations->GetTemp(2));
119*795d594fSAndroid Build Coastguard Worker     Register tmp_reg = WRegisterFrom(tmp_);
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
122*795d594fSAndroid Build Coastguard Worker     // The source range and destination pointer were initialized before entering the slow-path.
123*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label slow_copy_loop;
124*795d594fSAndroid Build Coastguard Worker     __ Bind(&slow_copy_loop);
125*795d594fSAndroid Build Coastguard Worker     __ Ldr(tmp_reg, MemOperand(src_curr_addr, element_size, PostIndex));
126*795d594fSAndroid Build Coastguard Worker     codegen->GetAssembler()->MaybeUnpoisonHeapReference(tmp_reg);
127*795d594fSAndroid Build Coastguard Worker     // TODO: Inline the mark bit check before calling the runtime?
128*795d594fSAndroid Build Coastguard Worker     // tmp_reg = ReadBarrier::Mark(tmp_reg);
129*795d594fSAndroid Build Coastguard Worker     // No need to save live registers; it's taken care of by the
130*795d594fSAndroid Build Coastguard Worker     // entrypoint. Also, there is no need to update the stack mask,
131*795d594fSAndroid Build Coastguard Worker     // as this runtime call will not trigger a garbage collection.
132*795d594fSAndroid Build Coastguard Worker     // (See ReadBarrierMarkSlowPathARM64::EmitNativeCode for more
133*795d594fSAndroid Build Coastguard Worker     // explanations.)
134*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(tmp_.reg(), LR);
135*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(tmp_.reg(), WSP);
136*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(tmp_.reg(), WZR);
137*795d594fSAndroid Build Coastguard Worker     // IP0 is used internally by the ReadBarrierMarkRegX entry point
138*795d594fSAndroid Build Coastguard Worker     // as a temporary (and not preserved).  It thus cannot be used by
139*795d594fSAndroid Build Coastguard Worker     // any live register in this slow path.
140*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(LocationFrom(src_curr_addr).reg(), IP0);
141*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(LocationFrom(dst_curr_addr).reg(), IP0);
142*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(LocationFrom(src_stop_addr).reg(), IP0);
143*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(tmp_.reg(), IP0);
144*795d594fSAndroid Build Coastguard Worker     DCHECK(0 <= tmp_.reg() && tmp_.reg() < kNumberOfWRegisters) << tmp_.reg();
145*795d594fSAndroid Build Coastguard Worker     // TODO: Load the entrypoint once before the loop, instead of
146*795d594fSAndroid Build Coastguard Worker     // loading it at every iteration.
147*795d594fSAndroid Build Coastguard Worker     int32_t entry_point_offset =
148*795d594fSAndroid Build Coastguard Worker         Thread::ReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(tmp_.reg());
149*795d594fSAndroid Build Coastguard Worker     // This runtime call does not require a stack map.
150*795d594fSAndroid Build Coastguard Worker     codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
151*795d594fSAndroid Build Coastguard Worker     codegen->GetAssembler()->MaybePoisonHeapReference(tmp_reg);
152*795d594fSAndroid Build Coastguard Worker     __ Str(tmp_reg, MemOperand(dst_curr_addr, element_size, PostIndex));
153*795d594fSAndroid Build Coastguard Worker     __ Cmp(src_curr_addr, src_stop_addr);
154*795d594fSAndroid Build Coastguard Worker     __ B(&slow_copy_loop, ne);
155*795d594fSAndroid Build Coastguard Worker     __ B(GetExitLabel());
156*795d594fSAndroid Build Coastguard Worker   }
157*795d594fSAndroid Build Coastguard Worker 
GetDescription() const158*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierSystemArrayCopySlowPathARM64"; }
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker  private:
161*795d594fSAndroid Build Coastguard Worker   Location tmp_;
162*795d594fSAndroid Build Coastguard Worker 
163*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierSystemArrayCopySlowPathARM64);
164*795d594fSAndroid Build Coastguard Worker };
165*795d594fSAndroid Build Coastguard Worker 
166*795d594fSAndroid Build Coastguard Worker // The MethodHandle.invokeExact intrinsic sets up arguments to match the target method call. If we
167*795d594fSAndroid Build Coastguard Worker // need to go to the slow path, we call art_quick_invoke_polymorphic_with_hidden_receiver, which
168*795d594fSAndroid Build Coastguard Worker // expects the MethodHandle object in w0 (in place of the actual ArtMethod).
169*795d594fSAndroid Build Coastguard Worker class InvokePolymorphicSlowPathARM64 : public SlowPathCodeARM64 {
170*795d594fSAndroid Build Coastguard Worker  public:
InvokePolymorphicSlowPathARM64(HInstruction * instruction,Register method_handle)171*795d594fSAndroid Build Coastguard Worker   InvokePolymorphicSlowPathARM64(HInstruction* instruction, Register method_handle)
172*795d594fSAndroid Build Coastguard Worker       : SlowPathCodeARM64(instruction), method_handle_(method_handle) {
173*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction->IsInvokePolymorphic());
174*795d594fSAndroid Build Coastguard Worker   }
175*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen_in)176*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen_in) override {
177*795d594fSAndroid Build Coastguard Worker     CodeGeneratorARM64* codegen = down_cast<CodeGeneratorARM64*>(codegen_in);
178*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
179*795d594fSAndroid Build Coastguard Worker 
180*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, instruction_->GetLocations());
181*795d594fSAndroid Build Coastguard Worker     // Passing `MethodHandle` object as hidden argument.
182*795d594fSAndroid Build Coastguard Worker     __ Mov(w0, method_handle_.W());
183*795d594fSAndroid Build Coastguard Worker     codegen->InvokeRuntime(QuickEntrypointEnum::kQuickInvokePolymorphicWithHiddenReceiver,
184*795d594fSAndroid Build Coastguard Worker                            instruction_,
185*795d594fSAndroid Build Coastguard Worker                            instruction_->GetDexPc());
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, instruction_->GetLocations());
188*795d594fSAndroid Build Coastguard Worker     __ B(GetExitLabel());
189*795d594fSAndroid Build Coastguard Worker   }
190*795d594fSAndroid Build Coastguard Worker 
GetDescription() const191*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "InvokePolymorphicSlowPathARM64"; }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker  private:
194*795d594fSAndroid Build Coastguard Worker   const Register method_handle_;
195*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(InvokePolymorphicSlowPathARM64);
196*795d594fSAndroid Build Coastguard Worker };
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker #undef __
199*795d594fSAndroid Build Coastguard Worker 
TryDispatch(HInvoke * invoke)200*795d594fSAndroid Build Coastguard Worker bool IntrinsicLocationsBuilderARM64::TryDispatch(HInvoke* invoke) {
201*795d594fSAndroid Build Coastguard Worker   Dispatch(invoke);
202*795d594fSAndroid Build Coastguard Worker   LocationSummary* res = invoke->GetLocations();
203*795d594fSAndroid Build Coastguard Worker   if (res == nullptr) {
204*795d594fSAndroid Build Coastguard Worker     return false;
205*795d594fSAndroid Build Coastguard Worker   }
206*795d594fSAndroid Build Coastguard Worker   return res->Intrinsified();
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker #define __ masm->
210*795d594fSAndroid Build Coastguard Worker 
CreateFPToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)211*795d594fSAndroid Build Coastguard Worker static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
212*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
213*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
214*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
215*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
216*795d594fSAndroid Build Coastguard Worker }
217*795d594fSAndroid Build Coastguard Worker 
CreateIntToFPLocations(ArenaAllocator * allocator,HInvoke * invoke)218*795d594fSAndroid Build Coastguard Worker static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
219*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
220*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
221*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
222*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister());
223*795d594fSAndroid Build Coastguard Worker }
224*795d594fSAndroid Build Coastguard Worker 
MoveFPToInt(LocationSummary * locations,bool is64bit,MacroAssembler * masm)225*795d594fSAndroid Build Coastguard Worker static void MoveFPToInt(LocationSummary* locations, bool is64bit, MacroAssembler* masm) {
226*795d594fSAndroid Build Coastguard Worker   Location input = locations->InAt(0);
227*795d594fSAndroid Build Coastguard Worker   Location output = locations->Out();
228*795d594fSAndroid Build Coastguard Worker   __ Fmov(is64bit ? XRegisterFrom(output) : WRegisterFrom(output),
229*795d594fSAndroid Build Coastguard Worker           is64bit ? DRegisterFrom(input) : SRegisterFrom(input));
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker 
MoveIntToFP(LocationSummary * locations,bool is64bit,MacroAssembler * masm)232*795d594fSAndroid Build Coastguard Worker static void MoveIntToFP(LocationSummary* locations, bool is64bit, MacroAssembler* masm) {
233*795d594fSAndroid Build Coastguard Worker   Location input = locations->InAt(0);
234*795d594fSAndroid Build Coastguard Worker   Location output = locations->Out();
235*795d594fSAndroid Build Coastguard Worker   __ Fmov(is64bit ? DRegisterFrom(output) : SRegisterFrom(output),
236*795d594fSAndroid Build Coastguard Worker           is64bit ? XRegisterFrom(input) : WRegisterFrom(input));
237*795d594fSAndroid Build Coastguard Worker }
238*795d594fSAndroid Build Coastguard Worker 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)239*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
240*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke);
241*795d594fSAndroid Build Coastguard Worker }
VisitDoubleLongBitsToDouble(HInvoke * invoke)242*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
243*795d594fSAndroid Build Coastguard Worker   CreateIntToFPLocations(allocator_, invoke);
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)246*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
247*795d594fSAndroid Build Coastguard Worker   MoveFPToInt(invoke->GetLocations(), /* is64bit= */ true, GetVIXLAssembler());
248*795d594fSAndroid Build Coastguard Worker }
VisitDoubleLongBitsToDouble(HInvoke * invoke)249*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
250*795d594fSAndroid Build Coastguard Worker   MoveIntToFP(invoke->GetLocations(), /* is64bit= */ true, GetVIXLAssembler());
251*795d594fSAndroid Build Coastguard Worker }
252*795d594fSAndroid Build Coastguard Worker 
VisitFloatFloatToRawIntBits(HInvoke * invoke)253*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
254*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke);
255*795d594fSAndroid Build Coastguard Worker }
VisitFloatIntBitsToFloat(HInvoke * invoke)256*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
257*795d594fSAndroid Build Coastguard Worker   CreateIntToFPLocations(allocator_, invoke);
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker 
VisitFloatFloatToRawIntBits(HInvoke * invoke)260*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
261*795d594fSAndroid Build Coastguard Worker   MoveFPToInt(invoke->GetLocations(), /* is64bit= */ false, GetVIXLAssembler());
262*795d594fSAndroid Build Coastguard Worker }
VisitFloatIntBitsToFloat(HInvoke * invoke)263*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
264*795d594fSAndroid Build Coastguard Worker   MoveIntToFP(invoke->GetLocations(), /* is64bit= */ false, GetVIXLAssembler());
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker 
CreateIntToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)267*795d594fSAndroid Build Coastguard Worker static void CreateIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
268*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
269*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
270*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
271*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker 
CreateIntIntToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)274*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
275*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
276*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
277*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
278*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
279*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
280*795d594fSAndroid Build Coastguard Worker }
281*795d594fSAndroid Build Coastguard Worker 
CreateIntIntToIntSlowPathCallLocations(ArenaAllocator * allocator,HInvoke * invoke)282*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToIntSlowPathCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
283*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
284*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
285*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
286*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
287*795d594fSAndroid Build Coastguard Worker   // Force kOutputOverlap; see comments in IntrinsicSlowPath::EmitNativeCode.
288*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
289*795d594fSAndroid Build Coastguard Worker }
290*795d594fSAndroid Build Coastguard Worker 
GenerateReverseBytes(MacroAssembler * masm,DataType::Type type,CPURegister in,CPURegister out)291*795d594fSAndroid Build Coastguard Worker static void GenerateReverseBytes(MacroAssembler* masm,
292*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type,
293*795d594fSAndroid Build Coastguard Worker                                  CPURegister in,
294*795d594fSAndroid Build Coastguard Worker                                  CPURegister out) {
295*795d594fSAndroid Build Coastguard Worker   switch (type) {
296*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
297*795d594fSAndroid Build Coastguard Worker       __ Rev16(out.W(), in.W());
298*795d594fSAndroid Build Coastguard Worker       break;
299*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
300*795d594fSAndroid Build Coastguard Worker       __ Rev16(out.W(), in.W());
301*795d594fSAndroid Build Coastguard Worker       __ Sxth(out.W(), out.W());
302*795d594fSAndroid Build Coastguard Worker       break;
303*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
304*795d594fSAndroid Build Coastguard Worker       __ Rev(out.W(), in.W());
305*795d594fSAndroid Build Coastguard Worker       break;
306*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
307*795d594fSAndroid Build Coastguard Worker       __ Rev(out.X(), in.X());
308*795d594fSAndroid Build Coastguard Worker       break;
309*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
310*795d594fSAndroid Build Coastguard Worker       __ Rev(in.W(), in.W());  // Note: Clobbers `in`.
311*795d594fSAndroid Build Coastguard Worker       __ Fmov(out.S(), in.W());
312*795d594fSAndroid Build Coastguard Worker       break;
313*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
314*795d594fSAndroid Build Coastguard Worker       __ Rev(in.X(), in.X());  // Note: Clobbers `in`.
315*795d594fSAndroid Build Coastguard Worker       __ Fmov(out.D(), in.X());
316*795d594fSAndroid Build Coastguard Worker       break;
317*795d594fSAndroid Build Coastguard Worker     default:
318*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for reverse-bytes: " << type;
319*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
320*795d594fSAndroid Build Coastguard Worker   }
321*795d594fSAndroid Build Coastguard Worker }
322*795d594fSAndroid Build Coastguard Worker 
GenReverseBytes(LocationSummary * locations,DataType::Type type,MacroAssembler * masm)323*795d594fSAndroid Build Coastguard Worker static void GenReverseBytes(LocationSummary* locations,
324*795d594fSAndroid Build Coastguard Worker                             DataType::Type type,
325*795d594fSAndroid Build Coastguard Worker                             MacroAssembler* masm) {
326*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
327*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
328*795d594fSAndroid Build Coastguard Worker   GenerateReverseBytes(masm, type, CPURegisterFrom(in, type), CPURegisterFrom(out, type));
329*795d594fSAndroid Build Coastguard Worker }
330*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverseBytes(HInvoke * invoke)331*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerReverseBytes(HInvoke* invoke) {
332*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
333*795d594fSAndroid Build Coastguard Worker }
334*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverseBytes(HInvoke * invoke)335*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerReverseBytes(HInvoke* invoke) {
336*795d594fSAndroid Build Coastguard Worker   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker 
VisitLongReverseBytes(HInvoke * invoke)339*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongReverseBytes(HInvoke* invoke) {
340*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
341*795d594fSAndroid Build Coastguard Worker }
342*795d594fSAndroid Build Coastguard Worker 
VisitLongReverseBytes(HInvoke * invoke)343*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongReverseBytes(HInvoke* invoke) {
344*795d594fSAndroid Build Coastguard Worker   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
345*795d594fSAndroid Build Coastguard Worker }
346*795d594fSAndroid Build Coastguard Worker 
VisitShortReverseBytes(HInvoke * invoke)347*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitShortReverseBytes(HInvoke* invoke) {
348*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
349*795d594fSAndroid Build Coastguard Worker }
350*795d594fSAndroid Build Coastguard Worker 
VisitShortReverseBytes(HInvoke * invoke)351*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitShortReverseBytes(HInvoke* invoke) {
352*795d594fSAndroid Build Coastguard Worker   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetVIXLAssembler());
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker 
GenNumberOfLeadingZeros(LocationSummary * locations,DataType::Type type,MacroAssembler * masm)355*795d594fSAndroid Build Coastguard Worker static void GenNumberOfLeadingZeros(LocationSummary* locations,
356*795d594fSAndroid Build Coastguard Worker                                     DataType::Type type,
357*795d594fSAndroid Build Coastguard Worker                                     MacroAssembler* masm) {
358*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
359*795d594fSAndroid Build Coastguard Worker 
360*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
361*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
362*795d594fSAndroid Build Coastguard Worker 
363*795d594fSAndroid Build Coastguard Worker   __ Clz(RegisterFrom(out, type), RegisterFrom(in, type));
364*795d594fSAndroid Build Coastguard Worker }
365*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)366*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
367*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
368*795d594fSAndroid Build Coastguard Worker }
369*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)370*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
371*795d594fSAndroid Build Coastguard Worker   GenNumberOfLeadingZeros(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
372*795d594fSAndroid Build Coastguard Worker }
373*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)374*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
375*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
376*795d594fSAndroid Build Coastguard Worker }
377*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)378*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
379*795d594fSAndroid Build Coastguard Worker   GenNumberOfLeadingZeros(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
380*795d594fSAndroid Build Coastguard Worker }
381*795d594fSAndroid Build Coastguard Worker 
GenNumberOfTrailingZeros(LocationSummary * locations,DataType::Type type,MacroAssembler * masm)382*795d594fSAndroid Build Coastguard Worker static void GenNumberOfTrailingZeros(LocationSummary* locations,
383*795d594fSAndroid Build Coastguard Worker                                      DataType::Type type,
384*795d594fSAndroid Build Coastguard Worker                                      MacroAssembler* masm) {
385*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
386*795d594fSAndroid Build Coastguard Worker 
387*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
388*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker   __ Rbit(RegisterFrom(out, type), RegisterFrom(in, type));
391*795d594fSAndroid Build Coastguard Worker   __ Clz(RegisterFrom(out, type), RegisterFrom(out, type));
392*795d594fSAndroid Build Coastguard Worker }
393*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)394*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
395*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
396*795d594fSAndroid Build Coastguard Worker }
397*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)398*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
399*795d594fSAndroid Build Coastguard Worker   GenNumberOfTrailingZeros(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)402*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
403*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)406*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
407*795d594fSAndroid Build Coastguard Worker   GenNumberOfTrailingZeros(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker 
GenReverse(LocationSummary * locations,DataType::Type type,MacroAssembler * masm)410*795d594fSAndroid Build Coastguard Worker static void GenReverse(LocationSummary* locations,
411*795d594fSAndroid Build Coastguard Worker                        DataType::Type type,
412*795d594fSAndroid Build Coastguard Worker                        MacroAssembler* masm) {
413*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
416*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
417*795d594fSAndroid Build Coastguard Worker 
418*795d594fSAndroid Build Coastguard Worker   __ Rbit(RegisterFrom(out, type), RegisterFrom(in, type));
419*795d594fSAndroid Build Coastguard Worker }
420*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverse(HInvoke * invoke)421*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerReverse(HInvoke* invoke) {
422*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
423*795d594fSAndroid Build Coastguard Worker }
424*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverse(HInvoke * invoke)425*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerReverse(HInvoke* invoke) {
426*795d594fSAndroid Build Coastguard Worker   GenReverse(invoke->GetLocations(), DataType::Type::kInt32, GetVIXLAssembler());
427*795d594fSAndroid Build Coastguard Worker }
428*795d594fSAndroid Build Coastguard Worker 
VisitLongReverse(HInvoke * invoke)429*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongReverse(HInvoke* invoke) {
430*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
431*795d594fSAndroid Build Coastguard Worker }
432*795d594fSAndroid Build Coastguard Worker 
VisitLongReverse(HInvoke * invoke)433*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongReverse(HInvoke* invoke) {
434*795d594fSAndroid Build Coastguard Worker   GenReverse(invoke->GetLocations(), DataType::Type::kInt64, GetVIXLAssembler());
435*795d594fSAndroid Build Coastguard Worker }
436*795d594fSAndroid Build Coastguard Worker 
GenBitCount(HInvoke * instr,DataType::Type type,MacroAssembler * masm)437*795d594fSAndroid Build Coastguard Worker static void GenBitCount(HInvoke* instr, DataType::Type type, MacroAssembler* masm) {
438*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsIntOrLongType(type)) << type;
439*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(instr->GetType(), DataType::Type::kInt32);
440*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(DataType::Kind(instr->InputAt(0)->GetType()), type);
441*795d594fSAndroid Build Coastguard Worker 
442*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
443*795d594fSAndroid Build Coastguard Worker 
444*795d594fSAndroid Build Coastguard Worker   Register src = InputRegisterAt(instr, 0);
445*795d594fSAndroid Build Coastguard Worker   Register dst = RegisterFrom(instr->GetLocations()->Out(), type);
446*795d594fSAndroid Build Coastguard Worker   VRegister fpr = (type == DataType::Type::kInt64) ? temps.AcquireD() : temps.AcquireS();
447*795d594fSAndroid Build Coastguard Worker 
448*795d594fSAndroid Build Coastguard Worker   __ Fmov(fpr, src);
449*795d594fSAndroid Build Coastguard Worker   __ Cnt(fpr.V8B(), fpr.V8B());
450*795d594fSAndroid Build Coastguard Worker   __ Addv(fpr.B(), fpr.V8B());
451*795d594fSAndroid Build Coastguard Worker   __ Fmov(dst, fpr);
452*795d594fSAndroid Build Coastguard Worker }
453*795d594fSAndroid Build Coastguard Worker 
VisitLongBitCount(HInvoke * invoke)454*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongBitCount(HInvoke* invoke) {
455*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
456*795d594fSAndroid Build Coastguard Worker }
457*795d594fSAndroid Build Coastguard Worker 
VisitLongBitCount(HInvoke * invoke)458*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongBitCount(HInvoke* invoke) {
459*795d594fSAndroid Build Coastguard Worker   GenBitCount(invoke, DataType::Type::kInt64, GetVIXLAssembler());
460*795d594fSAndroid Build Coastguard Worker }
461*795d594fSAndroid Build Coastguard Worker 
VisitIntegerBitCount(HInvoke * invoke)462*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerBitCount(HInvoke* invoke) {
463*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
464*795d594fSAndroid Build Coastguard Worker }
465*795d594fSAndroid Build Coastguard Worker 
VisitIntegerBitCount(HInvoke * invoke)466*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerBitCount(HInvoke* invoke) {
467*795d594fSAndroid Build Coastguard Worker   GenBitCount(invoke, DataType::Type::kInt32, GetVIXLAssembler());
468*795d594fSAndroid Build Coastguard Worker }
469*795d594fSAndroid Build Coastguard Worker 
GenHighestOneBit(HInvoke * invoke,DataType::Type type,MacroAssembler * masm)470*795d594fSAndroid Build Coastguard Worker static void GenHighestOneBit(HInvoke* invoke, DataType::Type type, MacroAssembler* masm) {
471*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
472*795d594fSAndroid Build Coastguard Worker 
473*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
474*795d594fSAndroid Build Coastguard Worker 
475*795d594fSAndroid Build Coastguard Worker   Register src = InputRegisterAt(invoke, 0);
476*795d594fSAndroid Build Coastguard Worker   Register dst = RegisterFrom(invoke->GetLocations()->Out(), type);
477*795d594fSAndroid Build Coastguard Worker   Register temp = (type == DataType::Type::kInt64) ? temps.AcquireX() : temps.AcquireW();
478*795d594fSAndroid Build Coastguard Worker   size_t high_bit = (type == DataType::Type::kInt64) ? 63u : 31u;
479*795d594fSAndroid Build Coastguard Worker   size_t clz_high_bit = (type == DataType::Type::kInt64) ? 6u : 5u;
480*795d594fSAndroid Build Coastguard Worker 
481*795d594fSAndroid Build Coastguard Worker   __ Clz(temp, src);
482*795d594fSAndroid Build Coastguard Worker   __ Mov(dst, UINT64_C(1) << high_bit);  // MOV (bitmask immediate)
483*795d594fSAndroid Build Coastguard Worker   __ Bic(dst, dst, Operand(temp, LSL, high_bit - clz_high_bit));  // Clear dst if src was 0.
484*795d594fSAndroid Build Coastguard Worker   __ Lsr(dst, dst, temp);
485*795d594fSAndroid Build Coastguard Worker }
486*795d594fSAndroid Build Coastguard Worker 
VisitIntegerHighestOneBit(HInvoke * invoke)487*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerHighestOneBit(HInvoke* invoke) {
488*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
489*795d594fSAndroid Build Coastguard Worker }
490*795d594fSAndroid Build Coastguard Worker 
VisitIntegerHighestOneBit(HInvoke * invoke)491*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerHighestOneBit(HInvoke* invoke) {
492*795d594fSAndroid Build Coastguard Worker   GenHighestOneBit(invoke, DataType::Type::kInt32, GetVIXLAssembler());
493*795d594fSAndroid Build Coastguard Worker }
494*795d594fSAndroid Build Coastguard Worker 
VisitLongHighestOneBit(HInvoke * invoke)495*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongHighestOneBit(HInvoke* invoke) {
496*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
497*795d594fSAndroid Build Coastguard Worker }
498*795d594fSAndroid Build Coastguard Worker 
VisitLongHighestOneBit(HInvoke * invoke)499*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongHighestOneBit(HInvoke* invoke) {
500*795d594fSAndroid Build Coastguard Worker   GenHighestOneBit(invoke, DataType::Type::kInt64, GetVIXLAssembler());
501*795d594fSAndroid Build Coastguard Worker }
502*795d594fSAndroid Build Coastguard Worker 
GenLowestOneBit(HInvoke * invoke,DataType::Type type,MacroAssembler * masm)503*795d594fSAndroid Build Coastguard Worker static void GenLowestOneBit(HInvoke* invoke, DataType::Type type, MacroAssembler* masm) {
504*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
505*795d594fSAndroid Build Coastguard Worker 
506*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
507*795d594fSAndroid Build Coastguard Worker 
508*795d594fSAndroid Build Coastguard Worker   Register src = InputRegisterAt(invoke, 0);
509*795d594fSAndroid Build Coastguard Worker   Register dst = RegisterFrom(invoke->GetLocations()->Out(), type);
510*795d594fSAndroid Build Coastguard Worker   Register temp = (type == DataType::Type::kInt64) ? temps.AcquireX() : temps.AcquireW();
511*795d594fSAndroid Build Coastguard Worker 
512*795d594fSAndroid Build Coastguard Worker   __ Neg(temp, src);
513*795d594fSAndroid Build Coastguard Worker   __ And(dst, temp, src);
514*795d594fSAndroid Build Coastguard Worker }
515*795d594fSAndroid Build Coastguard Worker 
VisitIntegerLowestOneBit(HInvoke * invoke)516*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerLowestOneBit(HInvoke* invoke) {
517*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
518*795d594fSAndroid Build Coastguard Worker }
519*795d594fSAndroid Build Coastguard Worker 
VisitIntegerLowestOneBit(HInvoke * invoke)520*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerLowestOneBit(HInvoke* invoke) {
521*795d594fSAndroid Build Coastguard Worker   GenLowestOneBit(invoke, DataType::Type::kInt32, GetVIXLAssembler());
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker 
VisitLongLowestOneBit(HInvoke * invoke)524*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongLowestOneBit(HInvoke* invoke) {
525*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
526*795d594fSAndroid Build Coastguard Worker }
527*795d594fSAndroid Build Coastguard Worker 
VisitLongLowestOneBit(HInvoke * invoke)528*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongLowestOneBit(HInvoke* invoke) {
529*795d594fSAndroid Build Coastguard Worker   GenLowestOneBit(invoke, DataType::Type::kInt64, GetVIXLAssembler());
530*795d594fSAndroid Build Coastguard Worker }
531*795d594fSAndroid Build Coastguard Worker 
CreateFPToFPLocations(ArenaAllocator * allocator,HInvoke * invoke)532*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
533*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
534*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
535*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
536*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
537*795d594fSAndroid Build Coastguard Worker }
538*795d594fSAndroid Build Coastguard Worker 
VisitMathSqrt(HInvoke * invoke)539*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathSqrt(HInvoke* invoke) {
540*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator_, invoke);
541*795d594fSAndroid Build Coastguard Worker }
542*795d594fSAndroid Build Coastguard Worker 
VisitMathSqrt(HInvoke * invoke)543*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathSqrt(HInvoke* invoke) {
544*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
545*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
546*795d594fSAndroid Build Coastguard Worker   __ Fsqrt(DRegisterFrom(locations->Out()), DRegisterFrom(locations->InAt(0)));
547*795d594fSAndroid Build Coastguard Worker }
548*795d594fSAndroid Build Coastguard Worker 
VisitMathCeil(HInvoke * invoke)549*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathCeil(HInvoke* invoke) {
550*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator_, invoke);
551*795d594fSAndroid Build Coastguard Worker }
552*795d594fSAndroid Build Coastguard Worker 
VisitMathCeil(HInvoke * invoke)553*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathCeil(HInvoke* invoke) {
554*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
555*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
556*795d594fSAndroid Build Coastguard Worker   __ Frintp(DRegisterFrom(locations->Out()), DRegisterFrom(locations->InAt(0)));
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker 
VisitMathFloor(HInvoke * invoke)559*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathFloor(HInvoke* invoke) {
560*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator_, invoke);
561*795d594fSAndroid Build Coastguard Worker }
562*795d594fSAndroid Build Coastguard Worker 
VisitMathFloor(HInvoke * invoke)563*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathFloor(HInvoke* invoke) {
564*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
565*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
566*795d594fSAndroid Build Coastguard Worker   __ Frintm(DRegisterFrom(locations->Out()), DRegisterFrom(locations->InAt(0)));
567*795d594fSAndroid Build Coastguard Worker }
568*795d594fSAndroid Build Coastguard Worker 
VisitMathRint(HInvoke * invoke)569*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathRint(HInvoke* invoke) {
570*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator_, invoke);
571*795d594fSAndroid Build Coastguard Worker }
572*795d594fSAndroid Build Coastguard Worker 
VisitMathRint(HInvoke * invoke)573*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathRint(HInvoke* invoke) {
574*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
575*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
576*795d594fSAndroid Build Coastguard Worker   __ Frintn(DRegisterFrom(locations->Out()), DRegisterFrom(locations->InAt(0)));
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker 
CreateFPToIntPlusFPTempLocations(ArenaAllocator * allocator,HInvoke * invoke)579*795d594fSAndroid Build Coastguard Worker static void CreateFPToIntPlusFPTempLocations(ArenaAllocator* allocator, HInvoke* invoke) {
580*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
581*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
582*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
583*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
584*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresFpuRegister());
585*795d594fSAndroid Build Coastguard Worker }
586*795d594fSAndroid Build Coastguard Worker 
GenMathRound(HInvoke * invoke,bool is_double,vixl::aarch64::MacroAssembler * masm)587*795d594fSAndroid Build Coastguard Worker static void GenMathRound(HInvoke* invoke, bool is_double, vixl::aarch64::MacroAssembler* masm) {
588*795d594fSAndroid Build Coastguard Worker   // Java 8 API definition for Math.round():
589*795d594fSAndroid Build Coastguard Worker   // Return the closest long or int to the argument, with ties rounding to positive infinity.
590*795d594fSAndroid Build Coastguard Worker   //
591*795d594fSAndroid Build Coastguard Worker   // There is no single instruction in ARMv8 that can support the above definition.
592*795d594fSAndroid Build Coastguard Worker   // We choose to use FCVTAS here, because it has closest semantic.
593*795d594fSAndroid Build Coastguard Worker   // FCVTAS performs rounding to nearest integer, ties away from zero.
594*795d594fSAndroid Build Coastguard Worker   // For most inputs (positive values, zero or NaN), this instruction is enough.
595*795d594fSAndroid Build Coastguard Worker   // We only need a few handling code after FCVTAS if the input is negative half value.
596*795d594fSAndroid Build Coastguard Worker   //
597*795d594fSAndroid Build Coastguard Worker   // The reason why we didn't choose FCVTPS instruction here is that
598*795d594fSAndroid Build Coastguard Worker   // although it performs rounding toward positive infinity, it doesn't perform rounding to nearest.
599*795d594fSAndroid Build Coastguard Worker   // For example, FCVTPS(-1.9) = -1 and FCVTPS(1.1) = 2.
600*795d594fSAndroid Build Coastguard Worker   // If we were using this instruction, for most inputs, more handling code would be needed.
601*795d594fSAndroid Build Coastguard Worker   LocationSummary* l = invoke->GetLocations();
602*795d594fSAndroid Build Coastguard Worker   VRegister in_reg = is_double ? DRegisterFrom(l->InAt(0)) : SRegisterFrom(l->InAt(0));
603*795d594fSAndroid Build Coastguard Worker   VRegister tmp_fp = is_double ? DRegisterFrom(l->GetTemp(0)) : SRegisterFrom(l->GetTemp(0));
604*795d594fSAndroid Build Coastguard Worker   Register out_reg = is_double ? XRegisterFrom(l->Out()) : WRegisterFrom(l->Out());
605*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label done;
606*795d594fSAndroid Build Coastguard Worker 
607*795d594fSAndroid Build Coastguard Worker   // Round to nearest integer, ties away from zero.
608*795d594fSAndroid Build Coastguard Worker   __ Fcvtas(out_reg, in_reg);
609*795d594fSAndroid Build Coastguard Worker 
610*795d594fSAndroid Build Coastguard Worker   // For positive values, zero or NaN inputs, rounding is done.
611*795d594fSAndroid Build Coastguard Worker   __ Tbz(out_reg, out_reg.GetSizeInBits() - 1, &done);
612*795d594fSAndroid Build Coastguard Worker 
613*795d594fSAndroid Build Coastguard Worker   // Handle input < 0 cases.
614*795d594fSAndroid Build Coastguard Worker   // If input is negative but not a tie, previous result (round to nearest) is valid.
615*795d594fSAndroid Build Coastguard Worker   // If input is a negative tie, out_reg += 1.
616*795d594fSAndroid Build Coastguard Worker   __ Frinta(tmp_fp, in_reg);
617*795d594fSAndroid Build Coastguard Worker   __ Fsub(tmp_fp, in_reg, tmp_fp);
618*795d594fSAndroid Build Coastguard Worker   __ Fcmp(tmp_fp, 0.5);
619*795d594fSAndroid Build Coastguard Worker   __ Cinc(out_reg, out_reg, eq);
620*795d594fSAndroid Build Coastguard Worker 
621*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundDouble(HInvoke * invoke)624*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathRoundDouble(HInvoke* invoke) {
625*795d594fSAndroid Build Coastguard Worker   CreateFPToIntPlusFPTempLocations(allocator_, invoke);
626*795d594fSAndroid Build Coastguard Worker }
627*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundDouble(HInvoke * invoke)628*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathRoundDouble(HInvoke* invoke) {
629*795d594fSAndroid Build Coastguard Worker   GenMathRound(invoke, /* is_double= */ true, GetVIXLAssembler());
630*795d594fSAndroid Build Coastguard Worker }
631*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundFloat(HInvoke * invoke)632*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathRoundFloat(HInvoke* invoke) {
633*795d594fSAndroid Build Coastguard Worker   CreateFPToIntPlusFPTempLocations(allocator_, invoke);
634*795d594fSAndroid Build Coastguard Worker }
635*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundFloat(HInvoke * invoke)636*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathRoundFloat(HInvoke* invoke) {
637*795d594fSAndroid Build Coastguard Worker   GenMathRound(invoke, /* is_double= */ false, GetVIXLAssembler());
638*795d594fSAndroid Build Coastguard Worker }
639*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekByte(HInvoke * invoke)640*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPeekByte(HInvoke* invoke) {
641*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
642*795d594fSAndroid Build Coastguard Worker }
643*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekByte(HInvoke * invoke)644*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPeekByte(HInvoke* invoke) {
645*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
646*795d594fSAndroid Build Coastguard Worker   __ Ldrsb(WRegisterFrom(invoke->GetLocations()->Out()),
647*795d594fSAndroid Build Coastguard Worker           AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
648*795d594fSAndroid Build Coastguard Worker }
649*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekIntNative(HInvoke * invoke)650*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPeekIntNative(HInvoke* invoke) {
651*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekIntNative(HInvoke * invoke)654*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPeekIntNative(HInvoke* invoke) {
655*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
656*795d594fSAndroid Build Coastguard Worker   __ Ldr(WRegisterFrom(invoke->GetLocations()->Out()),
657*795d594fSAndroid Build Coastguard Worker          AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
658*795d594fSAndroid Build Coastguard Worker }
659*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekLongNative(HInvoke * invoke)660*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPeekLongNative(HInvoke* invoke) {
661*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
662*795d594fSAndroid Build Coastguard Worker }
663*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekLongNative(HInvoke * invoke)664*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPeekLongNative(HInvoke* invoke) {
665*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
666*795d594fSAndroid Build Coastguard Worker   __ Ldr(XRegisterFrom(invoke->GetLocations()->Out()),
667*795d594fSAndroid Build Coastguard Worker          AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
668*795d594fSAndroid Build Coastguard Worker }
669*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekShortNative(HInvoke * invoke)670*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPeekShortNative(HInvoke* invoke) {
671*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
672*795d594fSAndroid Build Coastguard Worker }
673*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekShortNative(HInvoke * invoke)674*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPeekShortNative(HInvoke* invoke) {
675*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
676*795d594fSAndroid Build Coastguard Worker   __ Ldrsh(WRegisterFrom(invoke->GetLocations()->Out()),
677*795d594fSAndroid Build Coastguard Worker            AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
678*795d594fSAndroid Build Coastguard Worker }
679*795d594fSAndroid Build Coastguard Worker 
CreateIntIntToVoidLocations(ArenaAllocator * allocator,HInvoke * invoke)680*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
681*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
682*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
683*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
684*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
685*795d594fSAndroid Build Coastguard Worker }
686*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeByte(HInvoke * invoke)687*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPokeByte(HInvoke* invoke) {
688*795d594fSAndroid Build Coastguard Worker   CreateIntIntToVoidLocations(allocator_, invoke);
689*795d594fSAndroid Build Coastguard Worker }
690*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeByte(HInvoke * invoke)691*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPokeByte(HInvoke* invoke) {
692*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
693*795d594fSAndroid Build Coastguard Worker   __ Strb(WRegisterFrom(invoke->GetLocations()->InAt(1)),
694*795d594fSAndroid Build Coastguard Worker           AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
695*795d594fSAndroid Build Coastguard Worker }
696*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeIntNative(HInvoke * invoke)697*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPokeIntNative(HInvoke* invoke) {
698*795d594fSAndroid Build Coastguard Worker   CreateIntIntToVoidLocations(allocator_, invoke);
699*795d594fSAndroid Build Coastguard Worker }
700*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeIntNative(HInvoke * invoke)701*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPokeIntNative(HInvoke* invoke) {
702*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
703*795d594fSAndroid Build Coastguard Worker   __ Str(WRegisterFrom(invoke->GetLocations()->InAt(1)),
704*795d594fSAndroid Build Coastguard Worker          AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
705*795d594fSAndroid Build Coastguard Worker }
706*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeLongNative(HInvoke * invoke)707*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPokeLongNative(HInvoke* invoke) {
708*795d594fSAndroid Build Coastguard Worker   CreateIntIntToVoidLocations(allocator_, invoke);
709*795d594fSAndroid Build Coastguard Worker }
710*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeLongNative(HInvoke * invoke)711*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPokeLongNative(HInvoke* invoke) {
712*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
713*795d594fSAndroid Build Coastguard Worker   __ Str(XRegisterFrom(invoke->GetLocations()->InAt(1)),
714*795d594fSAndroid Build Coastguard Worker          AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
715*795d594fSAndroid Build Coastguard Worker }
716*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeShortNative(HInvoke * invoke)717*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMemoryPokeShortNative(HInvoke* invoke) {
718*795d594fSAndroid Build Coastguard Worker   CreateIntIntToVoidLocations(allocator_, invoke);
719*795d594fSAndroid Build Coastguard Worker }
720*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeShortNative(HInvoke * invoke)721*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMemoryPokeShortNative(HInvoke* invoke) {
722*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
723*795d594fSAndroid Build Coastguard Worker   __ Strh(WRegisterFrom(invoke->GetLocations()->InAt(1)),
724*795d594fSAndroid Build Coastguard Worker           AbsoluteHeapOperandFrom(invoke->GetLocations()->InAt(0), 0));
725*795d594fSAndroid Build Coastguard Worker }
726*795d594fSAndroid Build Coastguard Worker 
VisitThreadCurrentThread(HInvoke * invoke)727*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitThreadCurrentThread(HInvoke* invoke) {
728*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
729*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
730*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
731*795d594fSAndroid Build Coastguard Worker }
732*795d594fSAndroid Build Coastguard Worker 
VisitThreadCurrentThread(HInvoke * invoke)733*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitThreadCurrentThread(HInvoke* invoke) {
734*795d594fSAndroid Build Coastguard Worker   codegen_->Load(DataType::Type::kReference, WRegisterFrom(invoke->GetLocations()->Out()),
735*795d594fSAndroid Build Coastguard Worker                  MemOperand(tr, Thread::PeerOffset<kArm64PointerSize>().Int32Value()));
736*795d594fSAndroid Build Coastguard Worker }
737*795d594fSAndroid Build Coastguard Worker 
ReadBarrierNeedsTemp(bool is_volatile,HInvoke * invoke)738*795d594fSAndroid Build Coastguard Worker static bool ReadBarrierNeedsTemp(bool is_volatile, HInvoke* invoke) {
739*795d594fSAndroid Build Coastguard Worker   return is_volatile ||
740*795d594fSAndroid Build Coastguard Worker       !invoke->InputAt(2)->IsLongConstant() ||
741*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(2)->AsLongConstant()->GetValue() >= kReferenceLoadMinFarOffset;
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGet(HInvoke * invoke,DataType::Type type,bool is_volatile,CodeGeneratorARM64 * codegen)744*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGet(HInvoke* invoke,
745*795d594fSAndroid Build Coastguard Worker                          DataType::Type type,
746*795d594fSAndroid Build Coastguard Worker                          bool is_volatile,
747*795d594fSAndroid Build Coastguard Worker                          CodeGeneratorARM64* codegen) {
748*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
749*795d594fSAndroid Build Coastguard Worker   DCHECK((type == DataType::Type::kInt8) ||
750*795d594fSAndroid Build Coastguard Worker          (type == DataType::Type::kInt32) ||
751*795d594fSAndroid Build Coastguard Worker          (type == DataType::Type::kInt64) ||
752*795d594fSAndroid Build Coastguard Worker          (type == DataType::Type::kReference));
753*795d594fSAndroid Build Coastguard Worker   Location base_loc = locations->InAt(1);
754*795d594fSAndroid Build Coastguard Worker   Register base = WRegisterFrom(base_loc);      // Object pointer.
755*795d594fSAndroid Build Coastguard Worker   Location offset_loc = locations->InAt(2);
756*795d594fSAndroid Build Coastguard Worker   Location trg_loc = locations->Out();
757*795d594fSAndroid Build Coastguard Worker   Register trg = RegisterFrom(trg_loc, type);
758*795d594fSAndroid Build Coastguard Worker 
759*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference && codegen->EmitBakerReadBarrier()) {
760*795d594fSAndroid Build Coastguard Worker     // UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case.
761*795d594fSAndroid Build Coastguard Worker     Register temp = WRegisterFrom(locations->GetTemp(0));
762*795d594fSAndroid Build Coastguard Worker     MacroAssembler* masm = codegen->GetVIXLAssembler();
763*795d594fSAndroid Build Coastguard Worker     // Piggy-back on the field load path using introspection for the Baker read barrier.
764*795d594fSAndroid Build Coastguard Worker     if (offset_loc.IsConstant()) {
765*795d594fSAndroid Build Coastguard Worker       uint32_t offset = Int64FromLocation(offset_loc);
766*795d594fSAndroid Build Coastguard Worker       Location maybe_temp = ReadBarrierNeedsTemp(is_volatile, invoke)
767*795d594fSAndroid Build Coastguard Worker           ? locations->GetTemp(0) : Location::NoLocation();
768*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(locations->GetTempCount(), ReadBarrierNeedsTemp(is_volatile, invoke));
769*795d594fSAndroid Build Coastguard Worker       codegen->GenerateFieldLoadWithBakerReadBarrier(invoke,
770*795d594fSAndroid Build Coastguard Worker                                                      trg_loc,
771*795d594fSAndroid Build Coastguard Worker                                                      base.W(),
772*795d594fSAndroid Build Coastguard Worker                                                      offset,
773*795d594fSAndroid Build Coastguard Worker                                                      maybe_temp,
774*795d594fSAndroid Build Coastguard Worker                                                      /* needs_null_check= */ false,
775*795d594fSAndroid Build Coastguard Worker                                                      is_volatile);
776*795d594fSAndroid Build Coastguard Worker     } else {
777*795d594fSAndroid Build Coastguard Worker       __ Add(temp, base, WRegisterFrom(offset_loc));  // Offset should not exceed 32 bits.
778*795d594fSAndroid Build Coastguard Worker       codegen->GenerateFieldLoadWithBakerReadBarrier(invoke,
779*795d594fSAndroid Build Coastguard Worker                                                      trg_loc,
780*795d594fSAndroid Build Coastguard Worker                                                      base,
781*795d594fSAndroid Build Coastguard Worker                                                      MemOperand(temp.X()),
782*795d594fSAndroid Build Coastguard Worker                                                      /* needs_null_check= */ false,
783*795d594fSAndroid Build Coastguard Worker                                                      is_volatile);
784*795d594fSAndroid Build Coastguard Worker     }
785*795d594fSAndroid Build Coastguard Worker   } else {
786*795d594fSAndroid Build Coastguard Worker     // Other cases.
787*795d594fSAndroid Build Coastguard Worker     MemOperand mem_op;
788*795d594fSAndroid Build Coastguard Worker     if (offset_loc.IsConstant()) {
789*795d594fSAndroid Build Coastguard Worker       mem_op = MemOperand(base.X(), Int64FromLocation(offset_loc));
790*795d594fSAndroid Build Coastguard Worker     } else {
791*795d594fSAndroid Build Coastguard Worker       mem_op = MemOperand(base.X(), XRegisterFrom(offset_loc));
792*795d594fSAndroid Build Coastguard Worker     }
793*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
794*795d594fSAndroid Build Coastguard Worker       codegen->LoadAcquire(invoke, type, trg, mem_op, /* needs_null_check= */ true);
795*795d594fSAndroid Build Coastguard Worker     } else {
796*795d594fSAndroid Build Coastguard Worker       codegen->Load(type, trg, mem_op);
797*795d594fSAndroid Build Coastguard Worker     }
798*795d594fSAndroid Build Coastguard Worker 
799*795d594fSAndroid Build Coastguard Worker     if (type == DataType::Type::kReference) {
800*795d594fSAndroid Build Coastguard Worker       DCHECK(trg.IsW());
801*795d594fSAndroid Build Coastguard Worker       codegen->MaybeGenerateReadBarrierSlow(invoke, trg_loc, trg_loc, base_loc, 0u, offset_loc);
802*795d594fSAndroid Build Coastguard Worker     }
803*795d594fSAndroid Build Coastguard Worker   }
804*795d594fSAndroid Build Coastguard Worker }
805*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGetAbsolute(HInvoke * invoke,DataType::Type type,bool is_volatile,CodeGeneratorARM64 * codegen)806*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAbsolute(HInvoke* invoke,
807*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type,
808*795d594fSAndroid Build Coastguard Worker                                  bool is_volatile,
809*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorARM64* codegen) {
810*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
811*795d594fSAndroid Build Coastguard Worker   DCHECK((type == DataType::Type::kInt8) ||
812*795d594fSAndroid Build Coastguard Worker          (type == DataType::Type::kInt32) ||
813*795d594fSAndroid Build Coastguard Worker          (type == DataType::Type::kInt64));
814*795d594fSAndroid Build Coastguard Worker   Location address_loc = locations->InAt(1);
815*795d594fSAndroid Build Coastguard Worker   MemOperand mem_op = MemOperand(XRegisterFrom(address_loc));
816*795d594fSAndroid Build Coastguard Worker   Location trg_loc = locations->Out();
817*795d594fSAndroid Build Coastguard Worker   Register trg = RegisterFrom(trg_loc, type);
818*795d594fSAndroid Build Coastguard Worker 
819*795d594fSAndroid Build Coastguard Worker   if (is_volatile) {
820*795d594fSAndroid Build Coastguard Worker     codegen->LoadAcquire(invoke, type, trg, mem_op, /* needs_null_check= */ true);
821*795d594fSAndroid Build Coastguard Worker   } else {
822*795d594fSAndroid Build Coastguard Worker     codegen->Load(type, trg, mem_op);
823*795d594fSAndroid Build Coastguard Worker   }
824*795d594fSAndroid Build Coastguard Worker }
825*795d594fSAndroid Build Coastguard Worker 
CreateUnsafeGetLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorARM64 * codegen,bool is_volatile=false)826*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetLocations(ArenaAllocator* allocator,
827*795d594fSAndroid Build Coastguard Worker                                      HInvoke* invoke,
828*795d594fSAndroid Build Coastguard Worker                                      CodeGeneratorARM64* codegen,
829*795d594fSAndroid Build Coastguard Worker                                      bool is_volatile = false) {
830*795d594fSAndroid Build Coastguard Worker   bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetReference(invoke);
831*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
832*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
833*795d594fSAndroid Build Coastguard Worker                                       can_call
834*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
835*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
836*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
837*795d594fSAndroid Build Coastguard Worker   if (can_call && kUseBakerReadBarrier) {
838*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
839*795d594fSAndroid Build Coastguard Worker     if (ReadBarrierNeedsTemp(is_volatile, invoke)) {
840*795d594fSAndroid Build Coastguard Worker       // We need a temporary register for the read barrier load in order to use
841*795d594fSAndroid Build Coastguard Worker       // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier().
842*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(FixedTempLocation());
843*795d594fSAndroid Build Coastguard Worker     }
844*795d594fSAndroid Build Coastguard Worker   }
845*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
846*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
847*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RegisterOrConstant(invoke->InputAt(2)));
848*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(),
849*795d594fSAndroid Build Coastguard Worker                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
850*795d594fSAndroid Build Coastguard Worker }
851*795d594fSAndroid Build Coastguard Worker 
CreateUnsafeGetAbsoluteLocations(ArenaAllocator * allocator,HInvoke * invoke)852*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetAbsoluteLocations(ArenaAllocator* allocator,
853*795d594fSAndroid Build Coastguard Worker                                              HInvoke* invoke) {
854*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
855*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
856*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
857*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
858*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
859*795d594fSAndroid Build Coastguard Worker }
860*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGet(HInvoke * invoke)861*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGet(HInvoke* invoke) {
862*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGet(invoke);
863*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAbsolute(HInvoke * invoke)864*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAbsolute(HInvoke* invoke) {
865*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAbsolute(invoke);
866*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetVolatile(HInvoke * invoke)867*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetVolatile(HInvoke* invoke) {
868*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetVolatile(invoke);
869*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLong(HInvoke * invoke)870*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetLong(HInvoke* invoke) {
871*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLong(invoke);
872*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLongVolatile(HInvoke * invoke)873*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
874*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLongVolatile(invoke);
875*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObject(HInvoke * invoke)876*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetObject(HInvoke* invoke) {
877*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReference(invoke);
878*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)879*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
880*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReferenceVolatile(invoke);
881*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetByte(HInvoke * invoke)882*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetByte(HInvoke* invoke) {
883*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetByte(invoke);
884*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGet(HInvoke * invoke)885*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGet(HInvoke* invoke) {
886*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_);
887*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)888*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
889*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAbsoluteLocations(allocator_, invoke);
890*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetVolatile(HInvoke * invoke)891*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
892*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
893*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAcquire(HInvoke * invoke)894*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
895*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
896*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLong(HInvoke * invoke)897*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetLong(HInvoke* invoke) {
898*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_);
899*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)900*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
901*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
902*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)903*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
904*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
905*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReference(HInvoke * invoke)906*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetReference(HInvoke* invoke) {
907*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_);
908*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)909*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
910*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
911*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)912*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
913*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_, /* is_volatile= */ true);
914*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetByte(HInvoke * invoke)915*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
916*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetLocations(allocator_, invoke, codegen_);
917*795d594fSAndroid Build Coastguard Worker }
918*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGet(HInvoke * invoke)919*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGet(HInvoke* invoke) {
920*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGet(invoke);
921*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAbsolute(HInvoke * invoke)922*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAbsolute(HInvoke* invoke) {
923*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAbsolute(invoke);
924*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetVolatile(HInvoke * invoke)925*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetVolatile(HInvoke* invoke) {
926*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetVolatile(invoke);
927*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLong(HInvoke * invoke)928*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLong(HInvoke* invoke) {
929*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLong(invoke);
930*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLongVolatile(HInvoke * invoke)931*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
932*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLongVolatile(invoke);
933*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObject(HInvoke * invoke)934*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObject(HInvoke* invoke) {
935*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReference(invoke);
936*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)937*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
938*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReferenceVolatile(invoke);
939*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetByte(HInvoke * invoke)940*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetByte(HInvoke* invoke) {
941*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetByte(invoke);
942*795d594fSAndroid Build Coastguard Worker }
943*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGet(HInvoke * invoke)944*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGet(HInvoke* invoke) {
945*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
946*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)947*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
948*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAbsolute(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
949*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetVolatile(HInvoke * invoke)950*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
951*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
952*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAcquire(HInvoke * invoke)953*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
954*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
955*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLong(HInvoke * invoke)956*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetLong(HInvoke* invoke) {
957*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ false, codegen_);
958*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)959*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
960*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
961*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)962*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
963*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
964*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReference(HInvoke * invoke)965*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetReference(HInvoke* invoke) {
966*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ false, codegen_);
967*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)968*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
969*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
970*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)971*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
972*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
973*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetByte(HInvoke * invoke)974*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
975*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
976*795d594fSAndroid Build Coastguard Worker }
977*795d594fSAndroid Build Coastguard Worker 
CreateUnsafePutLocations(ArenaAllocator * allocator,HInvoke * invoke)978*795d594fSAndroid Build Coastguard Worker static void CreateUnsafePutLocations(ArenaAllocator* allocator, HInvoke* invoke) {
979*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
980*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
981*795d594fSAndroid Build Coastguard Worker   static constexpr int kOffsetIndex = 2;
982*795d594fSAndroid Build Coastguard Worker   static constexpr int kValueIndex = 3;
983*795d594fSAndroid Build Coastguard Worker   // Unused receiver.
984*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());
985*795d594fSAndroid Build Coastguard Worker   // The object.
986*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
987*795d594fSAndroid Build Coastguard Worker   // The offset.
988*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(
989*795d594fSAndroid Build Coastguard Worker       kOffsetIndex, Location::RegisterOrConstant(invoke->InputAt(kOffsetIndex)));
990*795d594fSAndroid Build Coastguard Worker   // The value.
991*795d594fSAndroid Build Coastguard Worker   if (IsZeroBitPattern(invoke->InputAt(kValueIndex))) {
992*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(kValueIndex, Location::ConstantLocation(invoke->InputAt(kValueIndex)));
993*795d594fSAndroid Build Coastguard Worker   } else {
994*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(kValueIndex, Location::RequiresRegister());
995*795d594fSAndroid Build Coastguard Worker   }
996*795d594fSAndroid Build Coastguard Worker }
997*795d594fSAndroid Build Coastguard Worker 
CreateUnsafePutAbsoluteLocations(ArenaAllocator * allocator,HInvoke * invoke)998*795d594fSAndroid Build Coastguard Worker static void CreateUnsafePutAbsoluteLocations(ArenaAllocator* allocator, HInvoke* invoke) {
999*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1000*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1001*795d594fSAndroid Build Coastguard Worker   static constexpr int kAddressIndex = 1;
1002*795d594fSAndroid Build Coastguard Worker   static constexpr int kValueIndex = 2;
1003*795d594fSAndroid Build Coastguard Worker   // Unused receiver.
1004*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());
1005*795d594fSAndroid Build Coastguard Worker   // The address.
1006*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(kAddressIndex, Location::RequiresRegister());
1007*795d594fSAndroid Build Coastguard Worker   // The value.
1008*795d594fSAndroid Build Coastguard Worker   if (IsZeroBitPattern(invoke->InputAt(kValueIndex))) {
1009*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(kValueIndex, Location::ConstantLocation(invoke->InputAt(kValueIndex)));
1010*795d594fSAndroid Build Coastguard Worker   } else {
1011*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(kValueIndex, Location::RequiresRegister());
1012*795d594fSAndroid Build Coastguard Worker   }
1013*795d594fSAndroid Build Coastguard Worker }
1014*795d594fSAndroid Build Coastguard Worker 
VisitUnsafePut(HInvoke * invoke)1015*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePut(HInvoke* invoke) {
1016*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePut(invoke);
1017*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutAbsolute(HInvoke * invoke)1018*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutAbsolute(HInvoke* invoke) {
1019*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutAbsolute(invoke);
1020*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutOrdered(HInvoke * invoke)1021*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutOrdered(HInvoke* invoke) {
1022*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutOrdered(invoke);
1023*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutVolatile(HInvoke * invoke)1024*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutVolatile(HInvoke* invoke) {
1025*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutVolatile(invoke);
1026*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObject(HInvoke * invoke)1027*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutObject(HInvoke* invoke) {
1028*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReference(invoke);
1029*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectOrdered(HInvoke * invoke)1030*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1031*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutObjectOrdered(invoke);
1032*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectVolatile(HInvoke * invoke)1033*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1034*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReferenceVolatile(invoke);
1035*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLong(HInvoke * invoke)1036*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutLong(HInvoke* invoke) {
1037*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLong(invoke);
1038*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongOrdered(HInvoke * invoke)1039*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1040*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongOrdered(invoke);
1041*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongVolatile(HInvoke * invoke)1042*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1043*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongVolatile(invoke);
1044*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutByte(HInvoke * invoke)1045*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafePutByte(HInvoke* invoke) {
1046*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutByte(invoke);
1047*795d594fSAndroid Build Coastguard Worker }
1048*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafePut(HInvoke * invoke)1049*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePut(HInvoke* invoke) {
1050*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1051*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutAbsolute(HInvoke * invoke)1052*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
1053*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutAbsoluteLocations(allocator_, invoke);
1054*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutOrdered(HInvoke * invoke)1055*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
1056*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1057*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutVolatile(HInvoke * invoke)1058*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
1059*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1060*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutRelease(HInvoke * invoke)1061*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutRelease(HInvoke* invoke) {
1062*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1063*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReference(HInvoke * invoke)1064*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutReference(HInvoke* invoke) {
1065*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1066*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)1067*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
1068*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1069*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)1070*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
1071*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1072*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)1073*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
1074*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1075*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLong(HInvoke * invoke)1076*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutLong(HInvoke* invoke) {
1077*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1078*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)1079*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
1080*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1081*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)1082*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
1083*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1084*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongRelease(HInvoke * invoke)1085*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
1086*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1087*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutByte(HInvoke * invoke)1088*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafePutByte(HInvoke* invoke) {
1089*795d594fSAndroid Build Coastguard Worker   CreateUnsafePutLocations(allocator_, invoke);
1090*795d594fSAndroid Build Coastguard Worker }
1091*795d594fSAndroid Build Coastguard Worker 
GenUnsafePut(HInvoke * invoke,DataType::Type type,bool is_volatile,bool is_ordered,CodeGeneratorARM64 * codegen)1092*795d594fSAndroid Build Coastguard Worker static void GenUnsafePut(HInvoke* invoke,
1093*795d594fSAndroid Build Coastguard Worker                          DataType::Type type,
1094*795d594fSAndroid Build Coastguard Worker                          bool is_volatile,
1095*795d594fSAndroid Build Coastguard Worker                          bool is_ordered,
1096*795d594fSAndroid Build Coastguard Worker                          CodeGeneratorARM64* codegen) {
1097*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1098*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
1099*795d594fSAndroid Build Coastguard Worker 
1100*795d594fSAndroid Build Coastguard Worker   static constexpr int kOffsetIndex = 2;
1101*795d594fSAndroid Build Coastguard Worker   static constexpr int kValueIndex = 3;
1102*795d594fSAndroid Build Coastguard Worker   Register base = WRegisterFrom(locations->InAt(1));    // Object pointer.
1103*795d594fSAndroid Build Coastguard Worker   Location offset = locations->InAt(kOffsetIndex);      // Long offset.
1104*795d594fSAndroid Build Coastguard Worker   CPURegister value = InputCPURegisterOrZeroRegAt(invoke, kValueIndex);
1105*795d594fSAndroid Build Coastguard Worker   CPURegister source = value;
1106*795d594fSAndroid Build Coastguard Worker   MemOperand mem_op;
1107*795d594fSAndroid Build Coastguard Worker   if (offset.IsConstant()) {
1108*795d594fSAndroid Build Coastguard Worker     mem_op = MemOperand(base.X(), Int64FromLocation(offset));
1109*795d594fSAndroid Build Coastguard Worker   } else {
1110*795d594fSAndroid Build Coastguard Worker     mem_op = MemOperand(base.X(), XRegisterFrom(offset));
1111*795d594fSAndroid Build Coastguard Worker   }
1112*795d594fSAndroid Build Coastguard Worker 
1113*795d594fSAndroid Build Coastguard Worker   {
1114*795d594fSAndroid Build Coastguard Worker     // We use a block to end the scratch scope before the write barrier, thus
1115*795d594fSAndroid Build Coastguard Worker     // freeing the temporary registers so they can be used in `MarkGCCard`.
1116*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
1117*795d594fSAndroid Build Coastguard Worker 
1118*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences &&
1119*795d594fSAndroid Build Coastguard Worker         type == DataType::Type::kReference &&
1120*795d594fSAndroid Build Coastguard Worker         !IsZeroBitPattern(invoke->InputAt(kValueIndex))) {
1121*795d594fSAndroid Build Coastguard Worker       DCHECK(value.IsW());
1122*795d594fSAndroid Build Coastguard Worker       Register temp = temps.AcquireW();
1123*795d594fSAndroid Build Coastguard Worker       __ Mov(temp.W(), value.W());
1124*795d594fSAndroid Build Coastguard Worker       codegen->GetAssembler()->PoisonHeapReference(temp.W());
1125*795d594fSAndroid Build Coastguard Worker       source = temp;
1126*795d594fSAndroid Build Coastguard Worker     }
1127*795d594fSAndroid Build Coastguard Worker 
1128*795d594fSAndroid Build Coastguard Worker     if (is_volatile || is_ordered) {
1129*795d594fSAndroid Build Coastguard Worker       codegen->StoreRelease(invoke, type, source, mem_op, /* needs_null_check= */ false);
1130*795d594fSAndroid Build Coastguard Worker     } else {
1131*795d594fSAndroid Build Coastguard Worker       codegen->Store(type, source, mem_op);
1132*795d594fSAndroid Build Coastguard Worker     }
1133*795d594fSAndroid Build Coastguard Worker   }
1134*795d594fSAndroid Build Coastguard Worker 
1135*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference && !IsZeroBitPattern(invoke->InputAt(kValueIndex))) {
1136*795d594fSAndroid Build Coastguard Worker     bool value_can_be_null = true;  // TODO: Worth finding out this information?
1137*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(base, Register(source), value_can_be_null);
1138*795d594fSAndroid Build Coastguard Worker   }
1139*795d594fSAndroid Build Coastguard Worker }
1140*795d594fSAndroid Build Coastguard Worker 
GenUnsafePutAbsolute(HInvoke * invoke,DataType::Type type,bool is_volatile,bool is_ordered,CodeGeneratorARM64 * codegen)1141*795d594fSAndroid Build Coastguard Worker static void GenUnsafePutAbsolute(HInvoke* invoke,
1142*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type,
1143*795d594fSAndroid Build Coastguard Worker                                  bool is_volatile,
1144*795d594fSAndroid Build Coastguard Worker                                  bool is_ordered,
1145*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorARM64* codegen) {
1146*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1147*795d594fSAndroid Build Coastguard Worker 
1148*795d594fSAndroid Build Coastguard Worker   static constexpr int kAddressIndex = 1;
1149*795d594fSAndroid Build Coastguard Worker   static constexpr int kValueIndex = 2;
1150*795d594fSAndroid Build Coastguard Worker   Location address_loc = locations->InAt(kAddressIndex);
1151*795d594fSAndroid Build Coastguard Worker   MemOperand mem_op = MemOperand(WRegisterFrom(address_loc).X());
1152*795d594fSAndroid Build Coastguard Worker   CPURegister value = InputCPURegisterOrZeroRegAt(invoke, kValueIndex);
1153*795d594fSAndroid Build Coastguard Worker 
1154*795d594fSAndroid Build Coastguard Worker   if (is_volatile || is_ordered) {
1155*795d594fSAndroid Build Coastguard Worker     codegen->StoreRelease(invoke, type, value, mem_op, /* needs_null_check= */ false);
1156*795d594fSAndroid Build Coastguard Worker   } else {
1157*795d594fSAndroid Build Coastguard Worker     codegen->Store(type, value, mem_op);
1158*795d594fSAndroid Build Coastguard Worker   }
1159*795d594fSAndroid Build Coastguard Worker }
1160*795d594fSAndroid Build Coastguard Worker 
VisitUnsafePut(HInvoke * invoke)1161*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePut(HInvoke* invoke) {
1162*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePut(invoke);
1163*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutAbsolute(HInvoke * invoke)1164*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutAbsolute(HInvoke* invoke) {
1165*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutAbsolute(invoke);
1166*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutOrdered(HInvoke * invoke)1167*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutOrdered(HInvoke* invoke) {
1168*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutOrdered(invoke);
1169*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutVolatile(HInvoke * invoke)1170*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutVolatile(HInvoke* invoke) {
1171*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutVolatile(invoke);
1172*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObject(HInvoke * invoke)1173*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutObject(HInvoke* invoke) {
1174*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReference(invoke);
1175*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectOrdered(HInvoke * invoke)1176*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1177*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutObjectOrdered(invoke);
1178*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectVolatile(HInvoke * invoke)1179*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1180*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReferenceVolatile(invoke);
1181*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLong(HInvoke * invoke)1182*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutLong(HInvoke* invoke) {
1183*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLong(invoke);
1184*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongOrdered(HInvoke * invoke)1185*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1186*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongOrdered(invoke);
1187*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongVolatile(HInvoke * invoke)1188*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1189*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongVolatile(invoke);
1190*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutByte(HInvoke * invoke)1191*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafePutByte(HInvoke* invoke) {
1192*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutByte(invoke);
1193*795d594fSAndroid Build Coastguard Worker }
1194*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafePut(HInvoke * invoke)1195*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePut(HInvoke* invoke) {
1196*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1197*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt32,
1198*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1199*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1200*795d594fSAndroid Build Coastguard Worker                codegen_);
1201*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutAbsolute(HInvoke * invoke)1202*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
1203*795d594fSAndroid Build Coastguard Worker   GenUnsafePutAbsolute(invoke,
1204*795d594fSAndroid Build Coastguard Worker                        DataType::Type::kInt32,
1205*795d594fSAndroid Build Coastguard Worker                        /*is_volatile=*/ false,
1206*795d594fSAndroid Build Coastguard Worker                        /*is_ordered=*/ false,
1207*795d594fSAndroid Build Coastguard Worker                        codegen_);
1208*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutOrdered(HInvoke * invoke)1209*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
1210*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1211*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt32,
1212*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1213*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ true,
1214*795d594fSAndroid Build Coastguard Worker                codegen_);
1215*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutVolatile(HInvoke * invoke)1216*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
1217*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1218*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt32,
1219*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1220*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1221*795d594fSAndroid Build Coastguard Worker                codegen_);
1222*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutRelease(HInvoke * invoke)1223*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutRelease(HInvoke* invoke) {
1224*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1225*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt32,
1226*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1227*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1228*795d594fSAndroid Build Coastguard Worker                codegen_);
1229*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReference(HInvoke * invoke)1230*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutReference(HInvoke* invoke) {
1231*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1232*795d594fSAndroid Build Coastguard Worker                DataType::Type::kReference,
1233*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1234*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1235*795d594fSAndroid Build Coastguard Worker                codegen_);
1236*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)1237*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
1238*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1239*795d594fSAndroid Build Coastguard Worker                DataType::Type::kReference,
1240*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1241*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ true,
1242*795d594fSAndroid Build Coastguard Worker                codegen_);
1243*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)1244*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
1245*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1246*795d594fSAndroid Build Coastguard Worker                DataType::Type::kReference,
1247*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1248*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1249*795d594fSAndroid Build Coastguard Worker                codegen_);
1250*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)1251*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
1252*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1253*795d594fSAndroid Build Coastguard Worker                DataType::Type::kReference,
1254*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1255*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1256*795d594fSAndroid Build Coastguard Worker                codegen_);
1257*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLong(HInvoke * invoke)1258*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutLong(HInvoke* invoke) {
1259*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1260*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt64,
1261*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1262*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1263*795d594fSAndroid Build Coastguard Worker                codegen_);
1264*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)1265*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
1266*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1267*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt64,
1268*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1269*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ true,
1270*795d594fSAndroid Build Coastguard Worker                codegen_);
1271*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)1272*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
1273*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1274*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt64,
1275*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1276*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1277*795d594fSAndroid Build Coastguard Worker                codegen_);
1278*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongRelease(HInvoke * invoke)1279*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
1280*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1281*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt64,
1282*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ true,
1283*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1284*795d594fSAndroid Build Coastguard Worker                codegen_);
1285*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutByte(HInvoke * invoke)1286*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafePutByte(HInvoke* invoke) {
1287*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke,
1288*795d594fSAndroid Build Coastguard Worker                DataType::Type::kInt8,
1289*795d594fSAndroid Build Coastguard Worker                /*is_volatile=*/ false,
1290*795d594fSAndroid Build Coastguard Worker                /*is_ordered=*/ false,
1291*795d594fSAndroid Build Coastguard Worker                codegen_);
1292*795d594fSAndroid Build Coastguard Worker }
1293*795d594fSAndroid Build Coastguard Worker 
CreateUnsafeCASLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorARM64 * codegen)1294*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeCASLocations(ArenaAllocator* allocator,
1295*795d594fSAndroid Build Coastguard Worker                                      HInvoke* invoke,
1296*795d594fSAndroid Build Coastguard Worker                                      CodeGeneratorARM64* codegen) {
1297*795d594fSAndroid Build Coastguard Worker   const bool can_call = codegen->EmitReadBarrier() && IsUnsafeCASReference(invoke);
1298*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1299*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
1300*795d594fSAndroid Build Coastguard Worker                                       can_call
1301*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
1302*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
1303*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
1304*795d594fSAndroid Build Coastguard Worker   if (can_call && kUseBakerReadBarrier) {
1305*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
1306*795d594fSAndroid Build Coastguard Worker   }
1307*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1308*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1309*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
1310*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
1311*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(4, Location::RequiresRegister());
1312*795d594fSAndroid Build Coastguard Worker 
1313*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1314*795d594fSAndroid Build Coastguard Worker }
1315*795d594fSAndroid Build Coastguard Worker 
EmitLoadExclusive(CodeGeneratorARM64 * codegen,DataType::Type type,Register ptr,Register old_value,bool use_load_acquire)1316*795d594fSAndroid Build Coastguard Worker static void EmitLoadExclusive(CodeGeneratorARM64* codegen,
1317*795d594fSAndroid Build Coastguard Worker                               DataType::Type type,
1318*795d594fSAndroid Build Coastguard Worker                               Register ptr,
1319*795d594fSAndroid Build Coastguard Worker                               Register old_value,
1320*795d594fSAndroid Build Coastguard Worker                               bool use_load_acquire) {
1321*795d594fSAndroid Build Coastguard Worker   Arm64Assembler* assembler = codegen->GetAssembler();
1322*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = assembler->GetVIXLAssembler();
1323*795d594fSAndroid Build Coastguard Worker   switch (type) {
1324*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1325*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1326*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1327*795d594fSAndroid Build Coastguard Worker       if (use_load_acquire) {
1328*795d594fSAndroid Build Coastguard Worker         __ Ldaxrb(old_value, MemOperand(ptr));
1329*795d594fSAndroid Build Coastguard Worker       } else {
1330*795d594fSAndroid Build Coastguard Worker         __ Ldxrb(old_value, MemOperand(ptr));
1331*795d594fSAndroid Build Coastguard Worker       }
1332*795d594fSAndroid Build Coastguard Worker       break;
1333*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1334*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1335*795d594fSAndroid Build Coastguard Worker       if (use_load_acquire) {
1336*795d594fSAndroid Build Coastguard Worker         __ Ldaxrh(old_value, MemOperand(ptr));
1337*795d594fSAndroid Build Coastguard Worker       } else {
1338*795d594fSAndroid Build Coastguard Worker         __ Ldxrh(old_value, MemOperand(ptr));
1339*795d594fSAndroid Build Coastguard Worker       }
1340*795d594fSAndroid Build Coastguard Worker       break;
1341*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1342*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1343*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1344*795d594fSAndroid Build Coastguard Worker       if (use_load_acquire) {
1345*795d594fSAndroid Build Coastguard Worker         __ Ldaxr(old_value, MemOperand(ptr));
1346*795d594fSAndroid Build Coastguard Worker       } else {
1347*795d594fSAndroid Build Coastguard Worker         __ Ldxr(old_value, MemOperand(ptr));
1348*795d594fSAndroid Build Coastguard Worker       }
1349*795d594fSAndroid Build Coastguard Worker       break;
1350*795d594fSAndroid Build Coastguard Worker     default:
1351*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type: " << type;
1352*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1353*795d594fSAndroid Build Coastguard Worker   }
1354*795d594fSAndroid Build Coastguard Worker   switch (type) {
1355*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1356*795d594fSAndroid Build Coastguard Worker       __ Sxtb(old_value, old_value);
1357*795d594fSAndroid Build Coastguard Worker       break;
1358*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1359*795d594fSAndroid Build Coastguard Worker       __ Sxth(old_value, old_value);
1360*795d594fSAndroid Build Coastguard Worker       break;
1361*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1362*795d594fSAndroid Build Coastguard Worker       assembler->MaybeUnpoisonHeapReference(old_value);
1363*795d594fSAndroid Build Coastguard Worker       break;
1364*795d594fSAndroid Build Coastguard Worker     default:
1365*795d594fSAndroid Build Coastguard Worker       break;
1366*795d594fSAndroid Build Coastguard Worker   }
1367*795d594fSAndroid Build Coastguard Worker }
1368*795d594fSAndroid Build Coastguard Worker 
EmitStoreExclusive(CodeGeneratorARM64 * codegen,DataType::Type type,Register ptr,Register store_result,Register new_value,bool use_store_release)1369*795d594fSAndroid Build Coastguard Worker static void EmitStoreExclusive(CodeGeneratorARM64* codegen,
1370*795d594fSAndroid Build Coastguard Worker                                DataType::Type type,
1371*795d594fSAndroid Build Coastguard Worker                                Register ptr,
1372*795d594fSAndroid Build Coastguard Worker                                Register store_result,
1373*795d594fSAndroid Build Coastguard Worker                                Register new_value,
1374*795d594fSAndroid Build Coastguard Worker                                bool use_store_release) {
1375*795d594fSAndroid Build Coastguard Worker   Arm64Assembler* assembler = codegen->GetAssembler();
1376*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = assembler->GetVIXLAssembler();
1377*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1378*795d594fSAndroid Build Coastguard Worker     assembler->MaybePoisonHeapReference(new_value);
1379*795d594fSAndroid Build Coastguard Worker   }
1380*795d594fSAndroid Build Coastguard Worker   switch (type) {
1381*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1382*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1383*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1384*795d594fSAndroid Build Coastguard Worker       if (use_store_release) {
1385*795d594fSAndroid Build Coastguard Worker         __ Stlxrb(store_result, new_value, MemOperand(ptr));
1386*795d594fSAndroid Build Coastguard Worker       } else {
1387*795d594fSAndroid Build Coastguard Worker         __ Stxrb(store_result, new_value, MemOperand(ptr));
1388*795d594fSAndroid Build Coastguard Worker       }
1389*795d594fSAndroid Build Coastguard Worker       break;
1390*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1391*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1392*795d594fSAndroid Build Coastguard Worker       if (use_store_release) {
1393*795d594fSAndroid Build Coastguard Worker         __ Stlxrh(store_result, new_value, MemOperand(ptr));
1394*795d594fSAndroid Build Coastguard Worker       } else {
1395*795d594fSAndroid Build Coastguard Worker         __ Stxrh(store_result, new_value, MemOperand(ptr));
1396*795d594fSAndroid Build Coastguard Worker       }
1397*795d594fSAndroid Build Coastguard Worker       break;
1398*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1399*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1400*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1401*795d594fSAndroid Build Coastguard Worker       if (use_store_release) {
1402*795d594fSAndroid Build Coastguard Worker         __ Stlxr(store_result, new_value, MemOperand(ptr));
1403*795d594fSAndroid Build Coastguard Worker       } else {
1404*795d594fSAndroid Build Coastguard Worker         __ Stxr(store_result, new_value, MemOperand(ptr));
1405*795d594fSAndroid Build Coastguard Worker       }
1406*795d594fSAndroid Build Coastguard Worker       break;
1407*795d594fSAndroid Build Coastguard Worker     default:
1408*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type: " << type;
1409*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1410*795d594fSAndroid Build Coastguard Worker   }
1411*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1412*795d594fSAndroid Build Coastguard Worker     assembler->MaybeUnpoisonHeapReference(new_value);
1413*795d594fSAndroid Build Coastguard Worker   }
1414*795d594fSAndroid Build Coastguard Worker }
1415*795d594fSAndroid Build Coastguard Worker 
GenerateCompareAndSet(CodeGeneratorARM64 * codegen,DataType::Type type,std::memory_order order,bool strong,vixl::aarch64::Label * cmp_failure,Register ptr,Register new_value,Register old_value,Register store_result,Register expected,Register expected2=Register ())1416*795d594fSAndroid Build Coastguard Worker static void GenerateCompareAndSet(CodeGeneratorARM64* codegen,
1417*795d594fSAndroid Build Coastguard Worker                                   DataType::Type type,
1418*795d594fSAndroid Build Coastguard Worker                                   std::memory_order order,
1419*795d594fSAndroid Build Coastguard Worker                                   bool strong,
1420*795d594fSAndroid Build Coastguard Worker                                   vixl::aarch64::Label* cmp_failure,
1421*795d594fSAndroid Build Coastguard Worker                                   Register ptr,
1422*795d594fSAndroid Build Coastguard Worker                                   Register new_value,
1423*795d594fSAndroid Build Coastguard Worker                                   Register old_value,
1424*795d594fSAndroid Build Coastguard Worker                                   Register store_result,
1425*795d594fSAndroid Build Coastguard Worker                                   Register expected,
1426*795d594fSAndroid Build Coastguard Worker                                   Register expected2 = Register()) {
1427*795d594fSAndroid Build Coastguard Worker   // The `expected2` is valid only for reference slow path and represents the unmarked old value
1428*795d594fSAndroid Build Coastguard Worker   // from the main path attempt to emit CAS when the marked old value matched `expected`.
1429*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(expected2.IsValid(), type == DataType::Type::kReference);
1430*795d594fSAndroid Build Coastguard Worker 
1431*795d594fSAndroid Build Coastguard Worker   DCHECK(ptr.IsX());
1432*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(new_value.IsX(), type == DataType::Type::kInt64);
1433*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(old_value.IsX(), type == DataType::Type::kInt64);
1434*795d594fSAndroid Build Coastguard Worker   DCHECK(store_result.IsW());
1435*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(expected.IsX(), type == DataType::Type::kInt64);
1436*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(expected2.IsValid(), expected2.IsW());
1437*795d594fSAndroid Build Coastguard Worker 
1438*795d594fSAndroid Build Coastguard Worker   Arm64Assembler* assembler = codegen->GetAssembler();
1439*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = assembler->GetVIXLAssembler();
1440*795d594fSAndroid Build Coastguard Worker 
1441*795d594fSAndroid Build Coastguard Worker   bool use_load_acquire =
1442*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_acquire) || (order == std::memory_order_seq_cst);
1443*795d594fSAndroid Build Coastguard Worker   bool use_store_release =
1444*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_release) || (order == std::memory_order_seq_cst);
1445*795d594fSAndroid Build Coastguard Worker   DCHECK(use_load_acquire || use_store_release || order == std::memory_order_relaxed);
1446*795d594fSAndroid Build Coastguard Worker 
1447*795d594fSAndroid Build Coastguard Worker   // repeat: {
1448*795d594fSAndroid Build Coastguard Worker   //   old_value = [ptr];  // Load exclusive.
1449*795d594fSAndroid Build Coastguard Worker   //   if (old_value != expected && old_value != expected2) goto cmp_failure;
1450*795d594fSAndroid Build Coastguard Worker   //   store_result = failed([ptr] <- new_value);  // Store exclusive.
1451*795d594fSAndroid Build Coastguard Worker   // }
1452*795d594fSAndroid Build Coastguard Worker   // if (strong) {
1453*795d594fSAndroid Build Coastguard Worker   //   if (store_result) goto repeat;  // Repeat until compare fails or store exclusive succeeds.
1454*795d594fSAndroid Build Coastguard Worker   // } else {
1455*795d594fSAndroid Build Coastguard Worker   //   store_result = store_result ^ 1;  // Report success as 1, failure as 0.
1456*795d594fSAndroid Build Coastguard Worker   // }
1457*795d594fSAndroid Build Coastguard Worker   //
1458*795d594fSAndroid Build Coastguard Worker   // Flag Z indicates whether `old_value == expected || old_value == expected2`.
1459*795d594fSAndroid Build Coastguard Worker   // (If `expected2` is not valid, the `old_value == expected2` part is not emitted.)
1460*795d594fSAndroid Build Coastguard Worker 
1461*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop_head;
1462*795d594fSAndroid Build Coastguard Worker   if (strong) {
1463*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop_head);
1464*795d594fSAndroid Build Coastguard Worker   }
1465*795d594fSAndroid Build Coastguard Worker   EmitLoadExclusive(codegen, type, ptr, old_value, use_load_acquire);
1466*795d594fSAndroid Build Coastguard Worker   __ Cmp(old_value, expected);
1467*795d594fSAndroid Build Coastguard Worker   if (expected2.IsValid()) {
1468*795d594fSAndroid Build Coastguard Worker     __ Ccmp(old_value, expected2, ZFlag, ne);
1469*795d594fSAndroid Build Coastguard Worker   }
1470*795d594fSAndroid Build Coastguard Worker   // If the comparison failed, the Z flag is cleared as we branch to the `cmp_failure` label.
1471*795d594fSAndroid Build Coastguard Worker   // If the comparison succeeded, the Z flag is set and remains set after the end of the
1472*795d594fSAndroid Build Coastguard Worker   // code emitted here, unless we retry the whole operation.
1473*795d594fSAndroid Build Coastguard Worker   __ B(cmp_failure, ne);
1474*795d594fSAndroid Build Coastguard Worker   EmitStoreExclusive(codegen, type, ptr, store_result, new_value, use_store_release);
1475*795d594fSAndroid Build Coastguard Worker   if (strong) {
1476*795d594fSAndroid Build Coastguard Worker     __ Cbnz(store_result, &loop_head);
1477*795d594fSAndroid Build Coastguard Worker   } else {
1478*795d594fSAndroid Build Coastguard Worker     // Flip the `store_result` register to indicate success by 1 and failure by 0.
1479*795d594fSAndroid Build Coastguard Worker     __ Eor(store_result, store_result, 1);
1480*795d594fSAndroid Build Coastguard Worker   }
1481*795d594fSAndroid Build Coastguard Worker }
1482*795d594fSAndroid Build Coastguard Worker 
1483*795d594fSAndroid Build Coastguard Worker class ReadBarrierCasSlowPathARM64 : public SlowPathCodeARM64 {
1484*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierCasSlowPathARM64(HInvoke * invoke,std::memory_order order,bool strong,Register base,Register offset,Register expected,Register new_value,Register old_value,Register old_value_temp,Register store_result,bool update_old_value,CodeGeneratorARM64 * arm64_codegen)1485*795d594fSAndroid Build Coastguard Worker   ReadBarrierCasSlowPathARM64(HInvoke* invoke,
1486*795d594fSAndroid Build Coastguard Worker                               std::memory_order order,
1487*795d594fSAndroid Build Coastguard Worker                               bool strong,
1488*795d594fSAndroid Build Coastguard Worker                               Register base,
1489*795d594fSAndroid Build Coastguard Worker                               Register offset,
1490*795d594fSAndroid Build Coastguard Worker                               Register expected,
1491*795d594fSAndroid Build Coastguard Worker                               Register new_value,
1492*795d594fSAndroid Build Coastguard Worker                               Register old_value,
1493*795d594fSAndroid Build Coastguard Worker                               Register old_value_temp,
1494*795d594fSAndroid Build Coastguard Worker                               Register store_result,
1495*795d594fSAndroid Build Coastguard Worker                               bool update_old_value,
1496*795d594fSAndroid Build Coastguard Worker                               CodeGeneratorARM64* arm64_codegen)
1497*795d594fSAndroid Build Coastguard Worker       : SlowPathCodeARM64(invoke),
1498*795d594fSAndroid Build Coastguard Worker         order_(order),
1499*795d594fSAndroid Build Coastguard Worker         strong_(strong),
1500*795d594fSAndroid Build Coastguard Worker         base_(base),
1501*795d594fSAndroid Build Coastguard Worker         offset_(offset),
1502*795d594fSAndroid Build Coastguard Worker         expected_(expected),
1503*795d594fSAndroid Build Coastguard Worker         new_value_(new_value),
1504*795d594fSAndroid Build Coastguard Worker         old_value_(old_value),
1505*795d594fSAndroid Build Coastguard Worker         old_value_temp_(old_value_temp),
1506*795d594fSAndroid Build Coastguard Worker         store_result_(store_result),
1507*795d594fSAndroid Build Coastguard Worker         update_old_value_(update_old_value),
1508*795d594fSAndroid Build Coastguard Worker         mark_old_value_slow_path_(nullptr),
1509*795d594fSAndroid Build Coastguard Worker         update_old_value_slow_path_(nullptr) {
1510*795d594fSAndroid Build Coastguard Worker     if (!kUseBakerReadBarrier) {
1511*795d594fSAndroid Build Coastguard Worker       // We need to add the slow path now, it is too late when emitting slow path code.
1512*795d594fSAndroid Build Coastguard Worker       mark_old_value_slow_path_ = arm64_codegen->AddReadBarrierSlowPath(
1513*795d594fSAndroid Build Coastguard Worker           invoke,
1514*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(old_value_temp.GetCode()),
1515*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(old_value.GetCode()),
1516*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(base.GetCode()),
1517*795d594fSAndroid Build Coastguard Worker           /*offset=*/ 0u,
1518*795d594fSAndroid Build Coastguard Worker           /*index=*/ Location::RegisterLocation(offset.GetCode()));
1519*795d594fSAndroid Build Coastguard Worker       if (update_old_value_) {
1520*795d594fSAndroid Build Coastguard Worker         update_old_value_slow_path_ = arm64_codegen->AddReadBarrierSlowPath(
1521*795d594fSAndroid Build Coastguard Worker             invoke,
1522*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(old_value.GetCode()),
1523*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(old_value_temp.GetCode()),
1524*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(base.GetCode()),
1525*795d594fSAndroid Build Coastguard Worker             /*offset=*/ 0u,
1526*795d594fSAndroid Build Coastguard Worker             /*index=*/ Location::RegisterLocation(offset.GetCode()));
1527*795d594fSAndroid Build Coastguard Worker       }
1528*795d594fSAndroid Build Coastguard Worker     }
1529*795d594fSAndroid Build Coastguard Worker   }
1530*795d594fSAndroid Build Coastguard Worker 
GetDescription() const1531*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierCasSlowPathARM64"; }
1532*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)1533*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
1534*795d594fSAndroid Build Coastguard Worker     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
1535*795d594fSAndroid Build Coastguard Worker     Arm64Assembler* assembler = arm64_codegen->GetAssembler();
1536*795d594fSAndroid Build Coastguard Worker     MacroAssembler* masm = assembler->GetVIXLAssembler();
1537*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
1538*795d594fSAndroid Build Coastguard Worker 
1539*795d594fSAndroid Build Coastguard Worker     // Mark the `old_value_` from the main path and compare with `expected_`.
1540*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
1541*795d594fSAndroid Build Coastguard Worker       DCHECK(mark_old_value_slow_path_ == nullptr);
1542*795d594fSAndroid Build Coastguard Worker       arm64_codegen->GenerateIntrinsicMoveWithBakerReadBarrier(old_value_temp_, old_value_);
1543*795d594fSAndroid Build Coastguard Worker     } else {
1544*795d594fSAndroid Build Coastguard Worker       DCHECK(mark_old_value_slow_path_ != nullptr);
1545*795d594fSAndroid Build Coastguard Worker       __ B(mark_old_value_slow_path_->GetEntryLabel());
1546*795d594fSAndroid Build Coastguard Worker       __ Bind(mark_old_value_slow_path_->GetExitLabel());
1547*795d594fSAndroid Build Coastguard Worker     }
1548*795d594fSAndroid Build Coastguard Worker     __ Cmp(old_value_temp_, expected_);
1549*795d594fSAndroid Build Coastguard Worker     if (update_old_value_) {
1550*795d594fSAndroid Build Coastguard Worker       // Update the old value if we're going to return from the slow path.
1551*795d594fSAndroid Build Coastguard Worker       __ Csel(old_value_, old_value_temp_, old_value_, ne);
1552*795d594fSAndroid Build Coastguard Worker     }
1553*795d594fSAndroid Build Coastguard Worker     __ B(GetExitLabel(), ne);  // If taken, Z=false indicates failure.
1554*795d594fSAndroid Build Coastguard Worker 
1555*795d594fSAndroid Build Coastguard Worker     // The `old_value` we have read did not match `expected` (which is always a to-space
1556*795d594fSAndroid Build Coastguard Worker     // reference) but after the read barrier the marked to-space value matched, so the
1557*795d594fSAndroid Build Coastguard Worker     // `old_value` must be a from-space reference to the same object. Do the same CAS loop
1558*795d594fSAndroid Build Coastguard Worker     // as the main path but check for both `expected` and the unmarked old value
1559*795d594fSAndroid Build Coastguard Worker     // representing the to-space and from-space references for the same object.
1560*795d594fSAndroid Build Coastguard Worker 
1561*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
1562*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(store_result_.IsValid(), !temps.IsAvailable(store_result_));
1563*795d594fSAndroid Build Coastguard Worker     Register tmp_ptr = temps.AcquireX();
1564*795d594fSAndroid Build Coastguard Worker     Register store_result = store_result_.IsValid() ? store_result_ : temps.AcquireW();
1565*795d594fSAndroid Build Coastguard Worker 
1566*795d594fSAndroid Build Coastguard Worker     // Recalculate the `tmp_ptr` from main path clobbered by the read barrier above.
1567*795d594fSAndroid Build Coastguard Worker     __ Add(tmp_ptr, base_.X(), Operand(offset_));
1568*795d594fSAndroid Build Coastguard Worker 
1569*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label mark_old_value;
1570*795d594fSAndroid Build Coastguard Worker     GenerateCompareAndSet(arm64_codegen,
1571*795d594fSAndroid Build Coastguard Worker                           DataType::Type::kReference,
1572*795d594fSAndroid Build Coastguard Worker                           order_,
1573*795d594fSAndroid Build Coastguard Worker                           strong_,
1574*795d594fSAndroid Build Coastguard Worker                           /*cmp_failure=*/ update_old_value_ ? &mark_old_value : GetExitLabel(),
1575*795d594fSAndroid Build Coastguard Worker                           tmp_ptr,
1576*795d594fSAndroid Build Coastguard Worker                           new_value_,
1577*795d594fSAndroid Build Coastguard Worker                           /*old_value=*/ old_value_temp_,
1578*795d594fSAndroid Build Coastguard Worker                           store_result,
1579*795d594fSAndroid Build Coastguard Worker                           expected_,
1580*795d594fSAndroid Build Coastguard Worker                           /*expected2=*/ old_value_);
1581*795d594fSAndroid Build Coastguard Worker     if (update_old_value_) {
1582*795d594fSAndroid Build Coastguard Worker       // To reach this point, the `old_value_temp_` must be either a from-space or a to-space
1583*795d594fSAndroid Build Coastguard Worker       // reference of the `expected_` object. Update the `old_value_` to the to-space reference.
1584*795d594fSAndroid Build Coastguard Worker       __ Mov(old_value_, expected_);
1585*795d594fSAndroid Build Coastguard Worker     }
1586*795d594fSAndroid Build Coastguard Worker 
1587*795d594fSAndroid Build Coastguard Worker     // Z=true from the CMP+CCMP in GenerateCompareAndSet() above indicates comparison success.
1588*795d594fSAndroid Build Coastguard Worker     // For strong CAS, that's the overall success. For weak CAS, the code also needs
1589*795d594fSAndroid Build Coastguard Worker     // to check the `store_result` after returning from the slow path.
1590*795d594fSAndroid Build Coastguard Worker     __ B(GetExitLabel());
1591*795d594fSAndroid Build Coastguard Worker 
1592*795d594fSAndroid Build Coastguard Worker     if (update_old_value_) {
1593*795d594fSAndroid Build Coastguard Worker       __ Bind(&mark_old_value);
1594*795d594fSAndroid Build Coastguard Worker       if (kUseBakerReadBarrier) {
1595*795d594fSAndroid Build Coastguard Worker         DCHECK(update_old_value_slow_path_ == nullptr);
1596*795d594fSAndroid Build Coastguard Worker         arm64_codegen->GenerateIntrinsicMoveWithBakerReadBarrier(old_value_, old_value_temp_);
1597*795d594fSAndroid Build Coastguard Worker       } else {
1598*795d594fSAndroid Build Coastguard Worker         // Note: We could redirect the `failure` above directly to the entry label and bind
1599*795d594fSAndroid Build Coastguard Worker         // the exit label in the main path, but the main path would need to access the
1600*795d594fSAndroid Build Coastguard Worker         // `update_old_value_slow_path_`. To keep the code simple, keep the extra jumps.
1601*795d594fSAndroid Build Coastguard Worker         DCHECK(update_old_value_slow_path_ != nullptr);
1602*795d594fSAndroid Build Coastguard Worker         __ B(update_old_value_slow_path_->GetEntryLabel());
1603*795d594fSAndroid Build Coastguard Worker         __ Bind(update_old_value_slow_path_->GetExitLabel());
1604*795d594fSAndroid Build Coastguard Worker       }
1605*795d594fSAndroid Build Coastguard Worker       __ B(GetExitLabel());
1606*795d594fSAndroid Build Coastguard Worker     }
1607*795d594fSAndroid Build Coastguard Worker   }
1608*795d594fSAndroid Build Coastguard Worker 
1609*795d594fSAndroid Build Coastguard Worker  private:
1610*795d594fSAndroid Build Coastguard Worker   std::memory_order order_;
1611*795d594fSAndroid Build Coastguard Worker   bool strong_;
1612*795d594fSAndroid Build Coastguard Worker   Register base_;
1613*795d594fSAndroid Build Coastguard Worker   Register offset_;
1614*795d594fSAndroid Build Coastguard Worker   Register expected_;
1615*795d594fSAndroid Build Coastguard Worker   Register new_value_;
1616*795d594fSAndroid Build Coastguard Worker   Register old_value_;
1617*795d594fSAndroid Build Coastguard Worker   Register old_value_temp_;
1618*795d594fSAndroid Build Coastguard Worker   Register store_result_;
1619*795d594fSAndroid Build Coastguard Worker   bool update_old_value_;
1620*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* mark_old_value_slow_path_;
1621*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* update_old_value_slow_path_;
1622*795d594fSAndroid Build Coastguard Worker };
1623*795d594fSAndroid Build Coastguard Worker 
GenUnsafeCas(HInvoke * invoke,DataType::Type type,CodeGeneratorARM64 * codegen)1624*795d594fSAndroid Build Coastguard Worker static void GenUnsafeCas(HInvoke* invoke, DataType::Type type, CodeGeneratorARM64* codegen) {
1625*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
1626*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1627*795d594fSAndroid Build Coastguard Worker 
1628*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());                 // Boolean result.
1629*795d594fSAndroid Build Coastguard Worker   Register base = WRegisterFrom(locations->InAt(1));              // Object pointer.
1630*795d594fSAndroid Build Coastguard Worker   Register offset = XRegisterFrom(locations->InAt(2));            // Long offset.
1631*795d594fSAndroid Build Coastguard Worker   Register expected = RegisterFrom(locations->InAt(3), type);     // Expected.
1632*795d594fSAndroid Build Coastguard Worker   Register new_value = RegisterFrom(locations->InAt(4), type);    // New value.
1633*795d594fSAndroid Build Coastguard Worker 
1634*795d594fSAndroid Build Coastguard Worker   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
1635*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1636*795d594fSAndroid Build Coastguard Worker     // Mark card for object assuming new value is stored.
1637*795d594fSAndroid Build Coastguard Worker     bool new_value_can_be_null = true;  // TODO: Worth finding out this information?
1638*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(base, new_value, new_value_can_be_null);
1639*795d594fSAndroid Build Coastguard Worker   }
1640*795d594fSAndroid Build Coastguard Worker 
1641*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
1642*795d594fSAndroid Build Coastguard Worker   Register tmp_ptr = temps.AcquireX();                             // Pointer to actual memory.
1643*795d594fSAndroid Build Coastguard Worker   Register old_value;                                              // Value in memory.
1644*795d594fSAndroid Build Coastguard Worker 
1645*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label exit_loop_label;
1646*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* exit_loop = &exit_loop_label;
1647*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* cmp_failure = &exit_loop_label;
1648*795d594fSAndroid Build Coastguard Worker 
1649*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
1650*795d594fSAndroid Build Coastguard Worker     // We need to store the `old_value` in a non-scratch register to make sure
1651*795d594fSAndroid Build Coastguard Worker     // the read barrier in the slow path does not clobber it.
1652*795d594fSAndroid Build Coastguard Worker     old_value = WRegisterFrom(locations->GetTemp(0));  // The old value from main path.
1653*795d594fSAndroid Build Coastguard Worker     // The `old_value_temp` is used first for the marked `old_value` and then for the unmarked
1654*795d594fSAndroid Build Coastguard Worker     // reloaded old value for subsequent CAS in the slow path. It cannot be a scratch register.
1655*795d594fSAndroid Build Coastguard Worker     Register old_value_temp = WRegisterFrom(locations->GetTemp(1));
1656*795d594fSAndroid Build Coastguard Worker     ReadBarrierCasSlowPathARM64* slow_path =
1657*795d594fSAndroid Build Coastguard Worker         new (codegen->GetScopedAllocator()) ReadBarrierCasSlowPathARM64(
1658*795d594fSAndroid Build Coastguard Worker             invoke,
1659*795d594fSAndroid Build Coastguard Worker             std::memory_order_seq_cst,
1660*795d594fSAndroid Build Coastguard Worker             /*strong=*/ true,
1661*795d594fSAndroid Build Coastguard Worker             base,
1662*795d594fSAndroid Build Coastguard Worker             offset,
1663*795d594fSAndroid Build Coastguard Worker             expected,
1664*795d594fSAndroid Build Coastguard Worker             new_value,
1665*795d594fSAndroid Build Coastguard Worker             old_value,
1666*795d594fSAndroid Build Coastguard Worker             old_value_temp,
1667*795d594fSAndroid Build Coastguard Worker             /*store_result=*/ Register(),  // Use a scratch register.
1668*795d594fSAndroid Build Coastguard Worker             /*update_old_value=*/ false,
1669*795d594fSAndroid Build Coastguard Worker             codegen);
1670*795d594fSAndroid Build Coastguard Worker     codegen->AddSlowPath(slow_path);
1671*795d594fSAndroid Build Coastguard Worker     exit_loop = slow_path->GetExitLabel();
1672*795d594fSAndroid Build Coastguard Worker     cmp_failure = slow_path->GetEntryLabel();
1673*795d594fSAndroid Build Coastguard Worker   } else {
1674*795d594fSAndroid Build Coastguard Worker     old_value = temps.AcquireSameSizeAs(new_value);
1675*795d594fSAndroid Build Coastguard Worker   }
1676*795d594fSAndroid Build Coastguard Worker 
1677*795d594fSAndroid Build Coastguard Worker   __ Add(tmp_ptr, base.X(), Operand(offset));
1678*795d594fSAndroid Build Coastguard Worker 
1679*795d594fSAndroid Build Coastguard Worker   GenerateCompareAndSet(codegen,
1680*795d594fSAndroid Build Coastguard Worker                         type,
1681*795d594fSAndroid Build Coastguard Worker                         std::memory_order_seq_cst,
1682*795d594fSAndroid Build Coastguard Worker                         /*strong=*/ true,
1683*795d594fSAndroid Build Coastguard Worker                         cmp_failure,
1684*795d594fSAndroid Build Coastguard Worker                         tmp_ptr,
1685*795d594fSAndroid Build Coastguard Worker                         new_value,
1686*795d594fSAndroid Build Coastguard Worker                         old_value,
1687*795d594fSAndroid Build Coastguard Worker                         /*store_result=*/ old_value.W(),  // Reuse `old_value` for ST*XR* result.
1688*795d594fSAndroid Build Coastguard Worker                         expected);
1689*795d594fSAndroid Build Coastguard Worker   __ Bind(exit_loop);
1690*795d594fSAndroid Build Coastguard Worker   __ Cset(out, eq);
1691*795d594fSAndroid Build Coastguard Worker }
1692*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASInt(HInvoke * invoke)1693*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeCASInt(HInvoke* invoke) {
1694*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASInt(invoke);
1695*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeCASLong(HInvoke * invoke)1696*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeCASLong(HInvoke* invoke) {
1697*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASLong(invoke);
1698*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeCASObject(HInvoke * invoke)1699*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject(HInvoke* invoke) {
1700*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASObject(invoke);
1701*795d594fSAndroid Build Coastguard Worker }
1702*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASInt(HInvoke * invoke)1703*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCASInt(HInvoke* invoke) {
1704*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
1705*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetInt(invoke);
1706*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCASLong(HInvoke * invoke)1707*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCASLong(HInvoke* invoke) {
1708*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
1709*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetLong(invoke);
1710*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCASObject(HInvoke * invoke)1711*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCASObject(HInvoke* invoke) {
1712*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
1713*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetReference(invoke);
1714*795d594fSAndroid Build Coastguard Worker }
1715*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)1716*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
1717*795d594fSAndroid Build Coastguard Worker   CreateUnsafeCASLocations(allocator_, invoke, codegen_);
1718*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)1719*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
1720*795d594fSAndroid Build Coastguard Worker   CreateUnsafeCASLocations(allocator_, invoke, codegen_);
1721*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)1722*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
1723*795d594fSAndroid Build Coastguard Worker   // The only supported read barrier implementation is the Baker-style read barriers.
1724*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitNonBakerReadBarrier()) {
1725*795d594fSAndroid Build Coastguard Worker     return;
1726*795d594fSAndroid Build Coastguard Worker   }
1727*795d594fSAndroid Build Coastguard Worker 
1728*795d594fSAndroid Build Coastguard Worker   CreateUnsafeCASLocations(allocator_, invoke, codegen_);
1729*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitReadBarrier()) {
1730*795d594fSAndroid Build Coastguard Worker     // We need two non-scratch temporary registers for read barrier.
1731*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = invoke->GetLocations();
1732*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
1733*795d594fSAndroid Build Coastguard Worker       locations->AddRegisterTemps(2);
1734*795d594fSAndroid Build Coastguard Worker     } else {
1735*795d594fSAndroid Build Coastguard Worker       // To preserve the old value across the non-Baker read barrier
1736*795d594fSAndroid Build Coastguard Worker       // slow path, use a fixed callee-save register.
1737*795d594fSAndroid Build Coastguard Worker       constexpr int first_callee_save = CTZ(kArm64CalleeSaveRefSpills);
1738*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(first_callee_save));
1739*795d594fSAndroid Build Coastguard Worker       // To reduce the number of moves, request x0 as the second temporary.
1740*795d594fSAndroid Build Coastguard Worker       DCHECK(InvokeRuntimeCallingConvention().GetReturnLocation(DataType::Type::kReference).Equals(
1741*795d594fSAndroid Build Coastguard Worker                  Location::RegisterLocation(x0.GetCode())));
1742*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(x0.GetCode()));
1743*795d594fSAndroid Build Coastguard Worker     }
1744*795d594fSAndroid Build Coastguard Worker   }
1745*795d594fSAndroid Build Coastguard Worker }
1746*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASInt(HInvoke * invoke)1747*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeCASInt(HInvoke* invoke) {
1748*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASInt(invoke);
1749*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeCASLong(HInvoke * invoke)1750*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeCASLong(HInvoke* invoke) {
1751*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASLong(invoke);
1752*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeCASObject(HInvoke * invoke)1753*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeCASObject(HInvoke* invoke) {
1754*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASObject(invoke);
1755*795d594fSAndroid Build Coastguard Worker }
1756*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASInt(HInvoke * invoke)1757*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCASInt(HInvoke* invoke) {
1758*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
1759*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetInt(invoke);
1760*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCASLong(HInvoke * invoke)1761*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCASLong(HInvoke* invoke) {
1762*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
1763*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetLong(invoke);
1764*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCASObject(HInvoke * invoke)1765*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCASObject(HInvoke* invoke) {
1766*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
1767*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetReference(invoke);
1768*795d594fSAndroid Build Coastguard Worker }
1769*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)1770*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
1771*795d594fSAndroid Build Coastguard Worker   GenUnsafeCas(invoke, DataType::Type::kInt32, codegen_);
1772*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)1773*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
1774*795d594fSAndroid Build Coastguard Worker   GenUnsafeCas(invoke, DataType::Type::kInt64, codegen_);
1775*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)1776*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
1777*795d594fSAndroid Build Coastguard Worker   // The only supported read barrier implementation is the Baker-style read barriers.
1778*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
1779*795d594fSAndroid Build Coastguard Worker 
1780*795d594fSAndroid Build Coastguard Worker   GenUnsafeCas(invoke, DataType::Type::kReference, codegen_);
1781*795d594fSAndroid Build Coastguard Worker }
1782*795d594fSAndroid Build Coastguard Worker 
1783*795d594fSAndroid Build Coastguard Worker enum class GetAndUpdateOp {
1784*795d594fSAndroid Build Coastguard Worker   kSet,
1785*795d594fSAndroid Build Coastguard Worker   kAdd,
1786*795d594fSAndroid Build Coastguard Worker   kAddWithByteSwap,
1787*795d594fSAndroid Build Coastguard Worker   kAnd,
1788*795d594fSAndroid Build Coastguard Worker   kOr,
1789*795d594fSAndroid Build Coastguard Worker   kXor
1790*795d594fSAndroid Build Coastguard Worker };
1791*795d594fSAndroid Build Coastguard Worker 
GenerateGetAndUpdate(CodeGeneratorARM64 * codegen,GetAndUpdateOp get_and_update_op,DataType::Type load_store_type,std::memory_order order,Register ptr,CPURegister arg,CPURegister old_value)1792*795d594fSAndroid Build Coastguard Worker static void GenerateGetAndUpdate(CodeGeneratorARM64* codegen,
1793*795d594fSAndroid Build Coastguard Worker                                  GetAndUpdateOp get_and_update_op,
1794*795d594fSAndroid Build Coastguard Worker                                  DataType::Type load_store_type,
1795*795d594fSAndroid Build Coastguard Worker                                  std::memory_order order,
1796*795d594fSAndroid Build Coastguard Worker                                  Register ptr,
1797*795d594fSAndroid Build Coastguard Worker                                  CPURegister arg,
1798*795d594fSAndroid Build Coastguard Worker                                  CPURegister old_value) {
1799*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
1800*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
1801*795d594fSAndroid Build Coastguard Worker   Register store_result = temps.AcquireW();
1802*795d594fSAndroid Build Coastguard Worker 
1803*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(old_value.GetSizeInBits(), arg.GetSizeInBits());
1804*795d594fSAndroid Build Coastguard Worker   Register old_value_reg;
1805*795d594fSAndroid Build Coastguard Worker   Register new_value;
1806*795d594fSAndroid Build Coastguard Worker   switch (get_and_update_op) {
1807*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kSet:
1808*795d594fSAndroid Build Coastguard Worker       old_value_reg = old_value.IsX() ? old_value.X() : old_value.W();
1809*795d594fSAndroid Build Coastguard Worker       new_value = arg.IsX() ? arg.X() : arg.W();
1810*795d594fSAndroid Build Coastguard Worker       break;
1811*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAddWithByteSwap:
1812*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAdd:
1813*795d594fSAndroid Build Coastguard Worker       if (arg.IsVRegister()) {
1814*795d594fSAndroid Build Coastguard Worker         old_value_reg = arg.IsD() ? temps.AcquireX() : temps.AcquireW();
1815*795d594fSAndroid Build Coastguard Worker         new_value = old_value_reg;  // Use the same temporary.
1816*795d594fSAndroid Build Coastguard Worker         break;
1817*795d594fSAndroid Build Coastguard Worker       }
1818*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
1819*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAnd:
1820*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kOr:
1821*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kXor:
1822*795d594fSAndroid Build Coastguard Worker       old_value_reg = old_value.IsX() ? old_value.X() : old_value.W();
1823*795d594fSAndroid Build Coastguard Worker       new_value = old_value.IsX() ? temps.AcquireX() : temps.AcquireW();
1824*795d594fSAndroid Build Coastguard Worker       break;
1825*795d594fSAndroid Build Coastguard Worker   }
1826*795d594fSAndroid Build Coastguard Worker 
1827*795d594fSAndroid Build Coastguard Worker   bool use_load_acquire =
1828*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_acquire) || (order == std::memory_order_seq_cst);
1829*795d594fSAndroid Build Coastguard Worker   bool use_store_release =
1830*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_release) || (order == std::memory_order_seq_cst);
1831*795d594fSAndroid Build Coastguard Worker   DCHECK(use_load_acquire || use_store_release);
1832*795d594fSAndroid Build Coastguard Worker 
1833*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop_label;
1834*795d594fSAndroid Build Coastguard Worker   __ Bind(&loop_label);
1835*795d594fSAndroid Build Coastguard Worker   EmitLoadExclusive(codegen, load_store_type, ptr, old_value_reg, use_load_acquire);
1836*795d594fSAndroid Build Coastguard Worker   switch (get_and_update_op) {
1837*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kSet:
1838*795d594fSAndroid Build Coastguard Worker       break;
1839*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAddWithByteSwap:
1840*795d594fSAndroid Build Coastguard Worker       // To avoid unnecessary sign extension before REV16, the caller must specify `kUint16`
1841*795d594fSAndroid Build Coastguard Worker       // instead of `kInt16` and do the sign-extension explicitly afterwards.
1842*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(load_store_type, DataType::Type::kInt16);
1843*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, load_store_type, old_value_reg, old_value_reg);
1844*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
1845*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAdd:
1846*795d594fSAndroid Build Coastguard Worker       if (arg.IsVRegister()) {
1847*795d594fSAndroid Build Coastguard Worker         VRegister old_value_vreg = old_value.IsD() ? old_value.D() : old_value.S();
1848*795d594fSAndroid Build Coastguard Worker         VRegister sum = temps.AcquireSameSizeAs(old_value_vreg);
1849*795d594fSAndroid Build Coastguard Worker         __ Fmov(old_value_vreg, old_value_reg);
1850*795d594fSAndroid Build Coastguard Worker         __ Fadd(sum, old_value_vreg, arg.IsD() ? arg.D() : arg.S());
1851*795d594fSAndroid Build Coastguard Worker         __ Fmov(new_value, sum);
1852*795d594fSAndroid Build Coastguard Worker       } else {
1853*795d594fSAndroid Build Coastguard Worker         __ Add(new_value, old_value_reg, arg.IsX() ? arg.X() : arg.W());
1854*795d594fSAndroid Build Coastguard Worker       }
1855*795d594fSAndroid Build Coastguard Worker       if (get_and_update_op == GetAndUpdateOp::kAddWithByteSwap) {
1856*795d594fSAndroid Build Coastguard Worker         GenerateReverseBytes(masm, load_store_type, new_value, new_value);
1857*795d594fSAndroid Build Coastguard Worker       }
1858*795d594fSAndroid Build Coastguard Worker       break;
1859*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kAnd:
1860*795d594fSAndroid Build Coastguard Worker       __ And(new_value, old_value_reg, arg.IsX() ? arg.X() : arg.W());
1861*795d594fSAndroid Build Coastguard Worker       break;
1862*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kOr:
1863*795d594fSAndroid Build Coastguard Worker       __ Orr(new_value, old_value_reg, arg.IsX() ? arg.X() : arg.W());
1864*795d594fSAndroid Build Coastguard Worker       break;
1865*795d594fSAndroid Build Coastguard Worker     case GetAndUpdateOp::kXor:
1866*795d594fSAndroid Build Coastguard Worker       __ Eor(new_value, old_value_reg, arg.IsX() ? arg.X() : arg.W());
1867*795d594fSAndroid Build Coastguard Worker       break;
1868*795d594fSAndroid Build Coastguard Worker   }
1869*795d594fSAndroid Build Coastguard Worker   EmitStoreExclusive(codegen, load_store_type, ptr, store_result, new_value, use_store_release);
1870*795d594fSAndroid Build Coastguard Worker   __ Cbnz(store_result, &loop_label);
1871*795d594fSAndroid Build Coastguard Worker }
1872*795d594fSAndroid Build Coastguard Worker 
CreateUnsafeGetAndUpdateLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorARM64 * codegen)1873*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
1874*795d594fSAndroid Build Coastguard Worker                                               HInvoke* invoke,
1875*795d594fSAndroid Build Coastguard Worker                                               CodeGeneratorARM64* codegen) {
1876*795d594fSAndroid Build Coastguard Worker   const bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetAndSetReference(invoke);
1877*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1878*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
1879*795d594fSAndroid Build Coastguard Worker                                       can_call
1880*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
1881*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
1882*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
1883*795d594fSAndroid Build Coastguard Worker   if (can_call && kUseBakerReadBarrier) {
1884*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
1885*795d594fSAndroid Build Coastguard Worker   }
1886*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1887*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1888*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
1889*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
1890*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
1891*795d594fSAndroid Build Coastguard Worker 
1892*795d594fSAndroid Build Coastguard Worker   // Request another temporary register for methods that don't return a value.
1893*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
1894*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
1895*795d594fSAndroid Build Coastguard Worker   if (is_void) {
1896*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
1897*795d594fSAndroid Build Coastguard Worker   } else {
1898*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1899*795d594fSAndroid Build Coastguard Worker   }
1900*795d594fSAndroid Build Coastguard Worker }
1901*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGetAndUpdate(HInvoke * invoke,DataType::Type type,CodeGeneratorARM64 * codegen,GetAndUpdateOp get_and_update_op)1902*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAndUpdate(HInvoke* invoke,
1903*795d594fSAndroid Build Coastguard Worker                                   DataType::Type type,
1904*795d594fSAndroid Build Coastguard Worker                                   CodeGeneratorARM64* codegen,
1905*795d594fSAndroid Build Coastguard Worker                                   GetAndUpdateOp get_and_update_op) {
1906*795d594fSAndroid Build Coastguard Worker   // Currently only used for these GetAndUpdateOp. Might be fine for other ops but double check
1907*795d594fSAndroid Build Coastguard Worker   // before using.
1908*795d594fSAndroid Build Coastguard Worker   DCHECK(get_and_update_op == GetAndUpdateOp::kAdd || get_and_update_op == GetAndUpdateOp::kSet);
1909*795d594fSAndroid Build Coastguard Worker 
1910*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
1911*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1912*795d594fSAndroid Build Coastguard Worker 
1913*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
1914*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
1915*795d594fSAndroid Build Coastguard Worker   // We use a temporary for void methods, as we don't return the value.
1916*795d594fSAndroid Build Coastguard Worker   Location out_or_temp_loc =
1917*795d594fSAndroid Build Coastguard Worker       is_void ? locations->GetTemp(locations->GetTempCount() - 1u) : locations->Out();
1918*795d594fSAndroid Build Coastguard Worker   Register out_or_temp = RegisterFrom(out_or_temp_loc, type);     // Result.
1919*795d594fSAndroid Build Coastguard Worker   Register base = WRegisterFrom(locations->InAt(1));              // Object pointer.
1920*795d594fSAndroid Build Coastguard Worker   Register offset = XRegisterFrom(locations->InAt(2));            // Long offset.
1921*795d594fSAndroid Build Coastguard Worker   Register arg = RegisterFrom(locations->InAt(3), type);          // New value or addend.
1922*795d594fSAndroid Build Coastguard Worker   Register tmp_ptr = XRegisterFrom(locations->GetTemp(0));        // Pointer to actual memory.
1923*795d594fSAndroid Build Coastguard Worker 
1924*795d594fSAndroid Build Coastguard Worker   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
1925*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1926*795d594fSAndroid Build Coastguard Worker     DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
1927*795d594fSAndroid Build Coastguard Worker     // Mark card for object as a new value shall be stored.
1928*795d594fSAndroid Build Coastguard Worker     bool new_value_can_be_null = true;  // TODO: Worth finding out this information?
1929*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(base, /*value=*/arg, new_value_can_be_null);
1930*795d594fSAndroid Build Coastguard Worker   }
1931*795d594fSAndroid Build Coastguard Worker 
1932*795d594fSAndroid Build Coastguard Worker   __ Add(tmp_ptr, base.X(), Operand(offset));
1933*795d594fSAndroid Build Coastguard Worker   GenerateGetAndUpdate(codegen,
1934*795d594fSAndroid Build Coastguard Worker                        get_and_update_op,
1935*795d594fSAndroid Build Coastguard Worker                        type,
1936*795d594fSAndroid Build Coastguard Worker                        std::memory_order_seq_cst,
1937*795d594fSAndroid Build Coastguard Worker                        tmp_ptr,
1938*795d594fSAndroid Build Coastguard Worker                        arg,
1939*795d594fSAndroid Build Coastguard Worker                        /*old_value=*/ out_or_temp);
1940*795d594fSAndroid Build Coastguard Worker 
1941*795d594fSAndroid Build Coastguard Worker   if (!is_void && type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
1942*795d594fSAndroid Build Coastguard Worker     DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
1943*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
1944*795d594fSAndroid Build Coastguard Worker       codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out_or_temp.W(), out_or_temp.W());
1945*795d594fSAndroid Build Coastguard Worker     } else {
1946*795d594fSAndroid Build Coastguard Worker       codegen->GenerateReadBarrierSlow(invoke,
1947*795d594fSAndroid Build Coastguard Worker                                        Location::RegisterLocation(out_or_temp.GetCode()),
1948*795d594fSAndroid Build Coastguard Worker                                        Location::RegisterLocation(out_or_temp.GetCode()),
1949*795d594fSAndroid Build Coastguard Worker                                        Location::RegisterLocation(base.GetCode()),
1950*795d594fSAndroid Build Coastguard Worker                                        /*offset=*/ 0u,
1951*795d594fSAndroid Build Coastguard Worker                                        /*index=*/ Location::RegisterLocation(offset.GetCode()));
1952*795d594fSAndroid Build Coastguard Worker     }
1953*795d594fSAndroid Build Coastguard Worker   }
1954*795d594fSAndroid Build Coastguard Worker }
1955*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddInt(HInvoke * invoke)1956*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
1957*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddInt(invoke);
1958*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndAddLong(HInvoke * invoke)1959*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
1960*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddLong(invoke);
1961*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetInt(HInvoke * invoke)1962*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
1963*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetInt(invoke);
1964*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetLong(HInvoke * invoke)1965*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
1966*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetLong(invoke);
1967*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetObject(HInvoke * invoke)1968*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
1969*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetReference(invoke);
1970*795d594fSAndroid Build Coastguard Worker }
1971*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)1972*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
1973*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
1974*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)1975*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
1976*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
1977*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)1978*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
1979*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
1980*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)1981*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
1982*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
1983*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)1984*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
1985*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
1986*795d594fSAndroid Build Coastguard Worker }
1987*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddInt(HInvoke * invoke)1988*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
1989*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddInt(invoke);
1990*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndAddLong(HInvoke * invoke)1991*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
1992*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddLong(invoke);
1993*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetInt(HInvoke * invoke)1994*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
1995*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetInt(invoke);
1996*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetLong(HInvoke * invoke)1997*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
1998*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetLong(invoke);
1999*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAndSetObject(HInvoke * invoke)2000*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
2001*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetReference(invoke);
2002*795d594fSAndroid Build Coastguard Worker }
2003*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)2004*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
2005*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kAdd);
2006*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)2007*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
2008*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kAdd);
2009*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)2010*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
2011*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kSet);
2012*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)2013*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
2014*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kSet);
2015*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)2016*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
2017*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kReference, codegen_, GetAndUpdateOp::kSet);
2018*795d594fSAndroid Build Coastguard Worker }
2019*795d594fSAndroid Build Coastguard Worker 
VisitStringCompareTo(HInvoke * invoke)2020*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringCompareTo(HInvoke* invoke) {
2021*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2022*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke,
2023*795d594fSAndroid Build Coastguard Worker                                        invoke->InputAt(1)->CanBeNull()
2024*795d594fSAndroid Build Coastguard Worker                                            ? LocationSummary::kCallOnSlowPath
2025*795d594fSAndroid Build Coastguard Worker                                            : LocationSummary::kNoCall,
2026*795d594fSAndroid Build Coastguard Worker                                        kIntrinsified);
2027*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2028*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
2029*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(3);
2030*795d594fSAndroid Build Coastguard Worker   // Need temporary registers for String compression's feature.
2031*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2032*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
2033*795d594fSAndroid Build Coastguard Worker   }
2034*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2035*795d594fSAndroid Build Coastguard Worker }
2036*795d594fSAndroid Build Coastguard Worker 
VisitStringCompareTo(HInvoke * invoke)2037*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringCompareTo(HInvoke* invoke) {
2038*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
2039*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2040*795d594fSAndroid Build Coastguard Worker 
2041*795d594fSAndroid Build Coastguard Worker   Register str = InputRegisterAt(invoke, 0);
2042*795d594fSAndroid Build Coastguard Worker   Register arg = InputRegisterAt(invoke, 1);
2043*795d594fSAndroid Build Coastguard Worker   DCHECK(str.IsW());
2044*795d594fSAndroid Build Coastguard Worker   DCHECK(arg.IsW());
2045*795d594fSAndroid Build Coastguard Worker   Register out = OutputRegister(invoke);
2046*795d594fSAndroid Build Coastguard Worker 
2047*795d594fSAndroid Build Coastguard Worker   Register temp0 = WRegisterFrom(locations->GetTemp(0));
2048*795d594fSAndroid Build Coastguard Worker   Register temp1 = WRegisterFrom(locations->GetTemp(1));
2049*795d594fSAndroid Build Coastguard Worker   Register temp2 = WRegisterFrom(locations->GetTemp(2));
2050*795d594fSAndroid Build Coastguard Worker   Register temp3;
2051*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2052*795d594fSAndroid Build Coastguard Worker     temp3 = WRegisterFrom(locations->GetTemp(3));
2053*795d594fSAndroid Build Coastguard Worker   }
2054*795d594fSAndroid Build Coastguard Worker 
2055*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop;
2056*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label find_char_diff;
2057*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label end;
2058*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label different_compression;
2059*795d594fSAndroid Build Coastguard Worker 
2060*795d594fSAndroid Build Coastguard Worker   // Get offsets of count and value fields within a string object.
2061*795d594fSAndroid Build Coastguard Worker   const int32_t count_offset = mirror::String::CountOffset().Int32Value();
2062*795d594fSAndroid Build Coastguard Worker   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2063*795d594fSAndroid Build Coastguard Worker 
2064*795d594fSAndroid Build Coastguard Worker   // Note that the null check must have been done earlier.
2065*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2066*795d594fSAndroid Build Coastguard Worker 
2067*795d594fSAndroid Build Coastguard Worker   // Take slow path and throw if input can be and is null.
2068*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path = nullptr;
2069*795d594fSAndroid Build Coastguard Worker   const bool can_slow_path = invoke->InputAt(1)->CanBeNull();
2070*795d594fSAndroid Build Coastguard Worker   if (can_slow_path) {
2071*795d594fSAndroid Build Coastguard Worker     slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
2072*795d594fSAndroid Build Coastguard Worker     codegen_->AddSlowPath(slow_path);
2073*795d594fSAndroid Build Coastguard Worker     __ Cbz(arg, slow_path->GetEntryLabel());
2074*795d594fSAndroid Build Coastguard Worker   }
2075*795d594fSAndroid Build Coastguard Worker 
2076*795d594fSAndroid Build Coastguard Worker   // Reference equality check, return 0 if same reference.
2077*795d594fSAndroid Build Coastguard Worker   __ Subs(out, str, arg);
2078*795d594fSAndroid Build Coastguard Worker   __ B(&end, eq);
2079*795d594fSAndroid Build Coastguard Worker 
2080*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2081*795d594fSAndroid Build Coastguard Worker     // Load `count` fields of this and argument strings.
2082*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp3, HeapOperand(str, count_offset));
2083*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp2, HeapOperand(arg, count_offset));
2084*795d594fSAndroid Build Coastguard Worker     // Clean out compression flag from lengths.
2085*795d594fSAndroid Build Coastguard Worker     __ Lsr(temp0, temp3, 1u);
2086*795d594fSAndroid Build Coastguard Worker     __ Lsr(temp1, temp2, 1u);
2087*795d594fSAndroid Build Coastguard Worker   } else {
2088*795d594fSAndroid Build Coastguard Worker     // Load lengths of this and argument strings.
2089*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp0, HeapOperand(str, count_offset));
2090*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp1, HeapOperand(arg, count_offset));
2091*795d594fSAndroid Build Coastguard Worker   }
2092*795d594fSAndroid Build Coastguard Worker   // out = length diff.
2093*795d594fSAndroid Build Coastguard Worker   __ Subs(out, temp0, temp1);
2094*795d594fSAndroid Build Coastguard Worker   // temp0 = min(len(str), len(arg)).
2095*795d594fSAndroid Build Coastguard Worker   __ Csel(temp0, temp1, temp0, ge);
2096*795d594fSAndroid Build Coastguard Worker   // Shorter string is empty?
2097*795d594fSAndroid Build Coastguard Worker   __ Cbz(temp0, &end);
2098*795d594fSAndroid Build Coastguard Worker 
2099*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2100*795d594fSAndroid Build Coastguard Worker     // Check if both strings using same compression style to use this comparison loop.
2101*795d594fSAndroid Build Coastguard Worker     __ Eor(temp2, temp2, Operand(temp3));
2102*795d594fSAndroid Build Coastguard Worker     // Interleave with compression flag extraction which is needed for both paths
2103*795d594fSAndroid Build Coastguard Worker     // and also set flags which is needed only for the different compressions path.
2104*795d594fSAndroid Build Coastguard Worker     __ Ands(temp3.W(), temp3.W(), Operand(1));
2105*795d594fSAndroid Build Coastguard Worker     __ Tbnz(temp2, 0, &different_compression);  // Does not use flags.
2106*795d594fSAndroid Build Coastguard Worker   }
2107*795d594fSAndroid Build Coastguard Worker   // Store offset of string value in preparation for comparison loop.
2108*795d594fSAndroid Build Coastguard Worker   __ Mov(temp1, value_offset);
2109*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2110*795d594fSAndroid Build Coastguard Worker     // For string compression, calculate the number of bytes to compare (not chars).
2111*795d594fSAndroid Build Coastguard Worker     // This could in theory exceed INT32_MAX, so treat temp0 as unsigned.
2112*795d594fSAndroid Build Coastguard Worker     __ Lsl(temp0, temp0, temp3);
2113*795d594fSAndroid Build Coastguard Worker   }
2114*795d594fSAndroid Build Coastguard Worker 
2115*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope scratch_scope(masm);
2116*795d594fSAndroid Build Coastguard Worker   Register temp4 = scratch_scope.AcquireX();
2117*795d594fSAndroid Build Coastguard Worker 
2118*795d594fSAndroid Build Coastguard Worker   // Assertions that must hold in order to compare strings 8 bytes at a time.
2119*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(value_offset, 8);
2120*795d594fSAndroid Build Coastguard Worker   static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
2121*795d594fSAndroid Build Coastguard Worker 
2122*795d594fSAndroid Build Coastguard Worker   const size_t char_size = DataType::Size(DataType::Type::kUint16);
2123*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(char_size, 2u);
2124*795d594fSAndroid Build Coastguard Worker 
2125*795d594fSAndroid Build Coastguard Worker   // Promote temp2 to an X reg, ready for LDR.
2126*795d594fSAndroid Build Coastguard Worker   temp2 = temp2.X();
2127*795d594fSAndroid Build Coastguard Worker 
2128*795d594fSAndroid Build Coastguard Worker   // Loop to compare 4x16-bit characters at a time (ok because of string data alignment).
2129*795d594fSAndroid Build Coastguard Worker   __ Bind(&loop);
2130*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp4, MemOperand(str.X(), temp1.X()));
2131*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp2, MemOperand(arg.X(), temp1.X()));
2132*795d594fSAndroid Build Coastguard Worker   __ Cmp(temp4, temp2);
2133*795d594fSAndroid Build Coastguard Worker   __ B(ne, &find_char_diff);
2134*795d594fSAndroid Build Coastguard Worker   __ Add(temp1, temp1, char_size * 4);
2135*795d594fSAndroid Build Coastguard Worker   // With string compression, we have compared 8 bytes, otherwise 4 chars.
2136*795d594fSAndroid Build Coastguard Worker   __ Subs(temp0, temp0, (mirror::kUseStringCompression) ? 8 : 4);
2137*795d594fSAndroid Build Coastguard Worker   __ B(&loop, hi);
2138*795d594fSAndroid Build Coastguard Worker   __ B(&end);
2139*795d594fSAndroid Build Coastguard Worker 
2140*795d594fSAndroid Build Coastguard Worker   // Promote temp1 to an X reg, ready for EOR.
2141*795d594fSAndroid Build Coastguard Worker   temp1 = temp1.X();
2142*795d594fSAndroid Build Coastguard Worker 
2143*795d594fSAndroid Build Coastguard Worker   // Find the single character difference.
2144*795d594fSAndroid Build Coastguard Worker   __ Bind(&find_char_diff);
2145*795d594fSAndroid Build Coastguard Worker   // Get the bit position of the first character that differs.
2146*795d594fSAndroid Build Coastguard Worker   __ Eor(temp1, temp2, temp4);
2147*795d594fSAndroid Build Coastguard Worker   __ Rbit(temp1, temp1);
2148*795d594fSAndroid Build Coastguard Worker   __ Clz(temp1, temp1);
2149*795d594fSAndroid Build Coastguard Worker 
2150*795d594fSAndroid Build Coastguard Worker   // If the number of chars remaining <= the index where the difference occurs (0-3), then
2151*795d594fSAndroid Build Coastguard Worker   // the difference occurs outside the remaining string data, so just return length diff (out).
2152*795d594fSAndroid Build Coastguard Worker   // Unlike ARM, we're doing the comparison in one go here, without the subtraction at the
2153*795d594fSAndroid Build Coastguard Worker   // find_char_diff_2nd_cmp path, so it doesn't matter whether the comparison is signed or
2154*795d594fSAndroid Build Coastguard Worker   // unsigned when string compression is disabled.
2155*795d594fSAndroid Build Coastguard Worker   // When it's enabled, the comparison must be unsigned.
2156*795d594fSAndroid Build Coastguard Worker   __ Cmp(temp0, Operand(temp1.W(), LSR, (mirror::kUseStringCompression) ? 3 : 4));
2157*795d594fSAndroid Build Coastguard Worker   __ B(ls, &end);
2158*795d594fSAndroid Build Coastguard Worker 
2159*795d594fSAndroid Build Coastguard Worker   // Extract the characters and calculate the difference.
2160*795d594fSAndroid Build Coastguard Worker   if (mirror:: kUseStringCompression) {
2161*795d594fSAndroid Build Coastguard Worker     __ Bic(temp1, temp1, 0x7);
2162*795d594fSAndroid Build Coastguard Worker     __ Bic(temp1, temp1, Operand(temp3.X(), LSL, 3u));
2163*795d594fSAndroid Build Coastguard Worker   } else {
2164*795d594fSAndroid Build Coastguard Worker     __ Bic(temp1, temp1, 0xf);
2165*795d594fSAndroid Build Coastguard Worker   }
2166*795d594fSAndroid Build Coastguard Worker   __ Lsr(temp2, temp2, temp1);
2167*795d594fSAndroid Build Coastguard Worker   __ Lsr(temp4, temp4, temp1);
2168*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2169*795d594fSAndroid Build Coastguard Worker     // Prioritize the case of compressed strings and calculate such result first.
2170*795d594fSAndroid Build Coastguard Worker     __ Uxtb(temp1, temp4);
2171*795d594fSAndroid Build Coastguard Worker     __ Sub(out, temp1.W(), Operand(temp2.W(), UXTB));
2172*795d594fSAndroid Build Coastguard Worker     __ Tbz(temp3, 0u, &end);  // If actually compressed, we're done.
2173*795d594fSAndroid Build Coastguard Worker   }
2174*795d594fSAndroid Build Coastguard Worker   __ Uxth(temp4, temp4);
2175*795d594fSAndroid Build Coastguard Worker   __ Sub(out, temp4.W(), Operand(temp2.W(), UXTH));
2176*795d594fSAndroid Build Coastguard Worker 
2177*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2178*795d594fSAndroid Build Coastguard Worker     __ B(&end);
2179*795d594fSAndroid Build Coastguard Worker     __ Bind(&different_compression);
2180*795d594fSAndroid Build Coastguard Worker 
2181*795d594fSAndroid Build Coastguard Worker     // Comparison for different compression style.
2182*795d594fSAndroid Build Coastguard Worker     const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
2183*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(c_char_size, 1u);
2184*795d594fSAndroid Build Coastguard Worker     temp1 = temp1.W();
2185*795d594fSAndroid Build Coastguard Worker     temp2 = temp2.W();
2186*795d594fSAndroid Build Coastguard Worker     temp4 = temp4.W();
2187*795d594fSAndroid Build Coastguard Worker 
2188*795d594fSAndroid Build Coastguard Worker     // `temp1` will hold the compressed data pointer, `temp2` the uncompressed data pointer.
2189*795d594fSAndroid Build Coastguard Worker     // Note that flags have been set by the `str` compression flag extraction to `temp3`
2190*795d594fSAndroid Build Coastguard Worker     // before branching to the `different_compression` label.
2191*795d594fSAndroid Build Coastguard Worker     __ Csel(temp1, str, arg, eq);   // Pointer to the compressed string.
2192*795d594fSAndroid Build Coastguard Worker     __ Csel(temp2, str, arg, ne);   // Pointer to the uncompressed string.
2193*795d594fSAndroid Build Coastguard Worker 
2194*795d594fSAndroid Build Coastguard Worker     // We want to free up the temp3, currently holding `str` compression flag, for comparison.
2195*795d594fSAndroid Build Coastguard Worker     // So, we move it to the bottom bit of the iteration count `temp0` which we then need to treat
2196*795d594fSAndroid Build Coastguard Worker     // as unsigned. Start by freeing the bit with a LSL and continue further down by a SUB which
2197*795d594fSAndroid Build Coastguard Worker     // will allow `subs temp0, #2; bhi different_compression_loop` to serve as the loop condition.
2198*795d594fSAndroid Build Coastguard Worker     __ Lsl(temp0, temp0, 1u);
2199*795d594fSAndroid Build Coastguard Worker 
2200*795d594fSAndroid Build Coastguard Worker     // Adjust temp1 and temp2 from string pointers to data pointers.
2201*795d594fSAndroid Build Coastguard Worker     __ Add(temp1, temp1, Operand(value_offset));
2202*795d594fSAndroid Build Coastguard Worker     __ Add(temp2, temp2, Operand(value_offset));
2203*795d594fSAndroid Build Coastguard Worker 
2204*795d594fSAndroid Build Coastguard Worker     // Complete the move of the compression flag.
2205*795d594fSAndroid Build Coastguard Worker     __ Sub(temp0, temp0, Operand(temp3));
2206*795d594fSAndroid Build Coastguard Worker 
2207*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label different_compression_loop;
2208*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label different_compression_diff;
2209*795d594fSAndroid Build Coastguard Worker 
2210*795d594fSAndroid Build Coastguard Worker     __ Bind(&different_compression_loop);
2211*795d594fSAndroid Build Coastguard Worker     __ Ldrb(temp4, MemOperand(temp1.X(), c_char_size, PostIndex));
2212*795d594fSAndroid Build Coastguard Worker     __ Ldrh(temp3, MemOperand(temp2.X(), char_size, PostIndex));
2213*795d594fSAndroid Build Coastguard Worker     __ Subs(temp4, temp4, Operand(temp3));
2214*795d594fSAndroid Build Coastguard Worker     __ B(&different_compression_diff, ne);
2215*795d594fSAndroid Build Coastguard Worker     __ Subs(temp0, temp0, 2);
2216*795d594fSAndroid Build Coastguard Worker     __ B(&different_compression_loop, hi);
2217*795d594fSAndroid Build Coastguard Worker     __ B(&end);
2218*795d594fSAndroid Build Coastguard Worker 
2219*795d594fSAndroid Build Coastguard Worker     // Calculate the difference.
2220*795d594fSAndroid Build Coastguard Worker     __ Bind(&different_compression_diff);
2221*795d594fSAndroid Build Coastguard Worker     __ Tst(temp0, Operand(1));
2222*795d594fSAndroid Build Coastguard Worker     static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2223*795d594fSAndroid Build Coastguard Worker                   "Expecting 0=compressed, 1=uncompressed");
2224*795d594fSAndroid Build Coastguard Worker     __ Cneg(out, temp4, ne);
2225*795d594fSAndroid Build Coastguard Worker   }
2226*795d594fSAndroid Build Coastguard Worker 
2227*795d594fSAndroid Build Coastguard Worker   __ Bind(&end);
2228*795d594fSAndroid Build Coastguard Worker 
2229*795d594fSAndroid Build Coastguard Worker   if (can_slow_path) {
2230*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
2231*795d594fSAndroid Build Coastguard Worker   }
2232*795d594fSAndroid Build Coastguard Worker }
2233*795d594fSAndroid Build Coastguard Worker 
2234*795d594fSAndroid Build Coastguard Worker // The cut off for unrolling the loop in String.equals() intrinsic for const strings.
2235*795d594fSAndroid Build Coastguard Worker // The normal loop plus the pre-header is 9 instructions without string compression and 12
2236*795d594fSAndroid Build Coastguard Worker // instructions with string compression. We can compare up to 8 bytes in 4 instructions
2237*795d594fSAndroid Build Coastguard Worker // (LDR+LDR+CMP+BNE) and up to 16 bytes in 5 instructions (LDP+LDP+CMP+CCMP+BNE). Allow up
2238*795d594fSAndroid Build Coastguard Worker // to 10 instructions for the unrolled loop.
2239*795d594fSAndroid Build Coastguard Worker constexpr size_t kShortConstStringEqualsCutoffInBytes = 32;
2240*795d594fSAndroid Build Coastguard Worker 
GetConstString(HInstruction * candidate,uint32_t * utf16_length)2241*795d594fSAndroid Build Coastguard Worker static const char* GetConstString(HInstruction* candidate, uint32_t* utf16_length) {
2242*795d594fSAndroid Build Coastguard Worker   if (candidate->IsLoadString()) {
2243*795d594fSAndroid Build Coastguard Worker     HLoadString* load_string = candidate->AsLoadString();
2244*795d594fSAndroid Build Coastguard Worker     const DexFile& dex_file = load_string->GetDexFile();
2245*795d594fSAndroid Build Coastguard Worker     return dex_file.GetStringDataAndUtf16Length(load_string->GetStringIndex(), utf16_length);
2246*795d594fSAndroid Build Coastguard Worker   }
2247*795d594fSAndroid Build Coastguard Worker   return nullptr;
2248*795d594fSAndroid Build Coastguard Worker }
2249*795d594fSAndroid Build Coastguard Worker 
VisitStringEquals(HInvoke * invoke)2250*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringEquals(HInvoke* invoke) {
2251*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2252*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2253*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2254*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
2255*795d594fSAndroid Build Coastguard Worker 
2256*795d594fSAndroid Build Coastguard Worker   // For the generic implementation and for long const strings we need a temporary.
2257*795d594fSAndroid Build Coastguard Worker   // We do not need it for short const strings, up to 8 bytes, see code generation below.
2258*795d594fSAndroid Build Coastguard Worker   uint32_t const_string_length = 0u;
2259*795d594fSAndroid Build Coastguard Worker   const char* const_string = GetConstString(invoke->InputAt(0), &const_string_length);
2260*795d594fSAndroid Build Coastguard Worker   if (const_string == nullptr) {
2261*795d594fSAndroid Build Coastguard Worker     const_string = GetConstString(invoke->InputAt(1), &const_string_length);
2262*795d594fSAndroid Build Coastguard Worker   }
2263*795d594fSAndroid Build Coastguard Worker   bool is_compressed =
2264*795d594fSAndroid Build Coastguard Worker       mirror::kUseStringCompression &&
2265*795d594fSAndroid Build Coastguard Worker       const_string != nullptr &&
2266*795d594fSAndroid Build Coastguard Worker       mirror::String::DexFileStringAllASCII(const_string, const_string_length);
2267*795d594fSAndroid Build Coastguard Worker   if (const_string == nullptr || const_string_length > (is_compressed ? 8u : 4u)) {
2268*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
2269*795d594fSAndroid Build Coastguard Worker   }
2270*795d594fSAndroid Build Coastguard Worker 
2271*795d594fSAndroid Build Coastguard Worker   // TODO: If the String.equals() is used only for an immediately following HIf, we can
2272*795d594fSAndroid Build Coastguard Worker   // mark it as emitted-at-use-site and emit branches directly to the appropriate blocks.
2273*795d594fSAndroid Build Coastguard Worker   // Then we shall need an extra temporary register instead of the output register.
2274*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2275*795d594fSAndroid Build Coastguard Worker }
2276*795d594fSAndroid Build Coastguard Worker 
VisitStringEquals(HInvoke * invoke)2277*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringEquals(HInvoke* invoke) {
2278*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
2279*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2280*795d594fSAndroid Build Coastguard Worker 
2281*795d594fSAndroid Build Coastguard Worker   Register str = WRegisterFrom(locations->InAt(0));
2282*795d594fSAndroid Build Coastguard Worker   Register arg = WRegisterFrom(locations->InAt(1));
2283*795d594fSAndroid Build Coastguard Worker   Register out = XRegisterFrom(locations->Out());
2284*795d594fSAndroid Build Coastguard Worker 
2285*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope scratch_scope(masm);
2286*795d594fSAndroid Build Coastguard Worker   Register temp = scratch_scope.AcquireW();
2287*795d594fSAndroid Build Coastguard Worker   Register temp1 = scratch_scope.AcquireW();
2288*795d594fSAndroid Build Coastguard Worker 
2289*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop;
2290*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label end;
2291*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label return_true;
2292*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label return_false;
2293*795d594fSAndroid Build Coastguard Worker 
2294*795d594fSAndroid Build Coastguard Worker   // Get offsets of count, value, and class fields within a string object.
2295*795d594fSAndroid Build Coastguard Worker   const int32_t count_offset = mirror::String::CountOffset().Int32Value();
2296*795d594fSAndroid Build Coastguard Worker   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2297*795d594fSAndroid Build Coastguard Worker   const int32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2298*795d594fSAndroid Build Coastguard Worker 
2299*795d594fSAndroid Build Coastguard Worker   // Note that the null check must have been done earlier.
2300*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2301*795d594fSAndroid Build Coastguard Worker 
2302*795d594fSAndroid Build Coastguard Worker   StringEqualsOptimizations optimizations(invoke);
2303*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetArgumentNotNull()) {
2304*795d594fSAndroid Build Coastguard Worker     // Check if input is null, return false if it is.
2305*795d594fSAndroid Build Coastguard Worker     __ Cbz(arg, &return_false);
2306*795d594fSAndroid Build Coastguard Worker   }
2307*795d594fSAndroid Build Coastguard Worker 
2308*795d594fSAndroid Build Coastguard Worker   // Reference equality check, return true if same reference.
2309*795d594fSAndroid Build Coastguard Worker   __ Cmp(str, arg);
2310*795d594fSAndroid Build Coastguard Worker   __ B(&return_true, eq);
2311*795d594fSAndroid Build Coastguard Worker 
2312*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetArgumentIsString()) {
2313*795d594fSAndroid Build Coastguard Worker     // Instanceof check for the argument by comparing class fields.
2314*795d594fSAndroid Build Coastguard Worker     // All string objects must have the same type since String cannot be subclassed.
2315*795d594fSAndroid Build Coastguard Worker     // Receiver must be a string object, so its class field is equal to all strings' class fields.
2316*795d594fSAndroid Build Coastguard Worker     // If the argument is a string object, its class field must be equal to receiver's class field.
2317*795d594fSAndroid Build Coastguard Worker     //
2318*795d594fSAndroid Build Coastguard Worker     // As the String class is expected to be non-movable, we can read the class
2319*795d594fSAndroid Build Coastguard Worker     // field from String.equals' arguments without read barriers.
2320*795d594fSAndroid Build Coastguard Worker     AssertNonMovableStringClass();
2321*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp = str->klass_
2322*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, MemOperand(str.X(), class_offset));
2323*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp1 = arg->klass_
2324*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp1, MemOperand(arg.X(), class_offset));
2325*795d594fSAndroid Build Coastguard Worker     // Also, because we use the previously loaded class references only in the
2326*795d594fSAndroid Build Coastguard Worker     // following comparison, we don't need to unpoison them.
2327*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp, temp1);
2328*795d594fSAndroid Build Coastguard Worker     __ B(&return_false, ne);
2329*795d594fSAndroid Build Coastguard Worker   }
2330*795d594fSAndroid Build Coastguard Worker 
2331*795d594fSAndroid Build Coastguard Worker   // Check if one of the inputs is a const string. Do not special-case both strings
2332*795d594fSAndroid Build Coastguard Worker   // being const, such cases should be handled by constant folding if needed.
2333*795d594fSAndroid Build Coastguard Worker   uint32_t const_string_length = 0u;
2334*795d594fSAndroid Build Coastguard Worker   const char* const_string = GetConstString(invoke->InputAt(0), &const_string_length);
2335*795d594fSAndroid Build Coastguard Worker   if (const_string == nullptr) {
2336*795d594fSAndroid Build Coastguard Worker     const_string = GetConstString(invoke->InputAt(1), &const_string_length);
2337*795d594fSAndroid Build Coastguard Worker     if (const_string != nullptr) {
2338*795d594fSAndroid Build Coastguard Worker       std::swap(str, arg);  // Make sure the const string is in `str`.
2339*795d594fSAndroid Build Coastguard Worker     }
2340*795d594fSAndroid Build Coastguard Worker   }
2341*795d594fSAndroid Build Coastguard Worker   bool is_compressed =
2342*795d594fSAndroid Build Coastguard Worker       mirror::kUseStringCompression &&
2343*795d594fSAndroid Build Coastguard Worker       const_string != nullptr &&
2344*795d594fSAndroid Build Coastguard Worker       mirror::String::DexFileStringAllASCII(const_string, const_string_length);
2345*795d594fSAndroid Build Coastguard Worker 
2346*795d594fSAndroid Build Coastguard Worker   if (const_string != nullptr) {
2347*795d594fSAndroid Build Coastguard Worker     // Load `count` field of the argument string and check if it matches the const string.
2348*795d594fSAndroid Build Coastguard Worker     // Also compares the compression style, if differs return false.
2349*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, MemOperand(arg.X(), count_offset));
2350*795d594fSAndroid Build Coastguard Worker     // Temporarily release temp1 as we may not be able to embed the flagged count in CMP immediate.
2351*795d594fSAndroid Build Coastguard Worker     scratch_scope.Release(temp1);
2352*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp, Operand(mirror::String::GetFlaggedCount(const_string_length, is_compressed)));
2353*795d594fSAndroid Build Coastguard Worker     temp1 = scratch_scope.AcquireW();
2354*795d594fSAndroid Build Coastguard Worker     __ B(&return_false, ne);
2355*795d594fSAndroid Build Coastguard Worker   } else {
2356*795d594fSAndroid Build Coastguard Worker     // Load `count` fields of this and argument strings.
2357*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, MemOperand(str.X(), count_offset));
2358*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp1, MemOperand(arg.X(), count_offset));
2359*795d594fSAndroid Build Coastguard Worker     // Check if `count` fields are equal, return false if they're not.
2360*795d594fSAndroid Build Coastguard Worker     // Also compares the compression style, if differs return false.
2361*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp, temp1);
2362*795d594fSAndroid Build Coastguard Worker     __ B(&return_false, ne);
2363*795d594fSAndroid Build Coastguard Worker   }
2364*795d594fSAndroid Build Coastguard Worker 
2365*795d594fSAndroid Build Coastguard Worker   // Assertions that must hold in order to compare strings 8 bytes at a time.
2366*795d594fSAndroid Build Coastguard Worker   // Ok to do this because strings are zero-padded to kObjectAlignment.
2367*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(value_offset, 8);
2368*795d594fSAndroid Build Coastguard Worker   static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
2369*795d594fSAndroid Build Coastguard Worker 
2370*795d594fSAndroid Build Coastguard Worker   if (const_string != nullptr &&
2371*795d594fSAndroid Build Coastguard Worker       const_string_length <= (is_compressed ? kShortConstStringEqualsCutoffInBytes
2372*795d594fSAndroid Build Coastguard Worker                                             : kShortConstStringEqualsCutoffInBytes / 2u)) {
2373*795d594fSAndroid Build Coastguard Worker     // Load and compare the contents. Though we know the contents of the short const string
2374*795d594fSAndroid Build Coastguard Worker     // at compile time, materializing constants may be more code than loading from memory.
2375*795d594fSAndroid Build Coastguard Worker     int32_t offset = value_offset;
2376*795d594fSAndroid Build Coastguard Worker     size_t remaining_bytes =
2377*795d594fSAndroid Build Coastguard Worker         RoundUp(is_compressed ? const_string_length : const_string_length * 2u, 8u);
2378*795d594fSAndroid Build Coastguard Worker     temp = temp.X();
2379*795d594fSAndroid Build Coastguard Worker     temp1 = temp1.X();
2380*795d594fSAndroid Build Coastguard Worker     while (remaining_bytes > sizeof(uint64_t)) {
2381*795d594fSAndroid Build Coastguard Worker       Register temp2 = XRegisterFrom(locations->GetTemp(0));
2382*795d594fSAndroid Build Coastguard Worker       __ Ldp(temp, temp1, MemOperand(str.X(), offset));
2383*795d594fSAndroid Build Coastguard Worker       __ Ldp(temp2, out, MemOperand(arg.X(), offset));
2384*795d594fSAndroid Build Coastguard Worker       __ Cmp(temp, temp2);
2385*795d594fSAndroid Build Coastguard Worker       __ Ccmp(temp1, out, NoFlag, eq);
2386*795d594fSAndroid Build Coastguard Worker       __ B(&return_false, ne);
2387*795d594fSAndroid Build Coastguard Worker       offset += 2u * sizeof(uint64_t);
2388*795d594fSAndroid Build Coastguard Worker       remaining_bytes -= 2u * sizeof(uint64_t);
2389*795d594fSAndroid Build Coastguard Worker     }
2390*795d594fSAndroid Build Coastguard Worker     if (remaining_bytes != 0u) {
2391*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp, MemOperand(str.X(), offset));
2392*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp1, MemOperand(arg.X(), offset));
2393*795d594fSAndroid Build Coastguard Worker       __ Cmp(temp, temp1);
2394*795d594fSAndroid Build Coastguard Worker       __ B(&return_false, ne);
2395*795d594fSAndroid Build Coastguard Worker     }
2396*795d594fSAndroid Build Coastguard Worker   } else {
2397*795d594fSAndroid Build Coastguard Worker     // Return true if both strings are empty. Even with string compression `count == 0` means empty.
2398*795d594fSAndroid Build Coastguard Worker     static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2399*795d594fSAndroid Build Coastguard Worker                   "Expecting 0=compressed, 1=uncompressed");
2400*795d594fSAndroid Build Coastguard Worker     __ Cbz(temp, &return_true);
2401*795d594fSAndroid Build Coastguard Worker 
2402*795d594fSAndroid Build Coastguard Worker     if (mirror::kUseStringCompression) {
2403*795d594fSAndroid Build Coastguard Worker       // For string compression, calculate the number of bytes to compare (not chars).
2404*795d594fSAndroid Build Coastguard Worker       // This could in theory exceed INT32_MAX, so treat temp as unsigned.
2405*795d594fSAndroid Build Coastguard Worker       __ And(temp1, temp, Operand(1));    // Extract compression flag.
2406*795d594fSAndroid Build Coastguard Worker       __ Lsr(temp, temp, 1u);             // Extract length.
2407*795d594fSAndroid Build Coastguard Worker       __ Lsl(temp, temp, temp1);          // Calculate number of bytes to compare.
2408*795d594fSAndroid Build Coastguard Worker     }
2409*795d594fSAndroid Build Coastguard Worker 
2410*795d594fSAndroid Build Coastguard Worker     // Store offset of string value in preparation for comparison loop
2411*795d594fSAndroid Build Coastguard Worker     __ Mov(temp1, value_offset);
2412*795d594fSAndroid Build Coastguard Worker 
2413*795d594fSAndroid Build Coastguard Worker     temp1 = temp1.X();
2414*795d594fSAndroid Build Coastguard Worker     Register temp2 = XRegisterFrom(locations->GetTemp(0));
2415*795d594fSAndroid Build Coastguard Worker     // Loop to compare strings 8 bytes at a time starting at the front of the string.
2416*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop);
2417*795d594fSAndroid Build Coastguard Worker     __ Ldr(out, MemOperand(str.X(), temp1));
2418*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp2, MemOperand(arg.X(), temp1));
2419*795d594fSAndroid Build Coastguard Worker     __ Add(temp1, temp1, Operand(sizeof(uint64_t)));
2420*795d594fSAndroid Build Coastguard Worker     __ Cmp(out, temp2);
2421*795d594fSAndroid Build Coastguard Worker     __ B(&return_false, ne);
2422*795d594fSAndroid Build Coastguard Worker     // With string compression, we have compared 8 bytes, otherwise 4 chars.
2423*795d594fSAndroid Build Coastguard Worker     __ Sub(temp, temp, Operand(mirror::kUseStringCompression ? 8 : 4), SetFlags);
2424*795d594fSAndroid Build Coastguard Worker     __ B(&loop, hi);
2425*795d594fSAndroid Build Coastguard Worker   }
2426*795d594fSAndroid Build Coastguard Worker 
2427*795d594fSAndroid Build Coastguard Worker   // Return true and exit the function.
2428*795d594fSAndroid Build Coastguard Worker   // If loop does not result in returning false, we return true.
2429*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_true);
2430*795d594fSAndroid Build Coastguard Worker   __ Mov(out, 1);
2431*795d594fSAndroid Build Coastguard Worker   __ B(&end);
2432*795d594fSAndroid Build Coastguard Worker 
2433*795d594fSAndroid Build Coastguard Worker   // Return false and exit the function.
2434*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_false);
2435*795d594fSAndroid Build Coastguard Worker   __ Mov(out, 0);
2436*795d594fSAndroid Build Coastguard Worker   __ Bind(&end);
2437*795d594fSAndroid Build Coastguard Worker }
2438*795d594fSAndroid Build Coastguard Worker 
GenerateVisitStringIndexOf(HInvoke * invoke,MacroAssembler * masm,CodeGeneratorARM64 * codegen,bool start_at_zero)2439*795d594fSAndroid Build Coastguard Worker static void GenerateVisitStringIndexOf(HInvoke* invoke,
2440*795d594fSAndroid Build Coastguard Worker                                        MacroAssembler* masm,
2441*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorARM64* codegen,
2442*795d594fSAndroid Build Coastguard Worker                                        bool start_at_zero) {
2443*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2444*795d594fSAndroid Build Coastguard Worker 
2445*795d594fSAndroid Build Coastguard Worker   // Note that the null check must have been done earlier.
2446*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2447*795d594fSAndroid Build Coastguard Worker 
2448*795d594fSAndroid Build Coastguard Worker   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
2449*795d594fSAndroid Build Coastguard Worker   // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
2450*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path = nullptr;
2451*795d594fSAndroid Build Coastguard Worker   HInstruction* code_point = invoke->InputAt(1);
2452*795d594fSAndroid Build Coastguard Worker   if (code_point->IsIntConstant()) {
2453*795d594fSAndroid Build Coastguard Worker     if (static_cast<uint32_t>(code_point->AsIntConstant()->GetValue()) > 0xFFFFU) {
2454*795d594fSAndroid Build Coastguard Worker       // Always needs the slow-path. We could directly dispatch to it, but this case should be
2455*795d594fSAndroid Build Coastguard Worker       // rare, so for simplicity just put the full slow-path down and branch unconditionally.
2456*795d594fSAndroid Build Coastguard Worker       slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
2457*795d594fSAndroid Build Coastguard Worker       codegen->AddSlowPath(slow_path);
2458*795d594fSAndroid Build Coastguard Worker       __ B(slow_path->GetEntryLabel());
2459*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetExitLabel());
2460*795d594fSAndroid Build Coastguard Worker       return;
2461*795d594fSAndroid Build Coastguard Worker     }
2462*795d594fSAndroid Build Coastguard Worker   } else if (code_point->GetType() != DataType::Type::kUint16) {
2463*795d594fSAndroid Build Coastguard Worker     Register char_reg = WRegisterFrom(locations->InAt(1));
2464*795d594fSAndroid Build Coastguard Worker     __ Tst(char_reg, 0xFFFF0000);
2465*795d594fSAndroid Build Coastguard Worker     slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
2466*795d594fSAndroid Build Coastguard Worker     codegen->AddSlowPath(slow_path);
2467*795d594fSAndroid Build Coastguard Worker     __ B(ne, slow_path->GetEntryLabel());
2468*795d594fSAndroid Build Coastguard Worker   }
2469*795d594fSAndroid Build Coastguard Worker 
2470*795d594fSAndroid Build Coastguard Worker   if (start_at_zero) {
2471*795d594fSAndroid Build Coastguard Worker     // Start-index = 0.
2472*795d594fSAndroid Build Coastguard Worker     Register tmp_reg = WRegisterFrom(locations->GetTemp(0));
2473*795d594fSAndroid Build Coastguard Worker     __ Mov(tmp_reg, 0);
2474*795d594fSAndroid Build Coastguard Worker   }
2475*795d594fSAndroid Build Coastguard Worker 
2476*795d594fSAndroid Build Coastguard Worker   codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
2477*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
2478*795d594fSAndroid Build Coastguard Worker 
2479*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
2480*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
2481*795d594fSAndroid Build Coastguard Worker   }
2482*795d594fSAndroid Build Coastguard Worker }
2483*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOf(HInvoke * invoke)2484*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringIndexOf(HInvoke* invoke) {
2485*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
2486*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
2487*795d594fSAndroid Build Coastguard Worker   // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
2488*795d594fSAndroid Build Coastguard Worker   // best to align the inputs accordingly.
2489*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2490*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2491*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
2492*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
2493*795d594fSAndroid Build Coastguard Worker 
2494*795d594fSAndroid Build Coastguard Worker   // Need to send start_index=0.
2495*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
2496*795d594fSAndroid Build Coastguard Worker }
2497*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOf(HInvoke * invoke)2498*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringIndexOf(HInvoke* invoke) {
2499*795d594fSAndroid Build Coastguard Worker   GenerateVisitStringIndexOf(invoke, GetVIXLAssembler(), codegen_, /* start_at_zero= */ true);
2500*795d594fSAndroid Build Coastguard Worker }
2501*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOfAfter(HInvoke * invoke)2502*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringIndexOfAfter(HInvoke* invoke) {
2503*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
2504*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
2505*795d594fSAndroid Build Coastguard Worker   // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
2506*795d594fSAndroid Build Coastguard Worker   // best to align the inputs accordingly.
2507*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2508*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2509*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
2510*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
2511*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
2512*795d594fSAndroid Build Coastguard Worker }
2513*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOfAfter(HInvoke * invoke)2514*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringIndexOfAfter(HInvoke* invoke) {
2515*795d594fSAndroid Build Coastguard Worker   GenerateVisitStringIndexOf(invoke, GetVIXLAssembler(), codegen_, /* start_at_zero= */ false);
2516*795d594fSAndroid Build Coastguard Worker }
2517*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromBytes(HInvoke * invoke)2518*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromBytes(HInvoke* invoke) {
2519*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
2520*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
2521*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2522*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2523*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
2524*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
2525*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, LocationFrom(calling_convention.GetRegisterAt(3)));
2526*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
2527*795d594fSAndroid Build Coastguard Worker }
2528*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromBytes(HInvoke * invoke)2529*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromBytes(HInvoke* invoke) {
2530*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
2531*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2532*795d594fSAndroid Build Coastguard Worker 
2533*795d594fSAndroid Build Coastguard Worker   Register byte_array = WRegisterFrom(locations->InAt(0));
2534*795d594fSAndroid Build Coastguard Worker   __ Cmp(byte_array, 0);
2535*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
2536*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
2537*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
2538*795d594fSAndroid Build Coastguard Worker   __ B(eq, slow_path->GetEntryLabel());
2539*795d594fSAndroid Build Coastguard Worker 
2540*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
2541*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
2542*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
2543*795d594fSAndroid Build Coastguard Worker }
2544*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromChars(HInvoke * invoke)2545*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromChars(HInvoke* invoke) {
2546*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2547*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
2548*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2549*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2550*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
2551*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
2552*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
2553*795d594fSAndroid Build Coastguard Worker }
2554*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromChars(HInvoke * invoke)2555*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromChars(HInvoke* invoke) {
2556*795d594fSAndroid Build Coastguard Worker   // No need to emit code checking whether `locations->InAt(2)` is a null
2557*795d594fSAndroid Build Coastguard Worker   // pointer, as callers of the native method
2558*795d594fSAndroid Build Coastguard Worker   //
2559*795d594fSAndroid Build Coastguard Worker   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
2560*795d594fSAndroid Build Coastguard Worker   //
2561*795d594fSAndroid Build Coastguard Worker   // all include a null check on `data` before calling that method.
2562*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
2563*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
2564*795d594fSAndroid Build Coastguard Worker }
2565*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromString(HInvoke * invoke)2566*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromString(HInvoke* invoke) {
2567*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
2568*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
2569*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2570*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2571*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
2572*795d594fSAndroid Build Coastguard Worker }
2573*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromString(HInvoke * invoke)2574*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromString(HInvoke* invoke) {
2575*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
2576*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2577*795d594fSAndroid Build Coastguard Worker 
2578*795d594fSAndroid Build Coastguard Worker   Register string_to_copy = WRegisterFrom(locations->InAt(0));
2579*795d594fSAndroid Build Coastguard Worker   __ Cmp(string_to_copy, 0);
2580*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
2581*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
2582*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
2583*795d594fSAndroid Build Coastguard Worker   __ B(eq, slow_path->GetEntryLabel());
2584*795d594fSAndroid Build Coastguard Worker 
2585*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
2586*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
2587*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
2588*795d594fSAndroid Build Coastguard Worker }
2589*795d594fSAndroid Build Coastguard Worker 
CreateFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)2590*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2591*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
2592*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
2593*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
2594*795d594fSAndroid Build Coastguard Worker 
2595*795d594fSAndroid Build Coastguard Worker   LocationSummary* const locations =
2596*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
2597*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2598*795d594fSAndroid Build Coastguard Worker 
2599*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
2600*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
2601*795d594fSAndroid Build Coastguard Worker }
2602*795d594fSAndroid Build Coastguard Worker 
CreateFPFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)2603*795d594fSAndroid Build Coastguard Worker static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2604*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
2605*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
2606*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(1)->GetType()));
2607*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
2608*795d594fSAndroid Build Coastguard Worker 
2609*795d594fSAndroid Build Coastguard Worker   LocationSummary* const locations =
2610*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
2611*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2612*795d594fSAndroid Build Coastguard Worker 
2613*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
2614*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
2615*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
2616*795d594fSAndroid Build Coastguard Worker }
2617*795d594fSAndroid Build Coastguard Worker 
CreateFPFPFPToFPLocations(ArenaAllocator * allocator,HInvoke * invoke)2618*795d594fSAndroid Build Coastguard Worker static void CreateFPFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2619*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(invoke->GetNumberOfArguments(), 3U);
2620*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
2621*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(1)->GetType()));
2622*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->InputAt(2)->GetType()));
2623*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
2624*795d594fSAndroid Build Coastguard Worker 
2625*795d594fSAndroid Build Coastguard Worker   LocationSummary* const locations =
2626*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2627*795d594fSAndroid Build Coastguard Worker 
2628*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
2629*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresFpuRegister());
2630*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresFpuRegister());
2631*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2632*795d594fSAndroid Build Coastguard Worker }
2633*795d594fSAndroid Build Coastguard Worker 
GenFPToFPCall(HInvoke * invoke,CodeGeneratorARM64 * codegen,QuickEntrypointEnum entry)2634*795d594fSAndroid Build Coastguard Worker static void GenFPToFPCall(HInvoke* invoke,
2635*795d594fSAndroid Build Coastguard Worker                           CodeGeneratorARM64* codegen,
2636*795d594fSAndroid Build Coastguard Worker                           QuickEntrypointEnum entry) {
2637*795d594fSAndroid Build Coastguard Worker   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2638*795d594fSAndroid Build Coastguard Worker }
2639*795d594fSAndroid Build Coastguard Worker 
VisitMathCos(HInvoke * invoke)2640*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathCos(HInvoke* invoke) {
2641*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2642*795d594fSAndroid Build Coastguard Worker }
2643*795d594fSAndroid Build Coastguard Worker 
VisitMathCos(HInvoke * invoke)2644*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathCos(HInvoke* invoke) {
2645*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCos);
2646*795d594fSAndroid Build Coastguard Worker }
2647*795d594fSAndroid Build Coastguard Worker 
VisitMathSin(HInvoke * invoke)2648*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathSin(HInvoke* invoke) {
2649*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2650*795d594fSAndroid Build Coastguard Worker }
2651*795d594fSAndroid Build Coastguard Worker 
VisitMathSin(HInvoke * invoke)2652*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathSin(HInvoke* invoke) {
2653*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickSin);
2654*795d594fSAndroid Build Coastguard Worker }
2655*795d594fSAndroid Build Coastguard Worker 
VisitMathAcos(HInvoke * invoke)2656*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathAcos(HInvoke* invoke) {
2657*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2658*795d594fSAndroid Build Coastguard Worker }
2659*795d594fSAndroid Build Coastguard Worker 
VisitMathAcos(HInvoke * invoke)2660*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathAcos(HInvoke* invoke) {
2661*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAcos);
2662*795d594fSAndroid Build Coastguard Worker }
2663*795d594fSAndroid Build Coastguard Worker 
VisitMathAsin(HInvoke * invoke)2664*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathAsin(HInvoke* invoke) {
2665*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2666*795d594fSAndroid Build Coastguard Worker }
2667*795d594fSAndroid Build Coastguard Worker 
VisitMathAsin(HInvoke * invoke)2668*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathAsin(HInvoke* invoke) {
2669*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAsin);
2670*795d594fSAndroid Build Coastguard Worker }
2671*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan(HInvoke * invoke)2672*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathAtan(HInvoke* invoke) {
2673*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2674*795d594fSAndroid Build Coastguard Worker }
2675*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan(HInvoke * invoke)2676*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathAtan(HInvoke* invoke) {
2677*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAtan);
2678*795d594fSAndroid Build Coastguard Worker }
2679*795d594fSAndroid Build Coastguard Worker 
VisitMathCbrt(HInvoke * invoke)2680*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathCbrt(HInvoke* invoke) {
2681*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2682*795d594fSAndroid Build Coastguard Worker }
2683*795d594fSAndroid Build Coastguard Worker 
VisitMathCbrt(HInvoke * invoke)2684*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathCbrt(HInvoke* invoke) {
2685*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2686*795d594fSAndroid Build Coastguard Worker }
2687*795d594fSAndroid Build Coastguard Worker 
VisitMathCosh(HInvoke * invoke)2688*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathCosh(HInvoke* invoke) {
2689*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2690*795d594fSAndroid Build Coastguard Worker }
2691*795d594fSAndroid Build Coastguard Worker 
VisitMathCosh(HInvoke * invoke)2692*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathCosh(HInvoke* invoke) {
2693*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCosh);
2694*795d594fSAndroid Build Coastguard Worker }
2695*795d594fSAndroid Build Coastguard Worker 
VisitMathExp(HInvoke * invoke)2696*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathExp(HInvoke* invoke) {
2697*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2698*795d594fSAndroid Build Coastguard Worker }
2699*795d594fSAndroid Build Coastguard Worker 
VisitMathExp(HInvoke * invoke)2700*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathExp(HInvoke* invoke) {
2701*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickExp);
2702*795d594fSAndroid Build Coastguard Worker }
2703*795d594fSAndroid Build Coastguard Worker 
VisitMathExpm1(HInvoke * invoke)2704*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathExpm1(HInvoke* invoke) {
2705*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2706*795d594fSAndroid Build Coastguard Worker }
2707*795d594fSAndroid Build Coastguard Worker 
VisitMathExpm1(HInvoke * invoke)2708*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathExpm1(HInvoke* invoke) {
2709*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2710*795d594fSAndroid Build Coastguard Worker }
2711*795d594fSAndroid Build Coastguard Worker 
VisitMathLog(HInvoke * invoke)2712*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathLog(HInvoke* invoke) {
2713*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2714*795d594fSAndroid Build Coastguard Worker }
2715*795d594fSAndroid Build Coastguard Worker 
VisitMathLog(HInvoke * invoke)2716*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathLog(HInvoke* invoke) {
2717*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickLog);
2718*795d594fSAndroid Build Coastguard Worker }
2719*795d594fSAndroid Build Coastguard Worker 
VisitMathLog10(HInvoke * invoke)2720*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathLog10(HInvoke* invoke) {
2721*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2722*795d594fSAndroid Build Coastguard Worker }
2723*795d594fSAndroid Build Coastguard Worker 
VisitMathLog10(HInvoke * invoke)2724*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathLog10(HInvoke* invoke) {
2725*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickLog10);
2726*795d594fSAndroid Build Coastguard Worker }
2727*795d594fSAndroid Build Coastguard Worker 
VisitMathSinh(HInvoke * invoke)2728*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathSinh(HInvoke* invoke) {
2729*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2730*795d594fSAndroid Build Coastguard Worker }
2731*795d594fSAndroid Build Coastguard Worker 
VisitMathSinh(HInvoke * invoke)2732*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathSinh(HInvoke* invoke) {
2733*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickSinh);
2734*795d594fSAndroid Build Coastguard Worker }
2735*795d594fSAndroid Build Coastguard Worker 
VisitMathTan(HInvoke * invoke)2736*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathTan(HInvoke* invoke) {
2737*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2738*795d594fSAndroid Build Coastguard Worker }
2739*795d594fSAndroid Build Coastguard Worker 
VisitMathTan(HInvoke * invoke)2740*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathTan(HInvoke* invoke) {
2741*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickTan);
2742*795d594fSAndroid Build Coastguard Worker }
2743*795d594fSAndroid Build Coastguard Worker 
VisitMathTanh(HInvoke * invoke)2744*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathTanh(HInvoke* invoke) {
2745*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
2746*795d594fSAndroid Build Coastguard Worker }
2747*795d594fSAndroid Build Coastguard Worker 
VisitMathTanh(HInvoke * invoke)2748*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathTanh(HInvoke* invoke) {
2749*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickTanh);
2750*795d594fSAndroid Build Coastguard Worker }
2751*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan2(HInvoke * invoke)2752*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathAtan2(HInvoke* invoke) {
2753*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
2754*795d594fSAndroid Build Coastguard Worker }
2755*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan2(HInvoke * invoke)2756*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathAtan2(HInvoke* invoke) {
2757*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAtan2);
2758*795d594fSAndroid Build Coastguard Worker }
2759*795d594fSAndroid Build Coastguard Worker 
VisitMathPow(HInvoke * invoke)2760*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathPow(HInvoke* invoke) {
2761*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
2762*795d594fSAndroid Build Coastguard Worker }
2763*795d594fSAndroid Build Coastguard Worker 
VisitMathPow(HInvoke * invoke)2764*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathPow(HInvoke* invoke) {
2765*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickPow);
2766*795d594fSAndroid Build Coastguard Worker }
2767*795d594fSAndroid Build Coastguard Worker 
VisitMathHypot(HInvoke * invoke)2768*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathHypot(HInvoke* invoke) {
2769*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
2770*795d594fSAndroid Build Coastguard Worker }
2771*795d594fSAndroid Build Coastguard Worker 
VisitMathHypot(HInvoke * invoke)2772*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathHypot(HInvoke* invoke) {
2773*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickHypot);
2774*795d594fSAndroid Build Coastguard Worker }
2775*795d594fSAndroid Build Coastguard Worker 
VisitMathNextAfter(HInvoke * invoke)2776*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathNextAfter(HInvoke* invoke) {
2777*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
2778*795d594fSAndroid Build Coastguard Worker }
2779*795d594fSAndroid Build Coastguard Worker 
VisitMathNextAfter(HInvoke * invoke)2780*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathNextAfter(HInvoke* invoke) {
2781*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
2782*795d594fSAndroid Build Coastguard Worker }
2783*795d594fSAndroid Build Coastguard Worker 
VisitStringGetCharsNoCheck(HInvoke * invoke)2784*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2785*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2786*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2787*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2788*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
2789*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
2790*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
2791*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(4, Location::RequiresRegister());
2792*795d594fSAndroid Build Coastguard Worker 
2793*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(3);
2794*795d594fSAndroid Build Coastguard Worker }
2795*795d594fSAndroid Build Coastguard Worker 
VisitStringGetCharsNoCheck(HInvoke * invoke)2796*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2797*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
2798*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2799*795d594fSAndroid Build Coastguard Worker 
2800*795d594fSAndroid Build Coastguard Worker   // Check assumption that sizeof(Char) is 2 (used in scaling below).
2801*795d594fSAndroid Build Coastguard Worker   const size_t char_size = DataType::Size(DataType::Type::kUint16);
2802*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(char_size, 2u);
2803*795d594fSAndroid Build Coastguard Worker 
2804*795d594fSAndroid Build Coastguard Worker   // Location of data in char array buffer.
2805*795d594fSAndroid Build Coastguard Worker   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2806*795d594fSAndroid Build Coastguard Worker 
2807*795d594fSAndroid Build Coastguard Worker   // Location of char array data in string.
2808*795d594fSAndroid Build Coastguard Worker   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
2809*795d594fSAndroid Build Coastguard Worker 
2810*795d594fSAndroid Build Coastguard Worker   // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin);
2811*795d594fSAndroid Build Coastguard Worker   // Since getChars() calls getCharsNoCheck() - we use registers rather than constants.
2812*795d594fSAndroid Build Coastguard Worker   Register srcObj = XRegisterFrom(locations->InAt(0));
2813*795d594fSAndroid Build Coastguard Worker   Register srcBegin = XRegisterFrom(locations->InAt(1));
2814*795d594fSAndroid Build Coastguard Worker   Register srcEnd = XRegisterFrom(locations->InAt(2));
2815*795d594fSAndroid Build Coastguard Worker   Register dstObj = XRegisterFrom(locations->InAt(3));
2816*795d594fSAndroid Build Coastguard Worker   Register dstBegin = XRegisterFrom(locations->InAt(4));
2817*795d594fSAndroid Build Coastguard Worker 
2818*795d594fSAndroid Build Coastguard Worker   Register src_ptr = XRegisterFrom(locations->GetTemp(0));
2819*795d594fSAndroid Build Coastguard Worker   Register num_chr = XRegisterFrom(locations->GetTemp(1));
2820*795d594fSAndroid Build Coastguard Worker   Register tmp1 = XRegisterFrom(locations->GetTemp(2));
2821*795d594fSAndroid Build Coastguard Worker 
2822*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
2823*795d594fSAndroid Build Coastguard Worker   Register dst_ptr = temps.AcquireX();
2824*795d594fSAndroid Build Coastguard Worker   Register tmp2 = temps.AcquireX();
2825*795d594fSAndroid Build Coastguard Worker 
2826*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label done;
2827*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label compressed_string_vector_loop;
2828*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label compressed_string_remainder;
2829*795d594fSAndroid Build Coastguard Worker   __ Sub(num_chr, srcEnd, srcBegin);
2830*795d594fSAndroid Build Coastguard Worker   // Early out for valid zero-length retrievals.
2831*795d594fSAndroid Build Coastguard Worker   __ Cbz(num_chr, &done);
2832*795d594fSAndroid Build Coastguard Worker 
2833*795d594fSAndroid Build Coastguard Worker   // dst address start to copy to.
2834*795d594fSAndroid Build Coastguard Worker   __ Add(dst_ptr, dstObj, Operand(data_offset));
2835*795d594fSAndroid Build Coastguard Worker   __ Add(dst_ptr, dst_ptr, Operand(dstBegin, LSL, 1));
2836*795d594fSAndroid Build Coastguard Worker 
2837*795d594fSAndroid Build Coastguard Worker   // src address to copy from.
2838*795d594fSAndroid Build Coastguard Worker   __ Add(src_ptr, srcObj, Operand(value_offset));
2839*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label compressed_string_preloop;
2840*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2841*795d594fSAndroid Build Coastguard Worker     // Location of count in string.
2842*795d594fSAndroid Build Coastguard Worker     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2843*795d594fSAndroid Build Coastguard Worker     // String's length.
2844*795d594fSAndroid Build Coastguard Worker     __ Ldr(tmp2, MemOperand(srcObj, count_offset));
2845*795d594fSAndroid Build Coastguard Worker     __ Tbz(tmp2, 0, &compressed_string_preloop);
2846*795d594fSAndroid Build Coastguard Worker   }
2847*795d594fSAndroid Build Coastguard Worker   __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1));
2848*795d594fSAndroid Build Coastguard Worker 
2849*795d594fSAndroid Build Coastguard Worker   // Do the copy.
2850*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop;
2851*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label remainder;
2852*795d594fSAndroid Build Coastguard Worker 
2853*795d594fSAndroid Build Coastguard Worker   // Save repairing the value of num_chr on the < 8 character path.
2854*795d594fSAndroid Build Coastguard Worker   __ Subs(tmp1, num_chr, 8);
2855*795d594fSAndroid Build Coastguard Worker   __ B(lt, &remainder);
2856*795d594fSAndroid Build Coastguard Worker 
2857*795d594fSAndroid Build Coastguard Worker   // Keep the result of the earlier subs, we are going to fetch at least 8 characters.
2858*795d594fSAndroid Build Coastguard Worker   __ Mov(num_chr, tmp1);
2859*795d594fSAndroid Build Coastguard Worker 
2860*795d594fSAndroid Build Coastguard Worker   // Main loop used for longer fetches loads and stores 8x16-bit characters at a time.
2861*795d594fSAndroid Build Coastguard Worker   // (Unaligned addresses are acceptable here and not worth inlining extra code to rectify.)
2862*795d594fSAndroid Build Coastguard Worker   __ Bind(&loop);
2863*795d594fSAndroid Build Coastguard Worker   __ Ldp(tmp1, tmp2, MemOperand(src_ptr, char_size * 8, PostIndex));
2864*795d594fSAndroid Build Coastguard Worker   __ Subs(num_chr, num_chr, 8);
2865*795d594fSAndroid Build Coastguard Worker   __ Stp(tmp1, tmp2, MemOperand(dst_ptr, char_size * 8, PostIndex));
2866*795d594fSAndroid Build Coastguard Worker   __ B(ge, &loop);
2867*795d594fSAndroid Build Coastguard Worker 
2868*795d594fSAndroid Build Coastguard Worker   __ Adds(num_chr, num_chr, 8);
2869*795d594fSAndroid Build Coastguard Worker   __ B(eq, &done);
2870*795d594fSAndroid Build Coastguard Worker 
2871*795d594fSAndroid Build Coastguard Worker   // Main loop for < 8 character case and remainder handling. Loads and stores one
2872*795d594fSAndroid Build Coastguard Worker   // 16-bit Java character at a time.
2873*795d594fSAndroid Build Coastguard Worker   __ Bind(&remainder);
2874*795d594fSAndroid Build Coastguard Worker   __ Ldrh(tmp1, MemOperand(src_ptr, char_size, PostIndex));
2875*795d594fSAndroid Build Coastguard Worker   __ Subs(num_chr, num_chr, 1);
2876*795d594fSAndroid Build Coastguard Worker   __ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
2877*795d594fSAndroid Build Coastguard Worker   __ B(gt, &remainder);
2878*795d594fSAndroid Build Coastguard Worker   __ B(&done);
2879*795d594fSAndroid Build Coastguard Worker 
2880*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
2881*795d594fSAndroid Build Coastguard Worker     // For compressed strings, acquire a SIMD temporary register.
2882*795d594fSAndroid Build Coastguard Worker     VRegister vtmp1 = temps.AcquireVRegisterOfSize(kQRegSize);
2883*795d594fSAndroid Build Coastguard Worker     const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
2884*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(c_char_size, 1u);
2885*795d594fSAndroid Build Coastguard Worker     __ Bind(&compressed_string_preloop);
2886*795d594fSAndroid Build Coastguard Worker     __ Add(src_ptr, src_ptr, Operand(srcBegin));
2887*795d594fSAndroid Build Coastguard Worker 
2888*795d594fSAndroid Build Coastguard Worker     // Save repairing the value of num_chr on the < 8 character path.
2889*795d594fSAndroid Build Coastguard Worker     __ Subs(tmp1, num_chr, 8);
2890*795d594fSAndroid Build Coastguard Worker     __ B(lt, &compressed_string_remainder);
2891*795d594fSAndroid Build Coastguard Worker 
2892*795d594fSAndroid Build Coastguard Worker     // Keep the result of the earlier subs, we are going to fetch at least 8 characters.
2893*795d594fSAndroid Build Coastguard Worker     __ Mov(num_chr, tmp1);
2894*795d594fSAndroid Build Coastguard Worker 
2895*795d594fSAndroid Build Coastguard Worker     // Main loop for compressed src, copying 8 characters (8-bit) to (16-bit) at a time.
2896*795d594fSAndroid Build Coastguard Worker     // Uses SIMD instructions.
2897*795d594fSAndroid Build Coastguard Worker     __ Bind(&compressed_string_vector_loop);
2898*795d594fSAndroid Build Coastguard Worker     __ Ld1(vtmp1.V8B(), MemOperand(src_ptr, c_char_size * 8, PostIndex));
2899*795d594fSAndroid Build Coastguard Worker     __ Subs(num_chr, num_chr, 8);
2900*795d594fSAndroid Build Coastguard Worker     __ Uxtl(vtmp1.V8H(), vtmp1.V8B());
2901*795d594fSAndroid Build Coastguard Worker     __ St1(vtmp1.V8H(), MemOperand(dst_ptr, char_size * 8, PostIndex));
2902*795d594fSAndroid Build Coastguard Worker     __ B(ge, &compressed_string_vector_loop);
2903*795d594fSAndroid Build Coastguard Worker 
2904*795d594fSAndroid Build Coastguard Worker     __ Adds(num_chr, num_chr, 8);
2905*795d594fSAndroid Build Coastguard Worker     __ B(eq, &done);
2906*795d594fSAndroid Build Coastguard Worker 
2907*795d594fSAndroid Build Coastguard Worker     // Loop for < 8 character case and remainder handling with a compressed src.
2908*795d594fSAndroid Build Coastguard Worker     // Copies 1 character (8-bit) to (16-bit) at a time.
2909*795d594fSAndroid Build Coastguard Worker     __ Bind(&compressed_string_remainder);
2910*795d594fSAndroid Build Coastguard Worker     __ Ldrb(tmp1, MemOperand(src_ptr, c_char_size, PostIndex));
2911*795d594fSAndroid Build Coastguard Worker     __ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
2912*795d594fSAndroid Build Coastguard Worker     __ Subs(num_chr, num_chr, Operand(1));
2913*795d594fSAndroid Build Coastguard Worker     __ B(gt, &compressed_string_remainder);
2914*795d594fSAndroid Build Coastguard Worker   }
2915*795d594fSAndroid Build Coastguard Worker 
2916*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
2917*795d594fSAndroid Build Coastguard Worker }
2918*795d594fSAndroid Build Coastguard Worker 
2919*795d594fSAndroid Build Coastguard Worker // This value is greater than ARRAYCOPY_SHORT_CHAR_ARRAY_THRESHOLD in libcore,
2920*795d594fSAndroid Build Coastguard Worker // so if we choose to jump to the slow path we will end up in the native implementation.
2921*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kSystemArrayCopyCharThreshold = 192;
2922*795d594fSAndroid Build Coastguard Worker 
LocationForSystemArrayCopyInput(HInstruction * input)2923*795d594fSAndroid Build Coastguard Worker static Location LocationForSystemArrayCopyInput(HInstruction* input) {
2924*795d594fSAndroid Build Coastguard Worker   HIntConstant* const_input = input->AsIntConstantOrNull();
2925*795d594fSAndroid Build Coastguard Worker   if (const_input != nullptr && vixl::aarch64::Assembler::IsImmAddSub(const_input->GetValue())) {
2926*795d594fSAndroid Build Coastguard Worker     return Location::ConstantLocation(const_input);
2927*795d594fSAndroid Build Coastguard Worker   } else {
2928*795d594fSAndroid Build Coastguard Worker     return Location::RequiresRegister();
2929*795d594fSAndroid Build Coastguard Worker   }
2930*795d594fSAndroid Build Coastguard Worker }
2931*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyChar(HInvoke * invoke)2932*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2933*795d594fSAndroid Build Coastguard Worker   // Check to see if we have known failures that will cause us to have to bail out
2934*795d594fSAndroid Build Coastguard Worker   // to the runtime, and just generate the runtime call directly.
2935*795d594fSAndroid Build Coastguard Worker   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstantOrNull();
2936*795d594fSAndroid Build Coastguard Worker   HIntConstant* dst_pos = invoke->InputAt(3)->AsIntConstantOrNull();
2937*795d594fSAndroid Build Coastguard Worker 
2938*795d594fSAndroid Build Coastguard Worker   // The positions must be non-negative.
2939*795d594fSAndroid Build Coastguard Worker   if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2940*795d594fSAndroid Build Coastguard Worker       (dst_pos != nullptr && dst_pos->GetValue() < 0)) {
2941*795d594fSAndroid Build Coastguard Worker     // We will have to fail anyways.
2942*795d594fSAndroid Build Coastguard Worker     return;
2943*795d594fSAndroid Build Coastguard Worker   }
2944*795d594fSAndroid Build Coastguard Worker 
2945*795d594fSAndroid Build Coastguard Worker   // The length must be >= 0 and not so long that we would (currently) prefer libcore's
2946*795d594fSAndroid Build Coastguard Worker   // native implementation.
2947*795d594fSAndroid Build Coastguard Worker   HIntConstant* length = invoke->InputAt(4)->AsIntConstantOrNull();
2948*795d594fSAndroid Build Coastguard Worker   if (length != nullptr) {
2949*795d594fSAndroid Build Coastguard Worker     int32_t len = length->GetValue();
2950*795d594fSAndroid Build Coastguard Worker     if (len < 0 || len > kSystemArrayCopyCharThreshold) {
2951*795d594fSAndroid Build Coastguard Worker       // Just call as normal.
2952*795d594fSAndroid Build Coastguard Worker       return;
2953*795d594fSAndroid Build Coastguard Worker     }
2954*795d594fSAndroid Build Coastguard Worker   }
2955*795d594fSAndroid Build Coastguard Worker 
2956*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
2957*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2958*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
2959*795d594fSAndroid Build Coastguard Worker   // arraycopy(char[] src, int src_pos, char[] dst, int dst_pos, int length).
2960*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2961*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1)));
2962*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
2963*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3)));
2964*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4)));
2965*795d594fSAndroid Build Coastguard Worker 
2966*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(3);
2967*795d594fSAndroid Build Coastguard Worker }
2968*795d594fSAndroid Build Coastguard Worker 
CheckSystemArrayCopyPosition(MacroAssembler * masm,Register array,Location pos,Location length,SlowPathCodeARM64 * slow_path,Register temp,bool length_is_array_length,bool position_sign_checked)2969*795d594fSAndroid Build Coastguard Worker static void CheckSystemArrayCopyPosition(MacroAssembler* masm,
2970*795d594fSAndroid Build Coastguard Worker                                          Register array,
2971*795d594fSAndroid Build Coastguard Worker                                          Location pos,
2972*795d594fSAndroid Build Coastguard Worker                                          Location length,
2973*795d594fSAndroid Build Coastguard Worker                                          SlowPathCodeARM64* slow_path,
2974*795d594fSAndroid Build Coastguard Worker                                          Register temp,
2975*795d594fSAndroid Build Coastguard Worker                                          bool length_is_array_length,
2976*795d594fSAndroid Build Coastguard Worker                                          bool position_sign_checked) {
2977*795d594fSAndroid Build Coastguard Worker   const int32_t length_offset = mirror::Array::LengthOffset().Int32Value();
2978*795d594fSAndroid Build Coastguard Worker   if (pos.IsConstant()) {
2979*795d594fSAndroid Build Coastguard Worker     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
2980*795d594fSAndroid Build Coastguard Worker     if (pos_const == 0) {
2981*795d594fSAndroid Build Coastguard Worker       if (!length_is_array_length) {
2982*795d594fSAndroid Build Coastguard Worker         // Check that length(array) >= length.
2983*795d594fSAndroid Build Coastguard Worker         __ Ldr(temp, MemOperand(array, length_offset));
2984*795d594fSAndroid Build Coastguard Worker         __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32));
2985*795d594fSAndroid Build Coastguard Worker         __ B(slow_path->GetEntryLabel(), lt);
2986*795d594fSAndroid Build Coastguard Worker       }
2987*795d594fSAndroid Build Coastguard Worker     } else {
2988*795d594fSAndroid Build Coastguard Worker       // Calculate length(array) - pos.
2989*795d594fSAndroid Build Coastguard Worker       // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
2990*795d594fSAndroid Build Coastguard Worker       // as `int32_t`. If the result is negative, the B.LT below shall go to the slow path.
2991*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp, MemOperand(array, length_offset));
2992*795d594fSAndroid Build Coastguard Worker       __ Sub(temp, temp, pos_const);
2993*795d594fSAndroid Build Coastguard Worker 
2994*795d594fSAndroid Build Coastguard Worker       // Check that (length(array) - pos) >= length.
2995*795d594fSAndroid Build Coastguard Worker       __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32));
2996*795d594fSAndroid Build Coastguard Worker       __ B(slow_path->GetEntryLabel(), lt);
2997*795d594fSAndroid Build Coastguard Worker     }
2998*795d594fSAndroid Build Coastguard Worker   } else if (length_is_array_length) {
2999*795d594fSAndroid Build Coastguard Worker     // The only way the copy can succeed is if pos is zero.
3000*795d594fSAndroid Build Coastguard Worker     __ Cbnz(WRegisterFrom(pos), slow_path->GetEntryLabel());
3001*795d594fSAndroid Build Coastguard Worker   } else {
3002*795d594fSAndroid Build Coastguard Worker     // Check that pos >= 0.
3003*795d594fSAndroid Build Coastguard Worker     Register pos_reg = WRegisterFrom(pos);
3004*795d594fSAndroid Build Coastguard Worker     if (!position_sign_checked) {
3005*795d594fSAndroid Build Coastguard Worker       __ Tbnz(pos_reg, pos_reg.GetSizeInBits() - 1, slow_path->GetEntryLabel());
3006*795d594fSAndroid Build Coastguard Worker     }
3007*795d594fSAndroid Build Coastguard Worker 
3008*795d594fSAndroid Build Coastguard Worker     // Calculate length(array) - pos.
3009*795d594fSAndroid Build Coastguard Worker     // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
3010*795d594fSAndroid Build Coastguard Worker     // as `int32_t`. If the result is negative, the B.LT below shall go to the slow path.
3011*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, MemOperand(array, length_offset));
3012*795d594fSAndroid Build Coastguard Worker     __ Sub(temp, temp, pos_reg);
3013*795d594fSAndroid Build Coastguard Worker 
3014*795d594fSAndroid Build Coastguard Worker     // Check that (length(array) - pos) >= length.
3015*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32));
3016*795d594fSAndroid Build Coastguard Worker     __ B(slow_path->GetEntryLabel(), lt);
3017*795d594fSAndroid Build Coastguard Worker   }
3018*795d594fSAndroid Build Coastguard Worker }
3019*795d594fSAndroid Build Coastguard Worker 
GenArrayAddress(MacroAssembler * masm,Register dest,Register base,Location pos,DataType::Type type,int32_t data_offset)3020*795d594fSAndroid Build Coastguard Worker static void GenArrayAddress(MacroAssembler* masm,
3021*795d594fSAndroid Build Coastguard Worker                             Register dest,
3022*795d594fSAndroid Build Coastguard Worker                             Register base,
3023*795d594fSAndroid Build Coastguard Worker                             Location pos,
3024*795d594fSAndroid Build Coastguard Worker                             DataType::Type type,
3025*795d594fSAndroid Build Coastguard Worker                             int32_t data_offset) {
3026*795d594fSAndroid Build Coastguard Worker   if (pos.IsConstant()) {
3027*795d594fSAndroid Build Coastguard Worker     int32_t constant = pos.GetConstant()->AsIntConstant()->GetValue();
3028*795d594fSAndroid Build Coastguard Worker     __ Add(dest, base, DataType::Size(type) * constant + data_offset);
3029*795d594fSAndroid Build Coastguard Worker   } else {
3030*795d594fSAndroid Build Coastguard Worker     if (data_offset != 0) {
3031*795d594fSAndroid Build Coastguard Worker       __ Add(dest, base, data_offset);
3032*795d594fSAndroid Build Coastguard Worker       base = dest;
3033*795d594fSAndroid Build Coastguard Worker     }
3034*795d594fSAndroid Build Coastguard Worker     __ Add(dest, base, Operand(XRegisterFrom(pos), LSL, DataType::SizeShift(type)));
3035*795d594fSAndroid Build Coastguard Worker   }
3036*795d594fSAndroid Build Coastguard Worker }
3037*795d594fSAndroid Build Coastguard Worker 
3038*795d594fSAndroid Build Coastguard Worker // Compute base source address, base destination address, and end
3039*795d594fSAndroid Build Coastguard Worker // source address for System.arraycopy* intrinsics in `src_base`,
3040*795d594fSAndroid Build Coastguard Worker // `dst_base` and `src_end` respectively.
GenSystemArrayCopyAddresses(MacroAssembler * masm,DataType::Type type,Register src,Location src_pos,Register dst,Location dst_pos,Location copy_length,Register src_base,Register dst_base,Register src_end)3041*795d594fSAndroid Build Coastguard Worker static void GenSystemArrayCopyAddresses(MacroAssembler* masm,
3042*795d594fSAndroid Build Coastguard Worker                                         DataType::Type type,
3043*795d594fSAndroid Build Coastguard Worker                                         Register src,
3044*795d594fSAndroid Build Coastguard Worker                                         Location src_pos,
3045*795d594fSAndroid Build Coastguard Worker                                         Register dst,
3046*795d594fSAndroid Build Coastguard Worker                                         Location dst_pos,
3047*795d594fSAndroid Build Coastguard Worker                                         Location copy_length,
3048*795d594fSAndroid Build Coastguard Worker                                         Register src_base,
3049*795d594fSAndroid Build Coastguard Worker                                         Register dst_base,
3050*795d594fSAndroid Build Coastguard Worker                                         Register src_end) {
3051*795d594fSAndroid Build Coastguard Worker   // This routine is used by the SystemArrayCopy and the SystemArrayCopyChar intrinsics.
3052*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kReference || type == DataType::Type::kUint16)
3053*795d594fSAndroid Build Coastguard Worker       << "Unexpected element type: " << type;
3054*795d594fSAndroid Build Coastguard Worker   const int32_t element_size = DataType::Size(type);
3055*795d594fSAndroid Build Coastguard Worker   const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
3056*795d594fSAndroid Build Coastguard Worker 
3057*795d594fSAndroid Build Coastguard Worker   GenArrayAddress(masm, src_base, src, src_pos, type, data_offset);
3058*795d594fSAndroid Build Coastguard Worker   GenArrayAddress(masm, dst_base, dst, dst_pos, type, data_offset);
3059*795d594fSAndroid Build Coastguard Worker   if (src_end.IsValid()) {
3060*795d594fSAndroid Build Coastguard Worker     GenArrayAddress(masm, src_end, src_base, copy_length, type, /*data_offset=*/ 0);
3061*795d594fSAndroid Build Coastguard Worker   }
3062*795d594fSAndroid Build Coastguard Worker }
3063*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyChar(HInvoke * invoke)3064*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopyChar(HInvoke* invoke) {
3065*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3066*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3067*795d594fSAndroid Build Coastguard Worker   Register src = XRegisterFrom(locations->InAt(0));
3068*795d594fSAndroid Build Coastguard Worker   Location src_pos = locations->InAt(1);
3069*795d594fSAndroid Build Coastguard Worker   Register dst = XRegisterFrom(locations->InAt(2));
3070*795d594fSAndroid Build Coastguard Worker   Location dst_pos = locations->InAt(3);
3071*795d594fSAndroid Build Coastguard Worker   Location length = locations->InAt(4);
3072*795d594fSAndroid Build Coastguard Worker 
3073*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
3074*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
3075*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
3076*795d594fSAndroid Build Coastguard Worker 
3077*795d594fSAndroid Build Coastguard Worker   // If source and destination are the same, take the slow path. Overlapping copy regions must be
3078*795d594fSAndroid Build Coastguard Worker   // copied in reverse and we can't know in all cases if it's needed.
3079*795d594fSAndroid Build Coastguard Worker   __ Cmp(src, dst);
3080*795d594fSAndroid Build Coastguard Worker   __ B(slow_path->GetEntryLabel(), eq);
3081*795d594fSAndroid Build Coastguard Worker 
3082*795d594fSAndroid Build Coastguard Worker   // Bail out if the source is null.
3083*795d594fSAndroid Build Coastguard Worker   __ Cbz(src, slow_path->GetEntryLabel());
3084*795d594fSAndroid Build Coastguard Worker 
3085*795d594fSAndroid Build Coastguard Worker   // Bail out if the destination is null.
3086*795d594fSAndroid Build Coastguard Worker   __ Cbz(dst, slow_path->GetEntryLabel());
3087*795d594fSAndroid Build Coastguard Worker 
3088*795d594fSAndroid Build Coastguard Worker   if (!length.IsConstant()) {
3089*795d594fSAndroid Build Coastguard Worker     // Merge the following two comparisons into one:
3090*795d594fSAndroid Build Coastguard Worker     //   If the length is negative, bail out (delegate to libcore's native implementation).
3091*795d594fSAndroid Build Coastguard Worker     //   If the length > kSystemArrayCopyCharThreshold then (currently) prefer libcore's
3092*795d594fSAndroid Build Coastguard Worker     //   native implementation.
3093*795d594fSAndroid Build Coastguard Worker     __ Cmp(WRegisterFrom(length), kSystemArrayCopyCharThreshold);
3094*795d594fSAndroid Build Coastguard Worker     __ B(slow_path->GetEntryLabel(), hi);
3095*795d594fSAndroid Build Coastguard Worker   } else {
3096*795d594fSAndroid Build Coastguard Worker     // We have already checked in the LocationsBuilder for the constant case.
3097*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(length.GetConstant()->AsIntConstant()->GetValue(), 0);
3098*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(length.GetConstant()->AsIntConstant()->GetValue(), kSystemArrayCopyCharThreshold);
3099*795d594fSAndroid Build Coastguard Worker   }
3100*795d594fSAndroid Build Coastguard Worker 
3101*795d594fSAndroid Build Coastguard Worker   Register src_curr_addr = WRegisterFrom(locations->GetTemp(0));
3102*795d594fSAndroid Build Coastguard Worker   Register dst_curr_addr = WRegisterFrom(locations->GetTemp(1));
3103*795d594fSAndroid Build Coastguard Worker   Register src_stop_addr = WRegisterFrom(locations->GetTemp(2));
3104*795d594fSAndroid Build Coastguard Worker 
3105*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(masm,
3106*795d594fSAndroid Build Coastguard Worker                                src,
3107*795d594fSAndroid Build Coastguard Worker                                src_pos,
3108*795d594fSAndroid Build Coastguard Worker                                length,
3109*795d594fSAndroid Build Coastguard Worker                                slow_path,
3110*795d594fSAndroid Build Coastguard Worker                                src_curr_addr,
3111*795d594fSAndroid Build Coastguard Worker                                /*length_is_array_length=*/ false,
3112*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
3113*795d594fSAndroid Build Coastguard Worker 
3114*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(masm,
3115*795d594fSAndroid Build Coastguard Worker                                dst,
3116*795d594fSAndroid Build Coastguard Worker                                dst_pos,
3117*795d594fSAndroid Build Coastguard Worker                                length,
3118*795d594fSAndroid Build Coastguard Worker                                slow_path,
3119*795d594fSAndroid Build Coastguard Worker                                src_curr_addr,
3120*795d594fSAndroid Build Coastguard Worker                                /*length_is_array_length=*/ false,
3121*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
3122*795d594fSAndroid Build Coastguard Worker 
3123*795d594fSAndroid Build Coastguard Worker   src_curr_addr = src_curr_addr.X();
3124*795d594fSAndroid Build Coastguard Worker   dst_curr_addr = dst_curr_addr.X();
3125*795d594fSAndroid Build Coastguard Worker   src_stop_addr = src_stop_addr.X();
3126*795d594fSAndroid Build Coastguard Worker 
3127*795d594fSAndroid Build Coastguard Worker   GenSystemArrayCopyAddresses(masm,
3128*795d594fSAndroid Build Coastguard Worker                               DataType::Type::kUint16,
3129*795d594fSAndroid Build Coastguard Worker                               src,
3130*795d594fSAndroid Build Coastguard Worker                               src_pos,
3131*795d594fSAndroid Build Coastguard Worker                               dst,
3132*795d594fSAndroid Build Coastguard Worker                               dst_pos,
3133*795d594fSAndroid Build Coastguard Worker                               length,
3134*795d594fSAndroid Build Coastguard Worker                               src_curr_addr,
3135*795d594fSAndroid Build Coastguard Worker                               dst_curr_addr,
3136*795d594fSAndroid Build Coastguard Worker                               Register());
3137*795d594fSAndroid Build Coastguard Worker 
3138*795d594fSAndroid Build Coastguard Worker   // Iterate over the arrays and do a raw copy of the chars.
3139*795d594fSAndroid Build Coastguard Worker   const int32_t char_size = DataType::Size(DataType::Type::kUint16);
3140*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3141*795d594fSAndroid Build Coastguard Worker 
3142*795d594fSAndroid Build Coastguard Worker   // We split processing of the array in two parts: head and tail.
3143*795d594fSAndroid Build Coastguard Worker   // A first loop handles the head by copying a block of characters per
3144*795d594fSAndroid Build Coastguard Worker   // iteration (see: chars_per_block).
3145*795d594fSAndroid Build Coastguard Worker   // A second loop handles the tail by copying the remaining characters.
3146*795d594fSAndroid Build Coastguard Worker   // If the copy length is not constant, we copy them one-by-one.
3147*795d594fSAndroid Build Coastguard Worker   // If the copy length is constant, we optimize by always unrolling the tail
3148*795d594fSAndroid Build Coastguard Worker   // loop, and also unrolling the head loop when the copy length is small (see:
3149*795d594fSAndroid Build Coastguard Worker   // unroll_threshold).
3150*795d594fSAndroid Build Coastguard Worker   //
3151*795d594fSAndroid Build Coastguard Worker   // Both loops are inverted for better performance, meaning they are
3152*795d594fSAndroid Build Coastguard Worker   // implemented as conditional do-while loops.
3153*795d594fSAndroid Build Coastguard Worker   // Here, the loop condition is first checked to determine if there are
3154*795d594fSAndroid Build Coastguard Worker   // sufficient chars to run an iteration, then we enter the do-while: an
3155*795d594fSAndroid Build Coastguard Worker   // iteration is performed followed by a conditional branch only if another
3156*795d594fSAndroid Build Coastguard Worker   // iteration is necessary. As opposed to a standard while-loop, this inversion
3157*795d594fSAndroid Build Coastguard Worker   // can save some branching (e.g. we don't branch back to the initial condition
3158*795d594fSAndroid Build Coastguard Worker   // at the end of every iteration only to potentially immediately branch
3159*795d594fSAndroid Build Coastguard Worker   // again).
3160*795d594fSAndroid Build Coastguard Worker   //
3161*795d594fSAndroid Build Coastguard Worker   // A full block of chars is subtracted and added before and after the head
3162*795d594fSAndroid Build Coastguard Worker   // loop, respectively. This ensures that any remaining length after each
3163*795d594fSAndroid Build Coastguard Worker   // head loop iteration means there is a full block remaining, reducing the
3164*795d594fSAndroid Build Coastguard Worker   // number of conditional checks required on every iteration.
3165*795d594fSAndroid Build Coastguard Worker   constexpr int32_t chars_per_block = 4;
3166*795d594fSAndroid Build Coastguard Worker   constexpr int32_t unroll_threshold = 2 * chars_per_block;
3167*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop1, loop2, pre_loop2, done;
3168*795d594fSAndroid Build Coastguard Worker 
3169*795d594fSAndroid Build Coastguard Worker   Register length_tmp = src_stop_addr.W();
3170*795d594fSAndroid Build Coastguard Worker   Register tmp = temps.AcquireRegisterOfSize(char_size * chars_per_block * kBitsPerByte);
3171*795d594fSAndroid Build Coastguard Worker 
3172*795d594fSAndroid Build Coastguard Worker   auto emitHeadLoop = [&]() {
3173*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop1);
3174*795d594fSAndroid Build Coastguard Worker     __ Ldr(tmp, MemOperand(src_curr_addr, char_size * chars_per_block, PostIndex));
3175*795d594fSAndroid Build Coastguard Worker     __ Subs(length_tmp, length_tmp, chars_per_block);
3176*795d594fSAndroid Build Coastguard Worker     __ Str(tmp, MemOperand(dst_curr_addr, char_size * chars_per_block, PostIndex));
3177*795d594fSAndroid Build Coastguard Worker     __ B(&loop1, ge);
3178*795d594fSAndroid Build Coastguard Worker   };
3179*795d594fSAndroid Build Coastguard Worker 
3180*795d594fSAndroid Build Coastguard Worker   auto emitTailLoop = [&]() {
3181*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop2);
3182*795d594fSAndroid Build Coastguard Worker     __ Ldrh(tmp, MemOperand(src_curr_addr, char_size, PostIndex));
3183*795d594fSAndroid Build Coastguard Worker     __ Subs(length_tmp, length_tmp, 1);
3184*795d594fSAndroid Build Coastguard Worker     __ Strh(tmp, MemOperand(dst_curr_addr, char_size, PostIndex));
3185*795d594fSAndroid Build Coastguard Worker     __ B(&loop2, gt);
3186*795d594fSAndroid Build Coastguard Worker   };
3187*795d594fSAndroid Build Coastguard Worker 
3188*795d594fSAndroid Build Coastguard Worker   auto emitUnrolledTailLoop = [&](const int32_t tail_length) {
3189*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(tail_length, 4);
3190*795d594fSAndroid Build Coastguard Worker 
3191*795d594fSAndroid Build Coastguard Worker     // Don't use post-index addressing, and instead add a constant offset later.
3192*795d594fSAndroid Build Coastguard Worker     if ((tail_length & 2) != 0) {
3193*795d594fSAndroid Build Coastguard Worker       __ Ldr(tmp.W(), MemOperand(src_curr_addr));
3194*795d594fSAndroid Build Coastguard Worker       __ Str(tmp.W(), MemOperand(dst_curr_addr));
3195*795d594fSAndroid Build Coastguard Worker     }
3196*795d594fSAndroid Build Coastguard Worker     if ((tail_length & 1) != 0) {
3197*795d594fSAndroid Build Coastguard Worker       const int32_t offset = (tail_length & ~1) * char_size;
3198*795d594fSAndroid Build Coastguard Worker       __ Ldrh(tmp, MemOperand(src_curr_addr, offset));
3199*795d594fSAndroid Build Coastguard Worker       __ Strh(tmp, MemOperand(dst_curr_addr, offset));
3200*795d594fSAndroid Build Coastguard Worker     }
3201*795d594fSAndroid Build Coastguard Worker   };
3202*795d594fSAndroid Build Coastguard Worker 
3203*795d594fSAndroid Build Coastguard Worker   if (length.IsConstant()) {
3204*795d594fSAndroid Build Coastguard Worker     const int32_t constant_length = length.GetConstant()->AsIntConstant()->GetValue();
3205*795d594fSAndroid Build Coastguard Worker     if (constant_length >= unroll_threshold) {
3206*795d594fSAndroid Build Coastguard Worker       __ Mov(length_tmp, constant_length - chars_per_block);
3207*795d594fSAndroid Build Coastguard Worker       emitHeadLoop();
3208*795d594fSAndroid Build Coastguard Worker     } else {
3209*795d594fSAndroid Build Coastguard Worker       static_assert(unroll_threshold == 8, "The unroll_threshold must be 8.");
3210*795d594fSAndroid Build Coastguard Worker       // Fully unroll both the head and tail loops.
3211*795d594fSAndroid Build Coastguard Worker       if ((constant_length & 4) != 0) {
3212*795d594fSAndroid Build Coastguard Worker         __ Ldr(tmp, MemOperand(src_curr_addr, 4 * char_size, PostIndex));
3213*795d594fSAndroid Build Coastguard Worker         __ Str(tmp, MemOperand(dst_curr_addr, 4 * char_size, PostIndex));
3214*795d594fSAndroid Build Coastguard Worker       }
3215*795d594fSAndroid Build Coastguard Worker     }
3216*795d594fSAndroid Build Coastguard Worker     emitUnrolledTailLoop(constant_length % chars_per_block);
3217*795d594fSAndroid Build Coastguard Worker   } else {
3218*795d594fSAndroid Build Coastguard Worker     Register length_reg = WRegisterFrom(length);
3219*795d594fSAndroid Build Coastguard Worker     __ Subs(length_tmp, length_reg, chars_per_block);
3220*795d594fSAndroid Build Coastguard Worker     __ B(&pre_loop2, lt);
3221*795d594fSAndroid Build Coastguard Worker 
3222*795d594fSAndroid Build Coastguard Worker     emitHeadLoop();
3223*795d594fSAndroid Build Coastguard Worker 
3224*795d594fSAndroid Build Coastguard Worker     __ Bind(&pre_loop2);
3225*795d594fSAndroid Build Coastguard Worker     __ Adds(length_tmp, length_tmp, chars_per_block);
3226*795d594fSAndroid Build Coastguard Worker     __ B(&done, eq);
3227*795d594fSAndroid Build Coastguard Worker 
3228*795d594fSAndroid Build Coastguard Worker     emitTailLoop();
3229*795d594fSAndroid Build Coastguard Worker   }
3230*795d594fSAndroid Build Coastguard Worker 
3231*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
3232*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
3233*795d594fSAndroid Build Coastguard Worker }
3234*795d594fSAndroid Build Coastguard Worker 
3235*795d594fSAndroid Build Coastguard Worker // We choose to use the native implementation for longer copy lengths.
3236*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kSystemArrayCopyThreshold = 128;
3237*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopy(HInvoke * invoke)3238*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) {
3239*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
3240*795d594fSAndroid Build Coastguard Worker   // SystemArrayCopy intrinsic is the Baker-style read barriers.
3241*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitNonBakerReadBarrier()) {
3242*795d594fSAndroid Build Coastguard Worker     return;
3243*795d594fSAndroid Build Coastguard Worker   }
3244*795d594fSAndroid Build Coastguard Worker 
3245*795d594fSAndroid Build Coastguard Worker   constexpr size_t kInitialNumTemps = 2u;  // We need at least two temps.
3246*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = CodeGenerator::CreateSystemArrayCopyLocationSummary(
3247*795d594fSAndroid Build Coastguard Worker       invoke, kSystemArrayCopyThreshold, kInitialNumTemps);
3248*795d594fSAndroid Build Coastguard Worker   if (locations != nullptr) {
3249*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1)));
3250*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3)));
3251*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4)));
3252*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
3253*795d594fSAndroid Build Coastguard Worker       // Temporary register IP0, obtained from the VIXL scratch register
3254*795d594fSAndroid Build Coastguard Worker       // pool, cannot be used in ReadBarrierSystemArrayCopySlowPathARM64
3255*795d594fSAndroid Build Coastguard Worker       // (because that register is clobbered by ReadBarrierMarkRegX
3256*795d594fSAndroid Build Coastguard Worker       // entry points). It cannot be used in calls to
3257*795d594fSAndroid Build Coastguard Worker       // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier
3258*795d594fSAndroid Build Coastguard Worker       // either. For these reasons, get a third extra temporary register
3259*795d594fSAndroid Build Coastguard Worker       // from the register allocator.
3260*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
3261*795d594fSAndroid Build Coastguard Worker     } else {
3262*795d594fSAndroid Build Coastguard Worker       // Cases other than Baker read barriers: the third temporary will
3263*795d594fSAndroid Build Coastguard Worker       // be acquired from the VIXL scratch register pool.
3264*795d594fSAndroid Build Coastguard Worker     }
3265*795d594fSAndroid Build Coastguard Worker   }
3266*795d594fSAndroid Build Coastguard Worker }
3267*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopy(HInvoke * invoke)3268*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) {
3269*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
3270*795d594fSAndroid Build Coastguard Worker   // SystemArrayCopy intrinsic is the Baker-style read barriers.
3271*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
3272*795d594fSAndroid Build Coastguard Worker 
3273*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3274*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3275*795d594fSAndroid Build Coastguard Worker 
3276*795d594fSAndroid Build Coastguard Worker   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3277*795d594fSAndroid Build Coastguard Worker   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3278*795d594fSAndroid Build Coastguard Worker   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3279*795d594fSAndroid Build Coastguard Worker   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
3280*795d594fSAndroid Build Coastguard Worker   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
3281*795d594fSAndroid Build Coastguard Worker 
3282*795d594fSAndroid Build Coastguard Worker   Register src = XRegisterFrom(locations->InAt(0));
3283*795d594fSAndroid Build Coastguard Worker   Location src_pos = locations->InAt(1);
3284*795d594fSAndroid Build Coastguard Worker   Register dest = XRegisterFrom(locations->InAt(2));
3285*795d594fSAndroid Build Coastguard Worker   Location dest_pos = locations->InAt(3);
3286*795d594fSAndroid Build Coastguard Worker   Location length = locations->InAt(4);
3287*795d594fSAndroid Build Coastguard Worker   Register temp1 = WRegisterFrom(locations->GetTemp(0));
3288*795d594fSAndroid Build Coastguard Worker   Location temp1_loc = LocationFrom(temp1);
3289*795d594fSAndroid Build Coastguard Worker   Register temp2 = WRegisterFrom(locations->GetTemp(1));
3290*795d594fSAndroid Build Coastguard Worker   Location temp2_loc = LocationFrom(temp2);
3291*795d594fSAndroid Build Coastguard Worker 
3292*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* intrinsic_slow_path =
3293*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
3294*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(intrinsic_slow_path);
3295*795d594fSAndroid Build Coastguard Worker 
3296*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label conditions_on_positions_validated;
3297*795d594fSAndroid Build Coastguard Worker   SystemArrayCopyOptimizations optimizations(invoke);
3298*795d594fSAndroid Build Coastguard Worker 
3299*795d594fSAndroid Build Coastguard Worker   // If source and destination are the same, we go to slow path if we need to do forward copying.
3300*795d594fSAndroid Build Coastguard Worker   // We do not need to do this check if the source and destination positions are the same.
3301*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSourcePositionIsDestinationPosition()) {
3302*795d594fSAndroid Build Coastguard Worker     if (src_pos.IsConstant()) {
3303*795d594fSAndroid Build Coastguard Worker       int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
3304*795d594fSAndroid Build Coastguard Worker       if (dest_pos.IsConstant()) {
3305*795d594fSAndroid Build Coastguard Worker         int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
3306*795d594fSAndroid Build Coastguard Worker         if (optimizations.GetDestinationIsSource()) {
3307*795d594fSAndroid Build Coastguard Worker           // Checked when building locations.
3308*795d594fSAndroid Build Coastguard Worker           DCHECK_GE(src_pos_constant, dest_pos_constant);
3309*795d594fSAndroid Build Coastguard Worker         } else if (src_pos_constant < dest_pos_constant) {
3310*795d594fSAndroid Build Coastguard Worker           __ Cmp(src, dest);
3311*795d594fSAndroid Build Coastguard Worker           __ B(intrinsic_slow_path->GetEntryLabel(), eq);
3312*795d594fSAndroid Build Coastguard Worker         }
3313*795d594fSAndroid Build Coastguard Worker       } else {
3314*795d594fSAndroid Build Coastguard Worker         if (!optimizations.GetDestinationIsSource()) {
3315*795d594fSAndroid Build Coastguard Worker           __ Cmp(src, dest);
3316*795d594fSAndroid Build Coastguard Worker           __ B(&conditions_on_positions_validated, ne);
3317*795d594fSAndroid Build Coastguard Worker         }
3318*795d594fSAndroid Build Coastguard Worker         __ Cmp(WRegisterFrom(dest_pos), src_pos_constant);
3319*795d594fSAndroid Build Coastguard Worker         __ B(intrinsic_slow_path->GetEntryLabel(), gt);
3320*795d594fSAndroid Build Coastguard Worker       }
3321*795d594fSAndroid Build Coastguard Worker     } else {
3322*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetDestinationIsSource()) {
3323*795d594fSAndroid Build Coastguard Worker         __ Cmp(src, dest);
3324*795d594fSAndroid Build Coastguard Worker         __ B(&conditions_on_positions_validated, ne);
3325*795d594fSAndroid Build Coastguard Worker       }
3326*795d594fSAndroid Build Coastguard Worker       __ Cmp(RegisterFrom(src_pos, invoke->InputAt(1)->GetType()),
3327*795d594fSAndroid Build Coastguard Worker              OperandFrom(dest_pos, invoke->InputAt(3)->GetType()));
3328*795d594fSAndroid Build Coastguard Worker       __ B(intrinsic_slow_path->GetEntryLabel(), lt);
3329*795d594fSAndroid Build Coastguard Worker     }
3330*795d594fSAndroid Build Coastguard Worker   }
3331*795d594fSAndroid Build Coastguard Worker 
3332*795d594fSAndroid Build Coastguard Worker   __ Bind(&conditions_on_positions_validated);
3333*795d594fSAndroid Build Coastguard Worker 
3334*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSourceIsNotNull()) {
3335*795d594fSAndroid Build Coastguard Worker     // Bail out if the source is null.
3336*795d594fSAndroid Build Coastguard Worker     __ Cbz(src, intrinsic_slow_path->GetEntryLabel());
3337*795d594fSAndroid Build Coastguard Worker   }
3338*795d594fSAndroid Build Coastguard Worker 
3339*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
3340*795d594fSAndroid Build Coastguard Worker     // Bail out if the destination is null.
3341*795d594fSAndroid Build Coastguard Worker     __ Cbz(dest, intrinsic_slow_path->GetEntryLabel());
3342*795d594fSAndroid Build Coastguard Worker   }
3343*795d594fSAndroid Build Coastguard Worker 
3344*795d594fSAndroid Build Coastguard Worker   // We have already checked in the LocationsBuilder for the constant case.
3345*795d594fSAndroid Build Coastguard Worker   if (!length.IsConstant()) {
3346*795d594fSAndroid Build Coastguard Worker     // Merge the following two comparisons into one:
3347*795d594fSAndroid Build Coastguard Worker     //   If the length is negative, bail out (delegate to libcore's native implementation).
3348*795d594fSAndroid Build Coastguard Worker     //   If the length >= 128 then (currently) prefer native implementation.
3349*795d594fSAndroid Build Coastguard Worker     __ Cmp(WRegisterFrom(length), kSystemArrayCopyThreshold);
3350*795d594fSAndroid Build Coastguard Worker     __ B(intrinsic_slow_path->GetEntryLabel(), hs);
3351*795d594fSAndroid Build Coastguard Worker   }
3352*795d594fSAndroid Build Coastguard Worker   // Validity checks: source.
3353*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(masm,
3354*795d594fSAndroid Build Coastguard Worker                                src,
3355*795d594fSAndroid Build Coastguard Worker                                src_pos,
3356*795d594fSAndroid Build Coastguard Worker                                length,
3357*795d594fSAndroid Build Coastguard Worker                                intrinsic_slow_path,
3358*795d594fSAndroid Build Coastguard Worker                                temp1,
3359*795d594fSAndroid Build Coastguard Worker                                optimizations.GetCountIsSourceLength(),
3360*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
3361*795d594fSAndroid Build Coastguard Worker 
3362*795d594fSAndroid Build Coastguard Worker   // Validity checks: dest.
3363*795d594fSAndroid Build Coastguard Worker   bool dest_position_sign_checked = optimizations.GetSourcePositionIsDestinationPosition();
3364*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(masm,
3365*795d594fSAndroid Build Coastguard Worker                                dest,
3366*795d594fSAndroid Build Coastguard Worker                                dest_pos,
3367*795d594fSAndroid Build Coastguard Worker                                length,
3368*795d594fSAndroid Build Coastguard Worker                                intrinsic_slow_path,
3369*795d594fSAndroid Build Coastguard Worker                                temp1,
3370*795d594fSAndroid Build Coastguard Worker                                optimizations.GetCountIsDestinationLength(),
3371*795d594fSAndroid Build Coastguard Worker                                dest_position_sign_checked);
3372*795d594fSAndroid Build Coastguard Worker 
3373*795d594fSAndroid Build Coastguard Worker   auto check_non_primitive_array_class = [&](Register klass, Register temp) {
3374*795d594fSAndroid Build Coastguard Worker     // No read barrier is needed for reading a chain of constant references for comparing
3375*795d594fSAndroid Build Coastguard Worker     // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
3376*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp = klass->component_type_
3377*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, HeapOperand(klass, component_offset));
3378*795d594fSAndroid Build Coastguard Worker     codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp);
3379*795d594fSAndroid Build Coastguard Worker     // Check that the component type is not null.
3380*795d594fSAndroid Build Coastguard Worker     __ Cbz(temp, intrinsic_slow_path->GetEntryLabel());
3381*795d594fSAndroid Build Coastguard Worker     // Check that the component type is not a primitive.
3382*795d594fSAndroid Build Coastguard Worker     // /* uint16_t */ temp = static_cast<uint16>(klass->primitive_type_);
3383*795d594fSAndroid Build Coastguard Worker     __ Ldrh(temp, HeapOperand(temp, primitive_offset));
3384*795d594fSAndroid Build Coastguard Worker     static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
3385*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp, intrinsic_slow_path->GetEntryLabel());
3386*795d594fSAndroid Build Coastguard Worker   };
3387*795d594fSAndroid Build Coastguard Worker 
3388*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetDoesNotNeedTypeCheck()) {
3389*795d594fSAndroid Build Coastguard Worker     // Check whether all elements of the source array are assignable to the component
3390*795d594fSAndroid Build Coastguard Worker     // type of the destination array. We do two checks: the classes are the same,
3391*795d594fSAndroid Build Coastguard Worker     // or the destination is Object[]. If none of these checks succeed, we go to the
3392*795d594fSAndroid Build Coastguard Worker     // slow path.
3393*795d594fSAndroid Build Coastguard Worker 
3394*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
3395*795d594fSAndroid Build Coastguard Worker       Location temp3_loc = locations->GetTemp(2);
3396*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = dest->klass_
3397*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
3398*795d594fSAndroid Build Coastguard Worker                                                       temp1_loc,
3399*795d594fSAndroid Build Coastguard Worker                                                       dest.W(),
3400*795d594fSAndroid Build Coastguard Worker                                                       class_offset,
3401*795d594fSAndroid Build Coastguard Worker                                                       temp3_loc,
3402*795d594fSAndroid Build Coastguard Worker                                                       /* needs_null_check= */ false,
3403*795d594fSAndroid Build Coastguard Worker                                                       /* use_load_acquire= */ false);
3404*795d594fSAndroid Build Coastguard Worker       // Register `temp1` is not trashed by the read barrier emitted
3405*795d594fSAndroid Build Coastguard Worker       // by GenerateFieldLoadWithBakerReadBarrier below, as that
3406*795d594fSAndroid Build Coastguard Worker       // method produces a call to a ReadBarrierMarkRegX entry point,
3407*795d594fSAndroid Build Coastguard Worker       // which saves all potentially live registers, including
3408*795d594fSAndroid Build Coastguard Worker       // temporaries such a `temp1`.
3409*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp2 = src->klass_
3410*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
3411*795d594fSAndroid Build Coastguard Worker                                                       temp2_loc,
3412*795d594fSAndroid Build Coastguard Worker                                                       src.W(),
3413*795d594fSAndroid Build Coastguard Worker                                                       class_offset,
3414*795d594fSAndroid Build Coastguard Worker                                                       temp3_loc,
3415*795d594fSAndroid Build Coastguard Worker                                                       /* needs_null_check= */ false,
3416*795d594fSAndroid Build Coastguard Worker                                                       /* use_load_acquire= */ false);
3417*795d594fSAndroid Build Coastguard Worker     } else {
3418*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = dest->klass_
3419*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp1, MemOperand(dest, class_offset));
3420*795d594fSAndroid Build Coastguard Worker       codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1);
3421*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp2 = src->klass_
3422*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp2, MemOperand(src, class_offset));
3423*795d594fSAndroid Build Coastguard Worker       codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2);
3424*795d594fSAndroid Build Coastguard Worker     }
3425*795d594fSAndroid Build Coastguard Worker 
3426*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp1, temp2);
3427*795d594fSAndroid Build Coastguard Worker     if (optimizations.GetDestinationIsTypedObjectArray()) {
3428*795d594fSAndroid Build Coastguard Worker       DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
3429*795d594fSAndroid Build Coastguard Worker       vixl::aarch64::Label do_copy;
3430*795d594fSAndroid Build Coastguard Worker       // For class match, we can skip the source type check regardless of the optimization flag.
3431*795d594fSAndroid Build Coastguard Worker       __ B(&do_copy, eq);
3432*795d594fSAndroid Build Coastguard Worker       // No read barrier is needed for reading a chain of constant references
3433*795d594fSAndroid Build Coastguard Worker       // for comparing with null, see `ReadBarrierOption`.
3434*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = temp1->component_type_
3435*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp1, HeapOperand(temp1, component_offset));
3436*795d594fSAndroid Build Coastguard Worker       codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1);
3437*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = temp1->super_class_
3438*795d594fSAndroid Build Coastguard Worker       __ Ldr(temp1, HeapOperand(temp1, super_offset));
3439*795d594fSAndroid Build Coastguard Worker       // No need to unpoison the result, we're comparing against null.
3440*795d594fSAndroid Build Coastguard Worker       __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel());
3441*795d594fSAndroid Build Coastguard Worker       // Bail out if the source is not a non primitive array.
3442*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetSourceIsNonPrimitiveArray()) {
3443*795d594fSAndroid Build Coastguard Worker         check_non_primitive_array_class(temp2, temp2);
3444*795d594fSAndroid Build Coastguard Worker       }
3445*795d594fSAndroid Build Coastguard Worker       __ Bind(&do_copy);
3446*795d594fSAndroid Build Coastguard Worker     } else {
3447*795d594fSAndroid Build Coastguard Worker       DCHECK(!optimizations.GetDestinationIsTypedObjectArray());
3448*795d594fSAndroid Build Coastguard Worker       // For class match, we can skip the array type check completely if at least one of source
3449*795d594fSAndroid Build Coastguard Worker       // and destination is known to be a non primitive array, otherwise one check is enough.
3450*795d594fSAndroid Build Coastguard Worker       __ B(intrinsic_slow_path->GetEntryLabel(), ne);
3451*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetDestinationIsNonPrimitiveArray() &&
3452*795d594fSAndroid Build Coastguard Worker           !optimizations.GetSourceIsNonPrimitiveArray()) {
3453*795d594fSAndroid Build Coastguard Worker         check_non_primitive_array_class(temp2, temp2);
3454*795d594fSAndroid Build Coastguard Worker       }
3455*795d594fSAndroid Build Coastguard Worker     }
3456*795d594fSAndroid Build Coastguard Worker   } else if (!optimizations.GetSourceIsNonPrimitiveArray()) {
3457*795d594fSAndroid Build Coastguard Worker     DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
3458*795d594fSAndroid Build Coastguard Worker     // Bail out if the source is not a non primitive array.
3459*795d594fSAndroid Build Coastguard Worker     // No read barrier is needed for reading a chain of constant references for comparing
3460*795d594fSAndroid Build Coastguard Worker     // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
3461*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp2 = src->klass_
3462*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp2, MemOperand(src, class_offset));
3463*795d594fSAndroid Build Coastguard Worker     codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2);
3464*795d594fSAndroid Build Coastguard Worker     check_non_primitive_array_class(temp2, temp2);
3465*795d594fSAndroid Build Coastguard Worker   }
3466*795d594fSAndroid Build Coastguard Worker 
3467*795d594fSAndroid Build Coastguard Worker   if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) {
3468*795d594fSAndroid Build Coastguard Worker     // Null constant length: not need to emit the loop code at all.
3469*795d594fSAndroid Build Coastguard Worker   } else {
3470*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label skip_copy_and_write_barrier;
3471*795d594fSAndroid Build Coastguard Worker     if (length.IsRegister()) {
3472*795d594fSAndroid Build Coastguard Worker       // Don't enter the copy loop if the length is null.
3473*795d594fSAndroid Build Coastguard Worker       __ Cbz(WRegisterFrom(length), &skip_copy_and_write_barrier);
3474*795d594fSAndroid Build Coastguard Worker     }
3475*795d594fSAndroid Build Coastguard Worker 
3476*795d594fSAndroid Build Coastguard Worker     {
3477*795d594fSAndroid Build Coastguard Worker       // We use a block to end the scratch scope before the write barrier, thus
3478*795d594fSAndroid Build Coastguard Worker       // freeing the temporary registers so they can be used in `MarkGCCard`.
3479*795d594fSAndroid Build Coastguard Worker       UseScratchRegisterScope temps(masm);
3480*795d594fSAndroid Build Coastguard Worker       bool emit_rb = codegen_->EmitBakerReadBarrier();
3481*795d594fSAndroid Build Coastguard Worker       Register temp3;
3482*795d594fSAndroid Build Coastguard Worker       Register tmp;
3483*795d594fSAndroid Build Coastguard Worker       if (emit_rb) {
3484*795d594fSAndroid Build Coastguard Worker         temp3 = WRegisterFrom(locations->GetTemp(2));
3485*795d594fSAndroid Build Coastguard Worker         // Make sure `tmp` is not IP0, as it is clobbered by ReadBarrierMarkRegX entry points
3486*795d594fSAndroid Build Coastguard Worker         // in ReadBarrierSystemArrayCopySlowPathARM64. Explicitly allocate the register IP1.
3487*795d594fSAndroid Build Coastguard Worker         DCHECK(temps.IsAvailable(ip1));
3488*795d594fSAndroid Build Coastguard Worker         temps.Exclude(ip1);
3489*795d594fSAndroid Build Coastguard Worker         tmp = ip1.W();
3490*795d594fSAndroid Build Coastguard Worker       } else {
3491*795d594fSAndroid Build Coastguard Worker         temp3 = temps.AcquireW();
3492*795d594fSAndroid Build Coastguard Worker         tmp = temps.AcquireW();
3493*795d594fSAndroid Build Coastguard Worker       }
3494*795d594fSAndroid Build Coastguard Worker 
3495*795d594fSAndroid Build Coastguard Worker       Register src_curr_addr = temp1.X();
3496*795d594fSAndroid Build Coastguard Worker       Register dst_curr_addr = temp2.X();
3497*795d594fSAndroid Build Coastguard Worker       Register src_stop_addr = temp3.X();
3498*795d594fSAndroid Build Coastguard Worker       const DataType::Type type = DataType::Type::kReference;
3499*795d594fSAndroid Build Coastguard Worker       const int32_t element_size = DataType::Size(type);
3500*795d594fSAndroid Build Coastguard Worker 
3501*795d594fSAndroid Build Coastguard Worker       SlowPathCodeARM64* read_barrier_slow_path = nullptr;
3502*795d594fSAndroid Build Coastguard Worker       if (emit_rb) {
3503*795d594fSAndroid Build Coastguard Worker         // TODO: Also convert this intrinsic to the IsGcMarking strategy?
3504*795d594fSAndroid Build Coastguard Worker 
3505*795d594fSAndroid Build Coastguard Worker         // SystemArrayCopy implementation for Baker read barriers (see
3506*795d594fSAndroid Build Coastguard Worker         // also CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier):
3507*795d594fSAndroid Build Coastguard Worker         //
3508*795d594fSAndroid Build Coastguard Worker         //   uint32_t rb_state = Lockword(src->monitor_).ReadBarrierState();
3509*795d594fSAndroid Build Coastguard Worker         //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
3510*795d594fSAndroid Build Coastguard Worker         //   bool is_gray = (rb_state == ReadBarrier::GrayState());
3511*795d594fSAndroid Build Coastguard Worker         //   if (is_gray) {
3512*795d594fSAndroid Build Coastguard Worker         //     // Slow-path copy.
3513*795d594fSAndroid Build Coastguard Worker         //     do {
3514*795d594fSAndroid Build Coastguard Worker         //       *dest_ptr++ = MaybePoison(ReadBarrier::Mark(MaybeUnpoison(*src_ptr++)));
3515*795d594fSAndroid Build Coastguard Worker         //     } while (src_ptr != end_ptr)
3516*795d594fSAndroid Build Coastguard Worker         //   } else {
3517*795d594fSAndroid Build Coastguard Worker         //     // Fast-path copy.
3518*795d594fSAndroid Build Coastguard Worker         //     do {
3519*795d594fSAndroid Build Coastguard Worker         //       *dest_ptr++ = *src_ptr++;
3520*795d594fSAndroid Build Coastguard Worker         //     } while (src_ptr != end_ptr)
3521*795d594fSAndroid Build Coastguard Worker         //   }
3522*795d594fSAndroid Build Coastguard Worker 
3523*795d594fSAndroid Build Coastguard Worker         // /* int32_t */ monitor = src->monitor_
3524*795d594fSAndroid Build Coastguard Worker         __ Ldr(tmp, HeapOperand(src.W(), monitor_offset));
3525*795d594fSAndroid Build Coastguard Worker         // /* LockWord */ lock_word = LockWord(monitor)
3526*795d594fSAndroid Build Coastguard Worker         static_assert(sizeof(LockWord) == sizeof(int32_t),
3527*795d594fSAndroid Build Coastguard Worker                       "art::LockWord and int32_t have different sizes.");
3528*795d594fSAndroid Build Coastguard Worker 
3529*795d594fSAndroid Build Coastguard Worker         // Introduce a dependency on the lock_word including rb_state,
3530*795d594fSAndroid Build Coastguard Worker         // to prevent load-load reordering, and without using
3531*795d594fSAndroid Build Coastguard Worker         // a memory barrier (which would be more expensive).
3532*795d594fSAndroid Build Coastguard Worker         // `src` is unchanged by this operation, but its value now depends
3533*795d594fSAndroid Build Coastguard Worker         // on `tmp`.
3534*795d594fSAndroid Build Coastguard Worker         __ Add(src.X(), src.X(), Operand(tmp.X(), LSR, 32));
3535*795d594fSAndroid Build Coastguard Worker 
3536*795d594fSAndroid Build Coastguard Worker         // Slow path used to copy array when `src` is gray.
3537*795d594fSAndroid Build Coastguard Worker         read_barrier_slow_path =
3538*795d594fSAndroid Build Coastguard Worker             new (codegen_->GetScopedAllocator()) ReadBarrierSystemArrayCopySlowPathARM64(
3539*795d594fSAndroid Build Coastguard Worker                 invoke, LocationFrom(tmp));
3540*795d594fSAndroid Build Coastguard Worker         codegen_->AddSlowPath(read_barrier_slow_path);
3541*795d594fSAndroid Build Coastguard Worker       }
3542*795d594fSAndroid Build Coastguard Worker 
3543*795d594fSAndroid Build Coastguard Worker       // Compute base source address, base destination address, and end
3544*795d594fSAndroid Build Coastguard Worker       // source address for System.arraycopy* intrinsics in `src_base`,
3545*795d594fSAndroid Build Coastguard Worker       // `dst_base` and `src_end` respectively.
3546*795d594fSAndroid Build Coastguard Worker       // Note that `src_curr_addr` is computed from from `src` (and
3547*795d594fSAndroid Build Coastguard Worker       // `src_pos`) here, and thus honors the artificial dependency
3548*795d594fSAndroid Build Coastguard Worker       // of `src` on `tmp`.
3549*795d594fSAndroid Build Coastguard Worker       GenSystemArrayCopyAddresses(masm,
3550*795d594fSAndroid Build Coastguard Worker                                   type,
3551*795d594fSAndroid Build Coastguard Worker                                   src,
3552*795d594fSAndroid Build Coastguard Worker                                   src_pos,
3553*795d594fSAndroid Build Coastguard Worker                                   dest,
3554*795d594fSAndroid Build Coastguard Worker                                   dest_pos,
3555*795d594fSAndroid Build Coastguard Worker                                   length,
3556*795d594fSAndroid Build Coastguard Worker                                   src_curr_addr,
3557*795d594fSAndroid Build Coastguard Worker                                   dst_curr_addr,
3558*795d594fSAndroid Build Coastguard Worker                                   src_stop_addr);
3559*795d594fSAndroid Build Coastguard Worker 
3560*795d594fSAndroid Build Coastguard Worker       if (emit_rb) {
3561*795d594fSAndroid Build Coastguard Worker         // Given the numeric representation, it's enough to check the low bit of the rb_state.
3562*795d594fSAndroid Build Coastguard Worker         static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
3563*795d594fSAndroid Build Coastguard Worker         static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
3564*795d594fSAndroid Build Coastguard Worker         __ Tbnz(tmp, LockWord::kReadBarrierStateShift, read_barrier_slow_path->GetEntryLabel());
3565*795d594fSAndroid Build Coastguard Worker       }
3566*795d594fSAndroid Build Coastguard Worker 
3567*795d594fSAndroid Build Coastguard Worker       // Iterate over the arrays and do a raw copy of the objects. We don't need to
3568*795d594fSAndroid Build Coastguard Worker       // poison/unpoison.
3569*795d594fSAndroid Build Coastguard Worker       vixl::aarch64::Label loop;
3570*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
3571*795d594fSAndroid Build Coastguard Worker       __ Ldr(tmp, MemOperand(src_curr_addr, element_size, PostIndex));
3572*795d594fSAndroid Build Coastguard Worker       __ Str(tmp, MemOperand(dst_curr_addr, element_size, PostIndex));
3573*795d594fSAndroid Build Coastguard Worker       __ Cmp(src_curr_addr, src_stop_addr);
3574*795d594fSAndroid Build Coastguard Worker       __ B(&loop, ne);
3575*795d594fSAndroid Build Coastguard Worker 
3576*795d594fSAndroid Build Coastguard Worker       if (emit_rb) {
3577*795d594fSAndroid Build Coastguard Worker         DCHECK(read_barrier_slow_path != nullptr);
3578*795d594fSAndroid Build Coastguard Worker         __ Bind(read_barrier_slow_path->GetExitLabel());
3579*795d594fSAndroid Build Coastguard Worker       }
3580*795d594fSAndroid Build Coastguard Worker     }
3581*795d594fSAndroid Build Coastguard Worker 
3582*795d594fSAndroid Build Coastguard Worker     // We only need one card marking on the destination array.
3583*795d594fSAndroid Build Coastguard Worker     codegen_->MarkGCCard(dest.W());
3584*795d594fSAndroid Build Coastguard Worker 
3585*795d594fSAndroid Build Coastguard Worker     __ Bind(&skip_copy_and_write_barrier);
3586*795d594fSAndroid Build Coastguard Worker   }
3587*795d594fSAndroid Build Coastguard Worker 
3588*795d594fSAndroid Build Coastguard Worker   __ Bind(intrinsic_slow_path->GetExitLabel());
3589*795d594fSAndroid Build Coastguard Worker }
3590*795d594fSAndroid Build Coastguard Worker 
GenIsInfinite(LocationSummary * locations,bool is64bit,MacroAssembler * masm)3591*795d594fSAndroid Build Coastguard Worker static void GenIsInfinite(LocationSummary* locations,
3592*795d594fSAndroid Build Coastguard Worker                           bool is64bit,
3593*795d594fSAndroid Build Coastguard Worker                           MacroAssembler* masm) {
3594*795d594fSAndroid Build Coastguard Worker   Operand infinity(0);
3595*795d594fSAndroid Build Coastguard Worker   Operand tst_mask(0);
3596*795d594fSAndroid Build Coastguard Worker   Register out;
3597*795d594fSAndroid Build Coastguard Worker 
3598*795d594fSAndroid Build Coastguard Worker   if (is64bit) {
3599*795d594fSAndroid Build Coastguard Worker     infinity = Operand(kPositiveInfinityDouble);
3600*795d594fSAndroid Build Coastguard Worker     tst_mask = MaskLeastSignificant<uint64_t>(63);
3601*795d594fSAndroid Build Coastguard Worker     out = XRegisterFrom(locations->Out());
3602*795d594fSAndroid Build Coastguard Worker   } else {
3603*795d594fSAndroid Build Coastguard Worker     infinity = Operand(kPositiveInfinityFloat);
3604*795d594fSAndroid Build Coastguard Worker     tst_mask = MaskLeastSignificant<uint32_t>(31);
3605*795d594fSAndroid Build Coastguard Worker     out = WRegisterFrom(locations->Out());
3606*795d594fSAndroid Build Coastguard Worker   }
3607*795d594fSAndroid Build Coastguard Worker 
3608*795d594fSAndroid Build Coastguard Worker   MoveFPToInt(locations, is64bit, masm);
3609*795d594fSAndroid Build Coastguard Worker   // Checks whether exponent bits are all 1 and fraction bits are all 0.
3610*795d594fSAndroid Build Coastguard Worker   __ Eor(out, out, infinity);
3611*795d594fSAndroid Build Coastguard Worker   // TST bitmask is used to mask out the sign bit: either 0x7fffffff or 0x7fffffffffffffff
3612*795d594fSAndroid Build Coastguard Worker   // depending on is64bit.
3613*795d594fSAndroid Build Coastguard Worker   __ Tst(out, tst_mask);
3614*795d594fSAndroid Build Coastguard Worker   __ Cset(out, eq);
3615*795d594fSAndroid Build Coastguard Worker }
3616*795d594fSAndroid Build Coastguard Worker 
VisitFloatIsInfinite(HInvoke * invoke)3617*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFloatIsInfinite(HInvoke* invoke) {
3618*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke);
3619*795d594fSAndroid Build Coastguard Worker }
3620*795d594fSAndroid Build Coastguard Worker 
VisitFloatIsInfinite(HInvoke * invoke)3621*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFloatIsInfinite(HInvoke* invoke) {
3622*795d594fSAndroid Build Coastguard Worker   GenIsInfinite(invoke->GetLocations(), /* is64bit= */ false, GetVIXLAssembler());
3623*795d594fSAndroid Build Coastguard Worker }
3624*795d594fSAndroid Build Coastguard Worker 
VisitDoubleIsInfinite(HInvoke * invoke)3625*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitDoubleIsInfinite(HInvoke* invoke) {
3626*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke);
3627*795d594fSAndroid Build Coastguard Worker }
3628*795d594fSAndroid Build Coastguard Worker 
VisitDoubleIsInfinite(HInvoke * invoke)3629*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitDoubleIsInfinite(HInvoke* invoke) {
3630*795d594fSAndroid Build Coastguard Worker   GenIsInfinite(invoke->GetLocations(), /* is64bit= */ true, GetVIXLAssembler());
3631*795d594fSAndroid Build Coastguard Worker }
3632*795d594fSAndroid Build Coastguard Worker 
3633*795d594fSAndroid Build Coastguard Worker #define VISIT_INTRINSIC(name, low, high, type, start_index)                              \
3634*795d594fSAndroid Build Coastguard Worker   void IntrinsicLocationsBuilderARM64::Visit##name##ValueOf(HInvoke* invoke) {           \
3635*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;                                   \
3636*795d594fSAndroid Build Coastguard Worker     IntrinsicVisitor::ComputeValueOfLocations(                                           \
3637*795d594fSAndroid Build Coastguard Worker         invoke,                                                                          \
3638*795d594fSAndroid Build Coastguard Worker         codegen_,                                                                        \
3639*795d594fSAndroid Build Coastguard Worker         low,                                                                             \
3640*795d594fSAndroid Build Coastguard Worker         (high) - (low) + 1,                                                              \
3641*795d594fSAndroid Build Coastguard Worker         calling_convention.GetReturnLocation(DataType::Type::kReference),                \
3642*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));      \
3643*795d594fSAndroid Build Coastguard Worker   }                                                                                      \
3644*795d594fSAndroid Build Coastguard Worker   void IntrinsicCodeGeneratorARM64::Visit##name##ValueOf(HInvoke* invoke) {              \
3645*795d594fSAndroid Build Coastguard Worker     IntrinsicVisitor::ValueOfInfo info =                                                 \
3646*795d594fSAndroid Build Coastguard Worker         IntrinsicVisitor::ComputeValueOfInfo(invoke,                                     \
3647*795d594fSAndroid Build Coastguard Worker                                              codegen_->GetCompilerOptions(),             \
3648*795d594fSAndroid Build Coastguard Worker                                              WellKnownClasses::java_lang_##name##_value, \
3649*795d594fSAndroid Build Coastguard Worker                                              low,                                        \
3650*795d594fSAndroid Build Coastguard Worker                                              (high) - (low) + 1,                         \
3651*795d594fSAndroid Build Coastguard Worker                                              start_index);                               \
3652*795d594fSAndroid Build Coastguard Worker     HandleValueOf(invoke, info, type);                                                   \
3653*795d594fSAndroid Build Coastguard Worker   }
BOXED_TYPES(VISIT_INTRINSIC)3654*795d594fSAndroid Build Coastguard Worker   BOXED_TYPES(VISIT_INTRINSIC)
3655*795d594fSAndroid Build Coastguard Worker #undef VISIT_INTRINSIC
3656*795d594fSAndroid Build Coastguard Worker 
3657*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::HandleValueOf(HInvoke* invoke,
3658*795d594fSAndroid Build Coastguard Worker                                                 const IntrinsicVisitor::ValueOfInfo& info,
3659*795d594fSAndroid Build Coastguard Worker                                                 DataType::Type type) {
3660*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3661*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3662*795d594fSAndroid Build Coastguard Worker 
3663*795d594fSAndroid Build Coastguard Worker   Register out = RegisterFrom(locations->Out(), DataType::Type::kReference);
3664*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3665*795d594fSAndroid Build Coastguard Worker   Register temp = temps.AcquireW();
3666*795d594fSAndroid Build Coastguard Worker   auto allocate_instance = [&]() {
3667*795d594fSAndroid Build Coastguard Worker     DCHECK(out.X().Is(InvokeRuntimeCallingConvention().GetRegisterAt(0)));
3668*795d594fSAndroid Build Coastguard Worker     codegen_->LoadIntrinsicDeclaringClass(out, invoke);
3669*795d594fSAndroid Build Coastguard Worker     codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
3670*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
3671*795d594fSAndroid Build Coastguard Worker   };
3672*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsIntConstant()) {
3673*795d594fSAndroid Build Coastguard Worker     int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
3674*795d594fSAndroid Build Coastguard Worker     if (static_cast<uint32_t>(value - info.low) < info.length) {
3675*795d594fSAndroid Build Coastguard Worker       // Just embed the object in the code.
3676*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(info.value_boot_image_reference, ValueOfInfo::kInvalidReference);
3677*795d594fSAndroid Build Coastguard Worker       codegen_->LoadBootImageAddress(out, info.value_boot_image_reference);
3678*795d594fSAndroid Build Coastguard Worker     } else {
3679*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->CanCall());
3680*795d594fSAndroid Build Coastguard Worker       // Allocate and initialize a new object.
3681*795d594fSAndroid Build Coastguard Worker       // TODO: If we JIT, we could allocate the object now, and store it in the
3682*795d594fSAndroid Build Coastguard Worker       // JIT object table.
3683*795d594fSAndroid Build Coastguard Worker       allocate_instance();
3684*795d594fSAndroid Build Coastguard Worker       __ Mov(temp.W(), value);
3685*795d594fSAndroid Build Coastguard Worker       codegen_->Store(type, temp.W(), HeapOperand(out.W(), info.value_offset));
3686*795d594fSAndroid Build Coastguard Worker       // Class pointer and `value` final field stores require a barrier before publication.
3687*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3688*795d594fSAndroid Build Coastguard Worker     }
3689*795d594fSAndroid Build Coastguard Worker   } else {
3690*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
3691*795d594fSAndroid Build Coastguard Worker     Register in = RegisterFrom(locations->InAt(0), DataType::Type::kInt32);
3692*795d594fSAndroid Build Coastguard Worker     // Check bounds of our cache.
3693*795d594fSAndroid Build Coastguard Worker     __ Add(out.W(), in.W(), -info.low);
3694*795d594fSAndroid Build Coastguard Worker     __ Cmp(out.W(), info.length);
3695*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label allocate, done;
3696*795d594fSAndroid Build Coastguard Worker     __ B(&allocate, hs);
3697*795d594fSAndroid Build Coastguard Worker     // If the value is within the bounds, load the object directly from the array.
3698*795d594fSAndroid Build Coastguard Worker     codegen_->LoadBootImageAddress(temp, info.array_data_boot_image_reference);
3699*795d594fSAndroid Build Coastguard Worker     MemOperand source = HeapOperand(
3700*795d594fSAndroid Build Coastguard Worker         temp, out.X(), LSL, DataType::SizeShift(DataType::Type::kReference));
3701*795d594fSAndroid Build Coastguard Worker     codegen_->Load(DataType::Type::kReference, out, source);
3702*795d594fSAndroid Build Coastguard Worker     codegen_->GetAssembler()->MaybeUnpoisonHeapReference(out);
3703*795d594fSAndroid Build Coastguard Worker     __ B(&done);
3704*795d594fSAndroid Build Coastguard Worker     __ Bind(&allocate);
3705*795d594fSAndroid Build Coastguard Worker     // Otherwise allocate and initialize a new object.
3706*795d594fSAndroid Build Coastguard Worker     allocate_instance();
3707*795d594fSAndroid Build Coastguard Worker     codegen_->Store(type, in.W(), HeapOperand(out.W(), info.value_offset));
3708*795d594fSAndroid Build Coastguard Worker     // Class pointer and `value` final field stores require a barrier before publication.
3709*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3710*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
3711*795d594fSAndroid Build Coastguard Worker   }
3712*795d594fSAndroid Build Coastguard Worker }
3713*795d594fSAndroid Build Coastguard Worker 
VisitReferenceGetReferent(HInvoke * invoke)3714*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitReferenceGetReferent(HInvoke* invoke) {
3715*795d594fSAndroid Build Coastguard Worker   IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_);
3716*795d594fSAndroid Build Coastguard Worker 
3717*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitBakerReadBarrier() && invoke->GetLocations() != nullptr) {
3718*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->AddTemp(Location::RequiresRegister());
3719*795d594fSAndroid Build Coastguard Worker   }
3720*795d594fSAndroid Build Coastguard Worker }
3721*795d594fSAndroid Build Coastguard Worker 
VisitReferenceGetReferent(HInvoke * invoke)3722*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitReferenceGetReferent(HInvoke* invoke) {
3723*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3724*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3725*795d594fSAndroid Build Coastguard Worker 
3726*795d594fSAndroid Build Coastguard Worker   Location obj = locations->InAt(0);
3727*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3728*795d594fSAndroid Build Coastguard Worker 
3729*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke);
3730*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
3731*795d594fSAndroid Build Coastguard Worker 
3732*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitReadBarrier()) {
3733*795d594fSAndroid Build Coastguard Worker     // Check self->GetWeakRefAccessEnabled().
3734*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
3735*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
3736*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp,
3737*795d594fSAndroid Build Coastguard Worker            MemOperand(tr, Thread::WeakRefAccessEnabledOffset<kArm64PointerSize>().Uint32Value()));
3738*795d594fSAndroid Build Coastguard Worker     static_assert(enum_cast<int32_t>(WeakRefAccessState::kVisiblyEnabled) == 0);
3739*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp, slow_path->GetEntryLabel());
3740*795d594fSAndroid Build Coastguard Worker   }
3741*795d594fSAndroid Build Coastguard Worker 
3742*795d594fSAndroid Build Coastguard Worker   {
3743*795d594fSAndroid Build Coastguard Worker     // Load the java.lang.ref.Reference class.
3744*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
3745*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
3746*795d594fSAndroid Build Coastguard Worker     codegen_->LoadIntrinsicDeclaringClass(temp, invoke);
3747*795d594fSAndroid Build Coastguard Worker 
3748*795d594fSAndroid Build Coastguard Worker     // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together.
3749*795d594fSAndroid Build Coastguard Worker     MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset();
3750*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u);
3751*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u,
3752*795d594fSAndroid Build Coastguard Worker               IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value());
3753*795d594fSAndroid Build Coastguard Worker     __ Ldrh(temp, HeapOperand(temp, disable_intrinsic_offset.Uint32Value()));
3754*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp, slow_path->GetEntryLabel());
3755*795d594fSAndroid Build Coastguard Worker   }
3756*795d594fSAndroid Build Coastguard Worker 
3757*795d594fSAndroid Build Coastguard Worker   // Load the value from the field.
3758*795d594fSAndroid Build Coastguard Worker   uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
3759*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitBakerReadBarrier()) {
3760*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
3761*795d594fSAndroid Build Coastguard Worker                                                     out,
3762*795d594fSAndroid Build Coastguard Worker                                                     WRegisterFrom(obj),
3763*795d594fSAndroid Build Coastguard Worker                                                     referent_offset,
3764*795d594fSAndroid Build Coastguard Worker                                                     /*maybe_temp=*/ locations->GetTemp(0),
3765*795d594fSAndroid Build Coastguard Worker                                                     /*needs_null_check=*/ true,
3766*795d594fSAndroid Build Coastguard Worker                                                     /*use_load_acquire=*/ true);
3767*795d594fSAndroid Build Coastguard Worker   } else {
3768*795d594fSAndroid Build Coastguard Worker     MemOperand field = HeapOperand(WRegisterFrom(obj), referent_offset);
3769*795d594fSAndroid Build Coastguard Worker     codegen_->LoadAcquire(
3770*795d594fSAndroid Build Coastguard Worker         invoke, DataType::Type::kReference, WRegisterFrom(out), field, /*needs_null_check=*/ true);
3771*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset);
3772*795d594fSAndroid Build Coastguard Worker   }
3773*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
3774*795d594fSAndroid Build Coastguard Worker }
3775*795d594fSAndroid Build Coastguard Worker 
VisitReferenceRefersTo(HInvoke * invoke)3776*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitReferenceRefersTo(HInvoke* invoke) {
3777*795d594fSAndroid Build Coastguard Worker   IntrinsicVisitor::CreateReferenceRefersToLocations(invoke, codegen_);
3778*795d594fSAndroid Build Coastguard Worker }
3779*795d594fSAndroid Build Coastguard Worker 
VisitReferenceRefersTo(HInvoke * invoke)3780*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitReferenceRefersTo(HInvoke* invoke) {
3781*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3782*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen_->GetVIXLAssembler();
3783*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3784*795d594fSAndroid Build Coastguard Worker 
3785*795d594fSAndroid Build Coastguard Worker   Register obj = WRegisterFrom(locations->InAt(0));
3786*795d594fSAndroid Build Coastguard Worker   Register other = WRegisterFrom(locations->InAt(1));
3787*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
3788*795d594fSAndroid Build Coastguard Worker   Register tmp = temps.AcquireW();
3789*795d594fSAndroid Build Coastguard Worker 
3790*795d594fSAndroid Build Coastguard Worker   uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
3791*795d594fSAndroid Build Coastguard Worker   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
3792*795d594fSAndroid Build Coastguard Worker 
3793*795d594fSAndroid Build Coastguard Worker   MemOperand field = HeapOperand(obj, referent_offset);
3794*795d594fSAndroid Build Coastguard Worker   codegen_->LoadAcquire(invoke, DataType::Type::kReference, tmp, field, /*needs_null_check=*/ true);
3795*795d594fSAndroid Build Coastguard Worker   codegen_->GetAssembler()->MaybeUnpoisonHeapReference(tmp);
3796*795d594fSAndroid Build Coastguard Worker 
3797*795d594fSAndroid Build Coastguard Worker   __ Cmp(tmp, other);
3798*795d594fSAndroid Build Coastguard Worker 
3799*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitReadBarrier()) {
3800*795d594fSAndroid Build Coastguard Worker     DCHECK(kUseBakerReadBarrier);
3801*795d594fSAndroid Build Coastguard Worker 
3802*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label calculate_result;
3803*795d594fSAndroid Build Coastguard Worker 
3804*795d594fSAndroid Build Coastguard Worker     // If the GC is not marking, the comparison result is final.
3805*795d594fSAndroid Build Coastguard Worker     __ Cbz(mr, &calculate_result);
3806*795d594fSAndroid Build Coastguard Worker 
3807*795d594fSAndroid Build Coastguard Worker     __ B(&calculate_result, eq);  // ZF set if taken.
3808*795d594fSAndroid Build Coastguard Worker 
3809*795d594fSAndroid Build Coastguard Worker     // Check if the loaded reference is null.
3810*795d594fSAndroid Build Coastguard Worker     __ Cbz(tmp, &calculate_result);  // ZF clear if taken.
3811*795d594fSAndroid Build Coastguard Worker 
3812*795d594fSAndroid Build Coastguard Worker     // For correct memory visibility, we need a barrier before loading the lock word.
3813*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3814*795d594fSAndroid Build Coastguard Worker 
3815*795d594fSAndroid Build Coastguard Worker     // Load the lockword and check if it is a forwarding address.
3816*795d594fSAndroid Build Coastguard Worker     static_assert(LockWord::kStateShift == 30u);
3817*795d594fSAndroid Build Coastguard Worker     static_assert(LockWord::kStateForwardingAddress == 3u);
3818*795d594fSAndroid Build Coastguard Worker     __ Ldr(tmp, HeapOperand(tmp, monitor_offset));
3819*795d594fSAndroid Build Coastguard Worker     __ Cmp(tmp, Operand(0xc0000000));
3820*795d594fSAndroid Build Coastguard Worker     __ B(&calculate_result, lo);   // ZF clear if taken.
3821*795d594fSAndroid Build Coastguard Worker 
3822*795d594fSAndroid Build Coastguard Worker     // Extract the forwarding address and compare with `other`.
3823*795d594fSAndroid Build Coastguard Worker     __ Cmp(other, Operand(tmp, LSL, LockWord::kForwardingAddressShift));
3824*795d594fSAndroid Build Coastguard Worker 
3825*795d594fSAndroid Build Coastguard Worker     __ Bind(&calculate_result);
3826*795d594fSAndroid Build Coastguard Worker   }
3827*795d594fSAndroid Build Coastguard Worker 
3828*795d594fSAndroid Build Coastguard Worker   // Convert ZF into the Boolean result.
3829*795d594fSAndroid Build Coastguard Worker   __ Cset(out, eq);
3830*795d594fSAndroid Build Coastguard Worker }
3831*795d594fSAndroid Build Coastguard Worker 
VisitThreadInterrupted(HInvoke * invoke)3832*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitThreadInterrupted(HInvoke* invoke) {
3833*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3834*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3835*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
3836*795d594fSAndroid Build Coastguard Worker }
3837*795d594fSAndroid Build Coastguard Worker 
VisitThreadInterrupted(HInvoke * invoke)3838*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitThreadInterrupted(HInvoke* invoke) {
3839*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3840*795d594fSAndroid Build Coastguard Worker   Register out = RegisterFrom(invoke->GetLocations()->Out(), DataType::Type::kInt32);
3841*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3842*795d594fSAndroid Build Coastguard Worker   Register temp = temps.AcquireX();
3843*795d594fSAndroid Build Coastguard Worker 
3844*795d594fSAndroid Build Coastguard Worker   __ Add(temp, tr, Thread::InterruptedOffset<kArm64PointerSize>().Int32Value());
3845*795d594fSAndroid Build Coastguard Worker   __ Ldar(out.W(), MemOperand(temp));
3846*795d594fSAndroid Build Coastguard Worker 
3847*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label done;
3848*795d594fSAndroid Build Coastguard Worker   __ Cbz(out.W(), &done);
3849*795d594fSAndroid Build Coastguard Worker   __ Stlr(wzr, MemOperand(temp));
3850*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
3851*795d594fSAndroid Build Coastguard Worker }
3852*795d594fSAndroid Build Coastguard Worker 
VisitReachabilityFence(HInvoke * invoke)3853*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitReachabilityFence(HInvoke* invoke) {
3854*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3855*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3856*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::Any());
3857*795d594fSAndroid Build Coastguard Worker }
3858*795d594fSAndroid Build Coastguard Worker 
VisitReachabilityFence(HInvoke * invoke)3859*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitReachabilityFence([[maybe_unused]] HInvoke* invoke) {}
3860*795d594fSAndroid Build Coastguard Worker 
VisitCRC32Update(HInvoke * invoke)3861*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitCRC32Update(HInvoke* invoke) {
3862*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
3863*795d594fSAndroid Build Coastguard Worker     return;
3864*795d594fSAndroid Build Coastguard Worker   }
3865*795d594fSAndroid Build Coastguard Worker 
3866*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(invoke,
3867*795d594fSAndroid Build Coastguard Worker                                                                 LocationSummary::kNoCall,
3868*795d594fSAndroid Build Coastguard Worker                                                                 kIntrinsified);
3869*795d594fSAndroid Build Coastguard Worker 
3870*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
3871*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
3872*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3873*795d594fSAndroid Build Coastguard Worker }
3874*795d594fSAndroid Build Coastguard Worker 
3875*795d594fSAndroid Build Coastguard Worker // Lower the invoke of CRC32.update(int crc, int b).
VisitCRC32Update(HInvoke * invoke)3876*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) {
3877*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
3878*795d594fSAndroid Build Coastguard Worker 
3879*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
3880*795d594fSAndroid Build Coastguard Worker 
3881*795d594fSAndroid Build Coastguard Worker   Register crc = InputRegisterAt(invoke, 0);
3882*795d594fSAndroid Build Coastguard Worker   Register val = InputRegisterAt(invoke, 1);
3883*795d594fSAndroid Build Coastguard Worker   Register out = OutputRegister(invoke);
3884*795d594fSAndroid Build Coastguard Worker 
3885*795d594fSAndroid Build Coastguard Worker   // The general algorithm of the CRC32 calculation is:
3886*795d594fSAndroid Build Coastguard Worker   //   crc = ~crc
3887*795d594fSAndroid Build Coastguard Worker   //   result = crc32_for_byte(crc, b)
3888*795d594fSAndroid Build Coastguard Worker   //   crc = ~result
3889*795d594fSAndroid Build Coastguard Worker   // It is directly lowered to three instructions.
3890*795d594fSAndroid Build Coastguard Worker 
3891*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3892*795d594fSAndroid Build Coastguard Worker   Register tmp = temps.AcquireSameSizeAs(out);
3893*795d594fSAndroid Build Coastguard Worker 
3894*795d594fSAndroid Build Coastguard Worker   __ Mvn(tmp, crc);
3895*795d594fSAndroid Build Coastguard Worker   __ Crc32b(tmp, tmp, val);
3896*795d594fSAndroid Build Coastguard Worker   __ Mvn(out, tmp);
3897*795d594fSAndroid Build Coastguard Worker }
3898*795d594fSAndroid Build Coastguard Worker 
3899*795d594fSAndroid Build Coastguard Worker // Generate code using CRC32 instructions which calculates
3900*795d594fSAndroid Build Coastguard Worker // a CRC32 value of a byte.
3901*795d594fSAndroid Build Coastguard Worker //
3902*795d594fSAndroid Build Coastguard Worker // Parameters:
3903*795d594fSAndroid Build Coastguard Worker //   masm   - VIXL macro assembler
3904*795d594fSAndroid Build Coastguard Worker //   crc    - a register holding an initial CRC value
3905*795d594fSAndroid Build Coastguard Worker //   ptr    - a register holding a memory address of bytes
3906*795d594fSAndroid Build Coastguard Worker //   length - a register holding a number of bytes to process
3907*795d594fSAndroid Build Coastguard Worker //   out    - a register to put a result of calculation
GenerateCodeForCalculationCRC32ValueOfBytes(MacroAssembler * masm,const Register & crc,const Register & ptr,const Register & length,const Register & out)3908*795d594fSAndroid Build Coastguard Worker static void GenerateCodeForCalculationCRC32ValueOfBytes(MacroAssembler* masm,
3909*795d594fSAndroid Build Coastguard Worker                                                         const Register& crc,
3910*795d594fSAndroid Build Coastguard Worker                                                         const Register& ptr,
3911*795d594fSAndroid Build Coastguard Worker                                                         const Register& length,
3912*795d594fSAndroid Build Coastguard Worker                                                         const Register& out) {
3913*795d594fSAndroid Build Coastguard Worker   // The algorithm of CRC32 of bytes is:
3914*795d594fSAndroid Build Coastguard Worker   //   crc = ~crc
3915*795d594fSAndroid Build Coastguard Worker   //   process a few first bytes to make the array 8-byte aligned
3916*795d594fSAndroid Build Coastguard Worker   //   while array has 8 bytes do:
3917*795d594fSAndroid Build Coastguard Worker   //     crc = crc32_of_8bytes(crc, 8_bytes(array))
3918*795d594fSAndroid Build Coastguard Worker   //   if array has 4 bytes:
3919*795d594fSAndroid Build Coastguard Worker   //     crc = crc32_of_4bytes(crc, 4_bytes(array))
3920*795d594fSAndroid Build Coastguard Worker   //   if array has 2 bytes:
3921*795d594fSAndroid Build Coastguard Worker   //     crc = crc32_of_2bytes(crc, 2_bytes(array))
3922*795d594fSAndroid Build Coastguard Worker   //   if array has a byte:
3923*795d594fSAndroid Build Coastguard Worker   //     crc = crc32_of_byte(crc, 1_byte(array))
3924*795d594fSAndroid Build Coastguard Worker   //   crc = ~crc
3925*795d594fSAndroid Build Coastguard Worker 
3926*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop, done;
3927*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label process_4bytes, process_2bytes, process_1byte;
3928*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label aligned2, aligned4, aligned8;
3929*795d594fSAndroid Build Coastguard Worker 
3930*795d594fSAndroid Build Coastguard Worker   // Use VIXL scratch registers as the VIXL macro assembler won't use them in
3931*795d594fSAndroid Build Coastguard Worker   // instructions below.
3932*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
3933*795d594fSAndroid Build Coastguard Worker   Register len = temps.AcquireW();
3934*795d594fSAndroid Build Coastguard Worker   Register array_elem = temps.AcquireW();
3935*795d594fSAndroid Build Coastguard Worker 
3936*795d594fSAndroid Build Coastguard Worker   __ Mvn(out, crc);
3937*795d594fSAndroid Build Coastguard Worker   __ Mov(len, length);
3938*795d594fSAndroid Build Coastguard Worker 
3939*795d594fSAndroid Build Coastguard Worker   __ Tbz(ptr, 0, &aligned2);
3940*795d594fSAndroid Build Coastguard Worker   __ Subs(len, len, 1);
3941*795d594fSAndroid Build Coastguard Worker   __ B(&done, lo);
3942*795d594fSAndroid Build Coastguard Worker   __ Ldrb(array_elem, MemOperand(ptr, 1, PostIndex));
3943*795d594fSAndroid Build Coastguard Worker   __ Crc32b(out, out, array_elem);
3944*795d594fSAndroid Build Coastguard Worker 
3945*795d594fSAndroid Build Coastguard Worker   __ Bind(&aligned2);
3946*795d594fSAndroid Build Coastguard Worker   __ Tbz(ptr, 1, &aligned4);
3947*795d594fSAndroid Build Coastguard Worker   __ Subs(len, len, 2);
3948*795d594fSAndroid Build Coastguard Worker   __ B(&process_1byte, lo);
3949*795d594fSAndroid Build Coastguard Worker   __ Ldrh(array_elem, MemOperand(ptr, 2, PostIndex));
3950*795d594fSAndroid Build Coastguard Worker   __ Crc32h(out, out, array_elem);
3951*795d594fSAndroid Build Coastguard Worker 
3952*795d594fSAndroid Build Coastguard Worker   __ Bind(&aligned4);
3953*795d594fSAndroid Build Coastguard Worker   __ Tbz(ptr, 2, &aligned8);
3954*795d594fSAndroid Build Coastguard Worker   __ Subs(len, len, 4);
3955*795d594fSAndroid Build Coastguard Worker   __ B(&process_2bytes, lo);
3956*795d594fSAndroid Build Coastguard Worker   __ Ldr(array_elem, MemOperand(ptr, 4, PostIndex));
3957*795d594fSAndroid Build Coastguard Worker   __ Crc32w(out, out, array_elem);
3958*795d594fSAndroid Build Coastguard Worker 
3959*795d594fSAndroid Build Coastguard Worker   __ Bind(&aligned8);
3960*795d594fSAndroid Build Coastguard Worker   __ Subs(len, len, 8);
3961*795d594fSAndroid Build Coastguard Worker   // If len < 8 go to process data by 4 bytes, 2 bytes and a byte.
3962*795d594fSAndroid Build Coastguard Worker   __ B(&process_4bytes, lo);
3963*795d594fSAndroid Build Coastguard Worker 
3964*795d594fSAndroid Build Coastguard Worker   // The main loop processing data by 8 bytes.
3965*795d594fSAndroid Build Coastguard Worker   __ Bind(&loop);
3966*795d594fSAndroid Build Coastguard Worker   __ Ldr(array_elem.X(), MemOperand(ptr, 8, PostIndex));
3967*795d594fSAndroid Build Coastguard Worker   __ Subs(len, len, 8);
3968*795d594fSAndroid Build Coastguard Worker   __ Crc32x(out, out, array_elem.X());
3969*795d594fSAndroid Build Coastguard Worker   // if len >= 8, process the next 8 bytes.
3970*795d594fSAndroid Build Coastguard Worker   __ B(&loop, hs);
3971*795d594fSAndroid Build Coastguard Worker 
3972*795d594fSAndroid Build Coastguard Worker   // Process the data which is less than 8 bytes.
3973*795d594fSAndroid Build Coastguard Worker   // The code generated below works with values of len
3974*795d594fSAndroid Build Coastguard Worker   // which come in the range [-8, 0].
3975*795d594fSAndroid Build Coastguard Worker   // The first three bits are used to detect whether 4 bytes or 2 bytes or
3976*795d594fSAndroid Build Coastguard Worker   // a byte can be processed.
3977*795d594fSAndroid Build Coastguard Worker   // The checking order is from bit 2 to bit 0:
3978*795d594fSAndroid Build Coastguard Worker   //  bit 2 is set: at least 4 bytes available
3979*795d594fSAndroid Build Coastguard Worker   //  bit 1 is set: at least 2 bytes available
3980*795d594fSAndroid Build Coastguard Worker   //  bit 0 is set: at least a byte available
3981*795d594fSAndroid Build Coastguard Worker   __ Bind(&process_4bytes);
3982*795d594fSAndroid Build Coastguard Worker   // Goto process_2bytes if less than four bytes available
3983*795d594fSAndroid Build Coastguard Worker   __ Tbz(len, 2, &process_2bytes);
3984*795d594fSAndroid Build Coastguard Worker   __ Ldr(array_elem, MemOperand(ptr, 4, PostIndex));
3985*795d594fSAndroid Build Coastguard Worker   __ Crc32w(out, out, array_elem);
3986*795d594fSAndroid Build Coastguard Worker 
3987*795d594fSAndroid Build Coastguard Worker   __ Bind(&process_2bytes);
3988*795d594fSAndroid Build Coastguard Worker   // Goto process_1bytes if less than two bytes available
3989*795d594fSAndroid Build Coastguard Worker   __ Tbz(len, 1, &process_1byte);
3990*795d594fSAndroid Build Coastguard Worker   __ Ldrh(array_elem, MemOperand(ptr, 2, PostIndex));
3991*795d594fSAndroid Build Coastguard Worker   __ Crc32h(out, out, array_elem);
3992*795d594fSAndroid Build Coastguard Worker 
3993*795d594fSAndroid Build Coastguard Worker   __ Bind(&process_1byte);
3994*795d594fSAndroid Build Coastguard Worker   // Goto done if no bytes available
3995*795d594fSAndroid Build Coastguard Worker   __ Tbz(len, 0, &done);
3996*795d594fSAndroid Build Coastguard Worker   __ Ldrb(array_elem, MemOperand(ptr));
3997*795d594fSAndroid Build Coastguard Worker   __ Crc32b(out, out, array_elem);
3998*795d594fSAndroid Build Coastguard Worker 
3999*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
4000*795d594fSAndroid Build Coastguard Worker   __ Mvn(out, out);
4001*795d594fSAndroid Build Coastguard Worker }
4002*795d594fSAndroid Build Coastguard Worker 
4003*795d594fSAndroid Build Coastguard Worker // The threshold for sizes of arrays to use the library provided implementation
4004*795d594fSAndroid Build Coastguard Worker // of CRC32.updateBytes instead of the intrinsic.
4005*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kCRC32UpdateBytesThreshold = 64 * 1024;
4006*795d594fSAndroid Build Coastguard Worker 
VisitCRC32UpdateBytes(HInvoke * invoke)4007*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateBytes(HInvoke* invoke) {
4008*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
4009*795d594fSAndroid Build Coastguard Worker     return;
4010*795d594fSAndroid Build Coastguard Worker   }
4011*795d594fSAndroid Build Coastguard Worker 
4012*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
4013*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke,
4014*795d594fSAndroid Build Coastguard Worker                                        LocationSummary::kCallOnSlowPath,
4015*795d594fSAndroid Build Coastguard Worker                                        kIntrinsified);
4016*795d594fSAndroid Build Coastguard Worker 
4017*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4018*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
4019*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RegisterOrConstant(invoke->InputAt(2)));
4020*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
4021*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
4022*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
4023*795d594fSAndroid Build Coastguard Worker }
4024*795d594fSAndroid Build Coastguard Worker 
4025*795d594fSAndroid Build Coastguard Worker // Lower the invoke of CRC32.updateBytes(int crc, byte[] b, int off, int len)
4026*795d594fSAndroid Build Coastguard Worker //
4027*795d594fSAndroid Build Coastguard Worker // Note: The intrinsic is not used if len exceeds a threshold.
VisitCRC32UpdateBytes(HInvoke * invoke)4028*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) {
4029*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
4030*795d594fSAndroid Build Coastguard Worker 
4031*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4032*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4033*795d594fSAndroid Build Coastguard Worker 
4034*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
4035*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
4036*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
4037*795d594fSAndroid Build Coastguard Worker 
4038*795d594fSAndroid Build Coastguard Worker   Register length = WRegisterFrom(locations->InAt(3));
4039*795d594fSAndroid Build Coastguard Worker   __ Cmp(length, kCRC32UpdateBytesThreshold);
4040*795d594fSAndroid Build Coastguard Worker   __ B(slow_path->GetEntryLabel(), hi);
4041*795d594fSAndroid Build Coastguard Worker 
4042*795d594fSAndroid Build Coastguard Worker   const uint32_t array_data_offset =
4043*795d594fSAndroid Build Coastguard Worker       mirror::Array::DataOffset(Primitive::kPrimByte).Uint32Value();
4044*795d594fSAndroid Build Coastguard Worker   Register ptr = XRegisterFrom(locations->GetTemp(0));
4045*795d594fSAndroid Build Coastguard Worker   Register array = XRegisterFrom(locations->InAt(1));
4046*795d594fSAndroid Build Coastguard Worker   Location offset = locations->InAt(2);
4047*795d594fSAndroid Build Coastguard Worker   if (offset.IsConstant()) {
4048*795d594fSAndroid Build Coastguard Worker     int32_t offset_value = offset.GetConstant()->AsIntConstant()->GetValue();
4049*795d594fSAndroid Build Coastguard Worker     __ Add(ptr, array, array_data_offset + offset_value);
4050*795d594fSAndroid Build Coastguard Worker   } else {
4051*795d594fSAndroid Build Coastguard Worker     __ Add(ptr, array, array_data_offset);
4052*795d594fSAndroid Build Coastguard Worker     __ Add(ptr, ptr, XRegisterFrom(offset));
4053*795d594fSAndroid Build Coastguard Worker   }
4054*795d594fSAndroid Build Coastguard Worker 
4055*795d594fSAndroid Build Coastguard Worker   Register crc = WRegisterFrom(locations->InAt(0));
4056*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
4057*795d594fSAndroid Build Coastguard Worker 
4058*795d594fSAndroid Build Coastguard Worker   GenerateCodeForCalculationCRC32ValueOfBytes(masm, crc, ptr, length, out);
4059*795d594fSAndroid Build Coastguard Worker 
4060*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4061*795d594fSAndroid Build Coastguard Worker }
4062*795d594fSAndroid Build Coastguard Worker 
VisitCRC32UpdateByteBuffer(HInvoke * invoke)4063*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateByteBuffer(HInvoke* invoke) {
4064*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
4065*795d594fSAndroid Build Coastguard Worker     return;
4066*795d594fSAndroid Build Coastguard Worker   }
4067*795d594fSAndroid Build Coastguard Worker 
4068*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
4069*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke,
4070*795d594fSAndroid Build Coastguard Worker                                        LocationSummary::kNoCall,
4071*795d594fSAndroid Build Coastguard Worker                                        kIntrinsified);
4072*795d594fSAndroid Build Coastguard Worker 
4073*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4074*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
4075*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
4076*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
4077*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
4078*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
4079*795d594fSAndroid Build Coastguard Worker }
4080*795d594fSAndroid Build Coastguard Worker 
4081*795d594fSAndroid Build Coastguard Worker // Lower the invoke of CRC32.updateByteBuffer(int crc, long addr, int off, int len)
4082*795d594fSAndroid Build Coastguard Worker //
4083*795d594fSAndroid Build Coastguard Worker // There is no need to generate code checking if addr is 0.
4084*795d594fSAndroid Build Coastguard Worker // The method updateByteBuffer is a private method of java.util.zip.CRC32.
4085*795d594fSAndroid Build Coastguard Worker // This guarantees no calls outside of the CRC32 class.
4086*795d594fSAndroid Build Coastguard Worker // An address of DirectBuffer is always passed to the call of updateByteBuffer.
4087*795d594fSAndroid Build Coastguard Worker // It might be an implementation of an empty DirectBuffer which can use a zero
4088*795d594fSAndroid Build Coastguard Worker // address but it must have the length to be zero. The current generated code
4089*795d594fSAndroid Build Coastguard Worker // correctly works with the zero length.
VisitCRC32UpdateByteBuffer(HInvoke * invoke)4090*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateByteBuffer(HInvoke* invoke) {
4091*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
4092*795d594fSAndroid Build Coastguard Worker 
4093*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4094*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4095*795d594fSAndroid Build Coastguard Worker 
4096*795d594fSAndroid Build Coastguard Worker   Register addr = XRegisterFrom(locations->InAt(1));
4097*795d594fSAndroid Build Coastguard Worker   Register ptr = XRegisterFrom(locations->GetTemp(0));
4098*795d594fSAndroid Build Coastguard Worker   __ Add(ptr, addr, XRegisterFrom(locations->InAt(2)));
4099*795d594fSAndroid Build Coastguard Worker 
4100*795d594fSAndroid Build Coastguard Worker   Register crc = WRegisterFrom(locations->InAt(0));
4101*795d594fSAndroid Build Coastguard Worker   Register length = WRegisterFrom(locations->InAt(3));
4102*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
4103*795d594fSAndroid Build Coastguard Worker   GenerateCodeForCalculationCRC32ValueOfBytes(masm, crc, ptr, length, out);
4104*795d594fSAndroid Build Coastguard Worker }
4105*795d594fSAndroid Build Coastguard Worker 
VisitFP16ToFloat(HInvoke * invoke)4106*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16ToFloat(HInvoke* invoke) {
4107*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4108*795d594fSAndroid Build Coastguard Worker     return;
4109*795d594fSAndroid Build Coastguard Worker   }
4110*795d594fSAndroid Build Coastguard Worker 
4111*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(invoke,
4112*795d594fSAndroid Build Coastguard Worker                                                                 LocationSummary::kNoCall,
4113*795d594fSAndroid Build Coastguard Worker                                                                 kIntrinsified);
4114*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4115*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister());
4116*795d594fSAndroid Build Coastguard Worker }
4117*795d594fSAndroid Build Coastguard Worker 
VisitFP16ToFloat(HInvoke * invoke)4118*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16ToFloat(HInvoke* invoke) {
4119*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasFP16());
4120*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4121*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope scratch_scope(masm);
4122*795d594fSAndroid Build Coastguard Worker   Register bits = InputRegisterAt(invoke, 0);
4123*795d594fSAndroid Build Coastguard Worker   VRegister out = SRegisterFrom(invoke->GetLocations()->Out());
4124*795d594fSAndroid Build Coastguard Worker   VRegister half = scratch_scope.AcquireH();
4125*795d594fSAndroid Build Coastguard Worker   __ Fmov(half, bits);  // ARMv8.2
4126*795d594fSAndroid Build Coastguard Worker   __ Fcvt(out, half);
4127*795d594fSAndroid Build Coastguard Worker }
4128*795d594fSAndroid Build Coastguard Worker 
VisitFP16ToHalf(HInvoke * invoke)4129*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16ToHalf(HInvoke* invoke) {
4130*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4131*795d594fSAndroid Build Coastguard Worker     return;
4132*795d594fSAndroid Build Coastguard Worker   }
4133*795d594fSAndroid Build Coastguard Worker 
4134*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(invoke,
4135*795d594fSAndroid Build Coastguard Worker                                                                 LocationSummary::kNoCall,
4136*795d594fSAndroid Build Coastguard Worker                                                                 kIntrinsified);
4137*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
4138*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
4139*795d594fSAndroid Build Coastguard Worker }
4140*795d594fSAndroid Build Coastguard Worker 
VisitFP16ToHalf(HInvoke * invoke)4141*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16ToHalf(HInvoke* invoke) {
4142*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasFP16());
4143*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4144*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope scratch_scope(masm);
4145*795d594fSAndroid Build Coastguard Worker   VRegister in = SRegisterFrom(invoke->GetLocations()->InAt(0));
4146*795d594fSAndroid Build Coastguard Worker   VRegister half = scratch_scope.AcquireH();
4147*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(invoke->GetLocations()->Out());
4148*795d594fSAndroid Build Coastguard Worker   __ Fcvt(half, in);
4149*795d594fSAndroid Build Coastguard Worker   __ Fmov(out, half);
4150*795d594fSAndroid Build Coastguard Worker   __ Sxth(out, out);  // sign extend due to returning a short type.
4151*795d594fSAndroid Build Coastguard Worker }
4152*795d594fSAndroid Build Coastguard Worker 
4153*795d594fSAndroid Build Coastguard Worker template<typename OP>
GenerateFP16Round(HInvoke * invoke,CodeGeneratorARM64 * const codegen_,MacroAssembler * masm,OP && roundOp)4154*795d594fSAndroid Build Coastguard Worker void GenerateFP16Round(HInvoke* invoke,
4155*795d594fSAndroid Build Coastguard Worker                        CodeGeneratorARM64* const codegen_,
4156*795d594fSAndroid Build Coastguard Worker                        MacroAssembler* masm,
4157*795d594fSAndroid Build Coastguard Worker                        OP&& roundOp) {
4158*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasFP16());
4159*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4160*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope scratch_scope(masm);
4161*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
4162*795d594fSAndroid Build Coastguard Worker   VRegister half = scratch_scope.AcquireH();
4163*795d594fSAndroid Build Coastguard Worker   __ Fmov(half, WRegisterFrom(locations->InAt(0)));
4164*795d594fSAndroid Build Coastguard Worker   roundOp(half, half);
4165*795d594fSAndroid Build Coastguard Worker   __ Fmov(out, half);
4166*795d594fSAndroid Build Coastguard Worker   __ Sxth(out, out);
4167*795d594fSAndroid Build Coastguard Worker }
4168*795d594fSAndroid Build Coastguard Worker 
VisitFP16Floor(HInvoke * invoke)4169*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Floor(HInvoke* invoke) {
4170*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4171*795d594fSAndroid Build Coastguard Worker     return;
4172*795d594fSAndroid Build Coastguard Worker   }
4173*795d594fSAndroid Build Coastguard Worker 
4174*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
4175*795d594fSAndroid Build Coastguard Worker }
4176*795d594fSAndroid Build Coastguard Worker 
VisitFP16Floor(HInvoke * invoke)4177*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Floor(HInvoke* invoke) {
4178*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4179*795d594fSAndroid Build Coastguard Worker   auto roundOp = [masm](const VRegister& out, const VRegister& in) {
4180*795d594fSAndroid Build Coastguard Worker     __ Frintm(out, in);  // Round towards Minus infinity
4181*795d594fSAndroid Build Coastguard Worker   };
4182*795d594fSAndroid Build Coastguard Worker   GenerateFP16Round(invoke, codegen_, masm, roundOp);
4183*795d594fSAndroid Build Coastguard Worker }
4184*795d594fSAndroid Build Coastguard Worker 
VisitFP16Ceil(HInvoke * invoke)4185*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Ceil(HInvoke* invoke) {
4186*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4187*795d594fSAndroid Build Coastguard Worker     return;
4188*795d594fSAndroid Build Coastguard Worker   }
4189*795d594fSAndroid Build Coastguard Worker 
4190*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
4191*795d594fSAndroid Build Coastguard Worker }
4192*795d594fSAndroid Build Coastguard Worker 
VisitFP16Ceil(HInvoke * invoke)4193*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Ceil(HInvoke* invoke) {
4194*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4195*795d594fSAndroid Build Coastguard Worker   auto roundOp = [masm](const VRegister& out, const VRegister& in) {
4196*795d594fSAndroid Build Coastguard Worker     __ Frintp(out, in);  // Round towards Plus infinity
4197*795d594fSAndroid Build Coastguard Worker   };
4198*795d594fSAndroid Build Coastguard Worker   GenerateFP16Round(invoke, codegen_, masm, roundOp);
4199*795d594fSAndroid Build Coastguard Worker }
4200*795d594fSAndroid Build Coastguard Worker 
VisitFP16Rint(HInvoke * invoke)4201*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Rint(HInvoke* invoke) {
4202*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4203*795d594fSAndroid Build Coastguard Worker     return;
4204*795d594fSAndroid Build Coastguard Worker   }
4205*795d594fSAndroid Build Coastguard Worker 
4206*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
4207*795d594fSAndroid Build Coastguard Worker }
4208*795d594fSAndroid Build Coastguard Worker 
VisitFP16Rint(HInvoke * invoke)4209*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Rint(HInvoke* invoke) {
4210*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4211*795d594fSAndroid Build Coastguard Worker   auto roundOp = [masm](const VRegister& out, const VRegister& in) {
4212*795d594fSAndroid Build Coastguard Worker     __ Frintn(out, in);  // Round to nearest, with ties to even
4213*795d594fSAndroid Build Coastguard Worker   };
4214*795d594fSAndroid Build Coastguard Worker   GenerateFP16Round(invoke, codegen_, masm, roundOp);
4215*795d594fSAndroid Build Coastguard Worker }
4216*795d594fSAndroid Build Coastguard Worker 
FP16ComparisonLocations(HInvoke * invoke,ArenaAllocator * allocator_,CodeGeneratorARM64 * codegen_,int requiredTemps)4217*795d594fSAndroid Build Coastguard Worker void FP16ComparisonLocations(HInvoke* invoke,
4218*795d594fSAndroid Build Coastguard Worker                              ArenaAllocator* allocator_,
4219*795d594fSAndroid Build Coastguard Worker                              CodeGeneratorARM64* codegen_,
4220*795d594fSAndroid Build Coastguard Worker                              int requiredTemps) {
4221*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasFP16()) {
4222*795d594fSAndroid Build Coastguard Worker     return;
4223*795d594fSAndroid Build Coastguard Worker   }
4224*795d594fSAndroid Build Coastguard Worker 
4225*795d594fSAndroid Build Coastguard Worker   CreateIntIntToIntLocations(allocator_, invoke);
4226*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < requiredTemps; i++) {
4227*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->AddTemp(Location::RequiresFpuRegister());
4228*795d594fSAndroid Build Coastguard Worker   }
4229*795d594fSAndroid Build Coastguard Worker }
4230*795d594fSAndroid Build Coastguard Worker 
4231*795d594fSAndroid Build Coastguard Worker template<typename OP>
GenerateFP16Compare(HInvoke * invoke,CodeGeneratorARM64 * codegen,MacroAssembler * masm,const OP compareOp)4232*795d594fSAndroid Build Coastguard Worker void GenerateFP16Compare(HInvoke* invoke,
4233*795d594fSAndroid Build Coastguard Worker                          CodeGeneratorARM64* codegen,
4234*795d594fSAndroid Build Coastguard Worker                          MacroAssembler* masm,
4235*795d594fSAndroid Build Coastguard Worker                          const OP compareOp) {
4236*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen->GetInstructionSetFeatures().HasFP16());
4237*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4238*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
4239*795d594fSAndroid Build Coastguard Worker   VRegister half0 = HRegisterFrom(locations->GetTemp(0));
4240*795d594fSAndroid Build Coastguard Worker   VRegister half1 = HRegisterFrom(locations->GetTemp(1));
4241*795d594fSAndroid Build Coastguard Worker   __ Fmov(half0, WRegisterFrom(locations->InAt(0)));
4242*795d594fSAndroid Build Coastguard Worker   __ Fmov(half1, WRegisterFrom(locations->InAt(1)));
4243*795d594fSAndroid Build Coastguard Worker   compareOp(out, half0, half1);
4244*795d594fSAndroid Build Coastguard Worker }
4245*795d594fSAndroid Build Coastguard Worker 
GenerateFP16Compare(HInvoke * invoke,CodeGeneratorARM64 * codegen,MacroAssembler * masm,vixl::aarch64::Condition cond)4246*795d594fSAndroid Build Coastguard Worker static inline void GenerateFP16Compare(HInvoke* invoke,
4247*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorARM64* codegen,
4248*795d594fSAndroid Build Coastguard Worker                                        MacroAssembler* masm,
4249*795d594fSAndroid Build Coastguard Worker                                        vixl::aarch64::Condition cond) {
4250*795d594fSAndroid Build Coastguard Worker   auto compareOp = [masm, cond](const Register out, const VRegister& in0, const VRegister& in1) {
4251*795d594fSAndroid Build Coastguard Worker     __ Fcmp(in0, in1);
4252*795d594fSAndroid Build Coastguard Worker     __ Cset(out, cond);
4253*795d594fSAndroid Build Coastguard Worker   };
4254*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen, masm, compareOp);
4255*795d594fSAndroid Build Coastguard Worker }
4256*795d594fSAndroid Build Coastguard Worker 
VisitFP16Greater(HInvoke * invoke)4257*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Greater(HInvoke* invoke) {
4258*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 2);
4259*795d594fSAndroid Build Coastguard Worker }
4260*795d594fSAndroid Build Coastguard Worker 
VisitFP16Greater(HInvoke * invoke)4261*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Greater(HInvoke* invoke) {
4262*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4263*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen_, masm, gt);
4264*795d594fSAndroid Build Coastguard Worker }
4265*795d594fSAndroid Build Coastguard Worker 
VisitFP16GreaterEquals(HInvoke * invoke)4266*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16GreaterEquals(HInvoke* invoke) {
4267*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 2);
4268*795d594fSAndroid Build Coastguard Worker }
4269*795d594fSAndroid Build Coastguard Worker 
VisitFP16GreaterEquals(HInvoke * invoke)4270*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16GreaterEquals(HInvoke* invoke) {
4271*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4272*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen_, masm, ge);
4273*795d594fSAndroid Build Coastguard Worker }
4274*795d594fSAndroid Build Coastguard Worker 
VisitFP16Less(HInvoke * invoke)4275*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Less(HInvoke* invoke) {
4276*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 2);
4277*795d594fSAndroid Build Coastguard Worker }
4278*795d594fSAndroid Build Coastguard Worker 
VisitFP16Less(HInvoke * invoke)4279*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Less(HInvoke* invoke) {
4280*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4281*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen_, masm, mi);
4282*795d594fSAndroid Build Coastguard Worker }
4283*795d594fSAndroid Build Coastguard Worker 
VisitFP16LessEquals(HInvoke * invoke)4284*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16LessEquals(HInvoke* invoke) {
4285*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 2);
4286*795d594fSAndroid Build Coastguard Worker }
4287*795d594fSAndroid Build Coastguard Worker 
VisitFP16LessEquals(HInvoke * invoke)4288*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16LessEquals(HInvoke* invoke) {
4289*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4290*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen_, masm, ls);
4291*795d594fSAndroid Build Coastguard Worker }
4292*795d594fSAndroid Build Coastguard Worker 
VisitFP16Compare(HInvoke * invoke)4293*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Compare(HInvoke* invoke) {
4294*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 2);
4295*795d594fSAndroid Build Coastguard Worker }
4296*795d594fSAndroid Build Coastguard Worker 
VisitFP16Compare(HInvoke * invoke)4297*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Compare(HInvoke* invoke) {
4298*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4299*795d594fSAndroid Build Coastguard Worker   auto compareOp = [masm](const Register out,
4300*795d594fSAndroid Build Coastguard Worker                           const VRegister& in0,
4301*795d594fSAndroid Build Coastguard Worker                           const VRegister& in1) {
4302*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label end;
4303*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label equal;
4304*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label normal;
4305*795d594fSAndroid Build Coastguard Worker 
4306*795d594fSAndroid Build Coastguard Worker     // The normal cases for this method are:
4307*795d594fSAndroid Build Coastguard Worker     // - in0 > in1 => out = 1
4308*795d594fSAndroid Build Coastguard Worker     // - in0 < in1 => out = -1
4309*795d594fSAndroid Build Coastguard Worker     // - in0 == in1 => out = 0
4310*795d594fSAndroid Build Coastguard Worker     // +/-Infinity are ordered by default so are handled by the normal case.
4311*795d594fSAndroid Build Coastguard Worker     // There are two special cases that Fcmp is insufficient for distinguishing:
4312*795d594fSAndroid Build Coastguard Worker     // - in0 and in1 are +0 and -0 => +0 > -0 so compare encoding instead of value
4313*795d594fSAndroid Build Coastguard Worker     // - in0 or in1 is NaN => manually compare with in0 and in1 separately
4314*795d594fSAndroid Build Coastguard Worker     __ Fcmp(in0, in1);
4315*795d594fSAndroid Build Coastguard Worker     __ B(eq, &equal);  // in0==in1 or +0 -0 case.
4316*795d594fSAndroid Build Coastguard Worker     __ B(vc, &normal);  // in0 and in1 are ordered (not NaN).
4317*795d594fSAndroid Build Coastguard Worker 
4318*795d594fSAndroid Build Coastguard Worker     // Either of the inputs is NaN.
4319*795d594fSAndroid Build Coastguard Worker     // NaN is equal to itself and greater than any other number so:
4320*795d594fSAndroid Build Coastguard Worker     // - if only in0 is NaN => return 1
4321*795d594fSAndroid Build Coastguard Worker     // - if only in1 is NaN => return -1
4322*795d594fSAndroid Build Coastguard Worker     // - if both in0 and in1 are NaN => return 0
4323*795d594fSAndroid Build Coastguard Worker     __ Fcmp(in0, 0.0);
4324*795d594fSAndroid Build Coastguard Worker     __ Mov(out, -1);
4325*795d594fSAndroid Build Coastguard Worker     __ B(vc, &end);  // in0 != NaN => out = -1.
4326*795d594fSAndroid Build Coastguard Worker     __ Fcmp(in1, 0.0);
4327*795d594fSAndroid Build Coastguard Worker     __ Cset(out, vc);  // if in1 != NaN => out = 1, otherwise both are NaNs => out = 0.
4328*795d594fSAndroid Build Coastguard Worker     __ B(&end);
4329*795d594fSAndroid Build Coastguard Worker 
4330*795d594fSAndroid Build Coastguard Worker     // in0 == in1 or if one of the inputs is +0 and the other is -0.
4331*795d594fSAndroid Build Coastguard Worker     __ Bind(&equal);
4332*795d594fSAndroid Build Coastguard Worker     // Compare encoding of in0 and in1 as the denormal fraction of single precision float.
4333*795d594fSAndroid Build Coastguard Worker     // Reverse operand order because -0 > +0 when compared as S registers.
4334*795d594fSAndroid Build Coastguard Worker     // The instruction Fmov(Hregister, Wregister) zero extends the Hregister.
4335*795d594fSAndroid Build Coastguard Worker     // Therefore the value of bits[127:16] will not matter when doing the
4336*795d594fSAndroid Build Coastguard Worker     // below Fcmp as they are set to 0.
4337*795d594fSAndroid Build Coastguard Worker     __ Fcmp(in1.S(), in0.S());
4338*795d594fSAndroid Build Coastguard Worker 
4339*795d594fSAndroid Build Coastguard Worker     __ Bind(&normal);
4340*795d594fSAndroid Build Coastguard Worker     __ Cset(out, gt);  // if in0 > in1 => out = 1, otherwise out = 0.
4341*795d594fSAndroid Build Coastguard Worker                        // Note: could be from equals path or original comparison
4342*795d594fSAndroid Build Coastguard Worker     __ Csinv(out, out, wzr, pl);  // if in0 >= in1 out=out, otherwise out=-1.
4343*795d594fSAndroid Build Coastguard Worker 
4344*795d594fSAndroid Build Coastguard Worker     __ Bind(&end);
4345*795d594fSAndroid Build Coastguard Worker   };
4346*795d594fSAndroid Build Coastguard Worker 
4347*795d594fSAndroid Build Coastguard Worker   GenerateFP16Compare(invoke, codegen_, masm, compareOp);
4348*795d594fSAndroid Build Coastguard Worker }
4349*795d594fSAndroid Build Coastguard Worker 
4350*795d594fSAndroid Build Coastguard Worker const int kFP16NaN = 0x7e00;
4351*795d594fSAndroid Build Coastguard Worker 
GenerateFP16MinMax(HInvoke * invoke,CodeGeneratorARM64 * codegen,MacroAssembler * masm,vixl::aarch64::Condition cond)4352*795d594fSAndroid Build Coastguard Worker static inline void GenerateFP16MinMax(HInvoke* invoke,
4353*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorARM64* codegen,
4354*795d594fSAndroid Build Coastguard Worker                                        MacroAssembler* masm,
4355*795d594fSAndroid Build Coastguard Worker                                        vixl::aarch64::Condition cond) {
4356*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen->GetInstructionSetFeatures().HasFP16());
4357*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4358*795d594fSAndroid Build Coastguard Worker 
4359*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label equal;
4360*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label end;
4361*795d594fSAndroid Build Coastguard Worker 
4362*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
4363*795d594fSAndroid Build Coastguard Worker 
4364*795d594fSAndroid Build Coastguard Worker   Register out = WRegisterFrom(locations->Out());
4365*795d594fSAndroid Build Coastguard Worker   Register in0 = WRegisterFrom(locations->InAt(0));
4366*795d594fSAndroid Build Coastguard Worker   Register in1 = WRegisterFrom(locations->InAt(1));
4367*795d594fSAndroid Build Coastguard Worker   VRegister half0 = HRegisterFrom(locations->GetTemp(0));
4368*795d594fSAndroid Build Coastguard Worker   VRegister half1 = temps.AcquireH();
4369*795d594fSAndroid Build Coastguard Worker 
4370*795d594fSAndroid Build Coastguard Worker   // The normal cases for this method are:
4371*795d594fSAndroid Build Coastguard Worker   // - in0.h == in1.h => out = in0 or in1
4372*795d594fSAndroid Build Coastguard Worker   // - in0.h <cond> in1.h => out = in0
4373*795d594fSAndroid Build Coastguard Worker   // - in0.h <!cond> in1.h => out = in1
4374*795d594fSAndroid Build Coastguard Worker   // +/-Infinity are ordered by default so are handled by the normal case.
4375*795d594fSAndroid Build Coastguard Worker   // There are two special cases that Fcmp is insufficient for distinguishing:
4376*795d594fSAndroid Build Coastguard Worker   // - in0 and in1 are +0 and -0 => +0 > -0 so compare encoding instead of value
4377*795d594fSAndroid Build Coastguard Worker   // - in0 or in1 is NaN => out = NaN
4378*795d594fSAndroid Build Coastguard Worker   __ Fmov(half0, in0);
4379*795d594fSAndroid Build Coastguard Worker   __ Fmov(half1, in1);
4380*795d594fSAndroid Build Coastguard Worker   __ Fcmp(half0, half1);
4381*795d594fSAndroid Build Coastguard Worker   __ B(eq, &equal);  // half0 = half1 or +0/-0 case.
4382*795d594fSAndroid Build Coastguard Worker   __ Csel(out, in0, in1, cond);  // if half0 <cond> half1 => out = in0, otherwise out = in1.
4383*795d594fSAndroid Build Coastguard Worker   __ B(vc, &end);  // None of the inputs were NaN.
4384*795d594fSAndroid Build Coastguard Worker 
4385*795d594fSAndroid Build Coastguard Worker   // Atleast one input was NaN.
4386*795d594fSAndroid Build Coastguard Worker   __ Mov(out, kFP16NaN);  // out=NaN.
4387*795d594fSAndroid Build Coastguard Worker   __ B(&end);
4388*795d594fSAndroid Build Coastguard Worker 
4389*795d594fSAndroid Build Coastguard Worker   // in0 == in1 or if one of the inputs is +0 and the other is -0.
4390*795d594fSAndroid Build Coastguard Worker   __ Bind(&equal);
4391*795d594fSAndroid Build Coastguard Worker   // Fcmp cannot normally distinguish +0 and -0 so compare encoding.
4392*795d594fSAndroid Build Coastguard Worker   // Encoding is compared as the denormal fraction of a Single.
4393*795d594fSAndroid Build Coastguard Worker   // Note: encoding of -0 > encoding of +0 despite +0 > -0 so in0 and in1 are swapped.
4394*795d594fSAndroid Build Coastguard Worker   // Note: The instruction Fmov(Hregister, Wregister) zero extends the Hregister.
4395*795d594fSAndroid Build Coastguard Worker   __ Fcmp(half1.S(), half0.S());
4396*795d594fSAndroid Build Coastguard Worker 
4397*795d594fSAndroid Build Coastguard Worker   __ Csel(out, in0, in1, cond);  // if half0 <cond> half1 => out = in0, otherwise out = in1.
4398*795d594fSAndroid Build Coastguard Worker 
4399*795d594fSAndroid Build Coastguard Worker   __ Bind(&end);
4400*795d594fSAndroid Build Coastguard Worker }
4401*795d594fSAndroid Build Coastguard Worker 
VisitFP16Min(HInvoke * invoke)4402*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Min(HInvoke* invoke) {
4403*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 1);
4404*795d594fSAndroid Build Coastguard Worker }
4405*795d594fSAndroid Build Coastguard Worker 
VisitFP16Min(HInvoke * invoke)4406*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Min(HInvoke* invoke) {
4407*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasFP16());
4408*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4409*795d594fSAndroid Build Coastguard Worker   GenerateFP16MinMax(invoke, codegen_, masm, mi);
4410*795d594fSAndroid Build Coastguard Worker }
4411*795d594fSAndroid Build Coastguard Worker 
VisitFP16Max(HInvoke * invoke)4412*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitFP16Max(HInvoke* invoke) {
4413*795d594fSAndroid Build Coastguard Worker   FP16ComparisonLocations(invoke, allocator_, codegen_, 1);
4414*795d594fSAndroid Build Coastguard Worker }
4415*795d594fSAndroid Build Coastguard Worker 
VisitFP16Max(HInvoke * invoke)4416*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitFP16Max(HInvoke* invoke) {
4417*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasFP16());
4418*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = GetVIXLAssembler();
4419*795d594fSAndroid Build Coastguard Worker   GenerateFP16MinMax(invoke, codegen_, masm, gt);
4420*795d594fSAndroid Build Coastguard Worker }
4421*795d594fSAndroid Build Coastguard Worker 
GenerateDivideUnsigned(HInvoke * invoke,CodeGeneratorARM64 * codegen)4422*795d594fSAndroid Build Coastguard Worker static void GenerateDivideUnsigned(HInvoke* invoke, CodeGeneratorARM64* codegen) {
4423*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4424*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4425*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4426*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
4427*795d594fSAndroid Build Coastguard Worker 
4428*795d594fSAndroid Build Coastguard Worker   Register dividend = RegisterFrom(locations->InAt(0), type);
4429*795d594fSAndroid Build Coastguard Worker   Register divisor = RegisterFrom(locations->InAt(1), type);
4430*795d594fSAndroid Build Coastguard Worker   Register out = RegisterFrom(locations->Out(), type);
4431*795d594fSAndroid Build Coastguard Worker 
4432*795d594fSAndroid Build Coastguard Worker   // Check if divisor is zero, bail to managed implementation to handle.
4433*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
4434*795d594fSAndroid Build Coastguard Worker       new (codegen->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
4435*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4436*795d594fSAndroid Build Coastguard Worker   __ Cbz(divisor, slow_path->GetEntryLabel());
4437*795d594fSAndroid Build Coastguard Worker 
4438*795d594fSAndroid Build Coastguard Worker   __ Udiv(out, dividend, divisor);
4439*795d594fSAndroid Build Coastguard Worker 
4440*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4441*795d594fSAndroid Build Coastguard Worker }
4442*795d594fSAndroid Build Coastguard Worker 
VisitIntegerDivideUnsigned(HInvoke * invoke)4443*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) {
4444*795d594fSAndroid Build Coastguard Worker   CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
4445*795d594fSAndroid Build Coastguard Worker }
4446*795d594fSAndroid Build Coastguard Worker 
VisitIntegerDivideUnsigned(HInvoke * invoke)4447*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) {
4448*795d594fSAndroid Build Coastguard Worker   GenerateDivideUnsigned(invoke, codegen_);
4449*795d594fSAndroid Build Coastguard Worker }
4450*795d594fSAndroid Build Coastguard Worker 
VisitLongDivideUnsigned(HInvoke * invoke)4451*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitLongDivideUnsigned(HInvoke* invoke) {
4452*795d594fSAndroid Build Coastguard Worker   CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
4453*795d594fSAndroid Build Coastguard Worker }
4454*795d594fSAndroid Build Coastguard Worker 
VisitLongDivideUnsigned(HInvoke * invoke)4455*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitLongDivideUnsigned(HInvoke* invoke) {
4456*795d594fSAndroid Build Coastguard Worker   GenerateDivideUnsigned(invoke, codegen_);
4457*795d594fSAndroid Build Coastguard Worker }
4458*795d594fSAndroid Build Coastguard Worker 
VisitMathMultiplyHigh(HInvoke * invoke)4459*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathMultiplyHigh(HInvoke* invoke) {
4460*795d594fSAndroid Build Coastguard Worker   CreateIntIntToIntLocations(allocator_, invoke);
4461*795d594fSAndroid Build Coastguard Worker }
4462*795d594fSAndroid Build Coastguard Worker 
VisitMathMultiplyHigh(HInvoke * invoke)4463*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathMultiplyHigh(HInvoke* invoke) {
4464*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4465*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen_->GetVIXLAssembler();
4466*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4467*795d594fSAndroid Build Coastguard Worker   DCHECK(type == DataType::Type::kInt64);
4468*795d594fSAndroid Build Coastguard Worker 
4469*795d594fSAndroid Build Coastguard Worker   Register x = RegisterFrom(locations->InAt(0), type);
4470*795d594fSAndroid Build Coastguard Worker   Register y = RegisterFrom(locations->InAt(1), type);
4471*795d594fSAndroid Build Coastguard Worker   Register out = RegisterFrom(locations->Out(), type);
4472*795d594fSAndroid Build Coastguard Worker 
4473*795d594fSAndroid Build Coastguard Worker   __ Smulh(out, x, y);
4474*795d594fSAndroid Build Coastguard Worker }
4475*795d594fSAndroid Build Coastguard Worker 
GenerateMathFma(HInvoke * invoke,CodeGeneratorARM64 * codegen)4476*795d594fSAndroid Build Coastguard Worker static void GenerateMathFma(HInvoke* invoke, CodeGeneratorARM64* codegen) {
4477*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4478*795d594fSAndroid Build Coastguard Worker 
4479*795d594fSAndroid Build Coastguard Worker   VRegister n = helpers::InputFPRegisterAt(invoke, 0);
4480*795d594fSAndroid Build Coastguard Worker   VRegister m = helpers::InputFPRegisterAt(invoke, 1);
4481*795d594fSAndroid Build Coastguard Worker   VRegister a = helpers::InputFPRegisterAt(invoke, 2);
4482*795d594fSAndroid Build Coastguard Worker   VRegister out = helpers::OutputFPRegister(invoke);
4483*795d594fSAndroid Build Coastguard Worker 
4484*795d594fSAndroid Build Coastguard Worker   __ Fmadd(out, n, m, a);
4485*795d594fSAndroid Build Coastguard Worker }
4486*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaDouble(HInvoke * invoke)4487*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathFmaDouble(HInvoke* invoke) {
4488*795d594fSAndroid Build Coastguard Worker   CreateFPFPFPToFPLocations(allocator_, invoke);
4489*795d594fSAndroid Build Coastguard Worker }
4490*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaDouble(HInvoke * invoke)4491*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathFmaDouble(HInvoke* invoke) {
4492*795d594fSAndroid Build Coastguard Worker   GenerateMathFma(invoke, codegen_);
4493*795d594fSAndroid Build Coastguard Worker }
4494*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaFloat(HInvoke * invoke)4495*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMathFmaFloat(HInvoke* invoke) {
4496*795d594fSAndroid Build Coastguard Worker   CreateFPFPFPToFPLocations(allocator_, invoke);
4497*795d594fSAndroid Build Coastguard Worker }
4498*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaFloat(HInvoke * invoke)4499*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMathFmaFloat(HInvoke* invoke) {
4500*795d594fSAndroid Build Coastguard Worker   GenerateMathFma(invoke, codegen_);
4501*795d594fSAndroid Build Coastguard Worker }
4502*795d594fSAndroid Build Coastguard Worker 
4503*795d594fSAndroid Build Coastguard Worker class VarHandleSlowPathARM64 : public IntrinsicSlowPathARM64 {
4504*795d594fSAndroid Build Coastguard Worker  public:
VarHandleSlowPathARM64(HInvoke * invoke,std::memory_order order)4505*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64(HInvoke* invoke, std::memory_order order)
4506*795d594fSAndroid Build Coastguard Worker       : IntrinsicSlowPathARM64(invoke),
4507*795d594fSAndroid Build Coastguard Worker         order_(order),
4508*795d594fSAndroid Build Coastguard Worker         return_success_(false),
4509*795d594fSAndroid Build Coastguard Worker         strong_(false),
4510*795d594fSAndroid Build Coastguard Worker         get_and_update_op_(GetAndUpdateOp::kAdd) {
4511*795d594fSAndroid Build Coastguard Worker   }
4512*795d594fSAndroid Build Coastguard Worker 
GetByteArrayViewCheckLabel()4513*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* GetByteArrayViewCheckLabel() {
4514*795d594fSAndroid Build Coastguard Worker     return &byte_array_view_check_label_;
4515*795d594fSAndroid Build Coastguard Worker   }
4516*795d594fSAndroid Build Coastguard Worker 
GetNativeByteOrderLabel()4517*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* GetNativeByteOrderLabel() {
4518*795d594fSAndroid Build Coastguard Worker     return &native_byte_order_label_;
4519*795d594fSAndroid Build Coastguard Worker   }
4520*795d594fSAndroid Build Coastguard Worker 
SetCompareAndSetOrExchangeArgs(bool return_success,bool strong)4521*795d594fSAndroid Build Coastguard Worker   void SetCompareAndSetOrExchangeArgs(bool return_success, bool strong) {
4522*795d594fSAndroid Build Coastguard Worker     if (return_success) {
4523*795d594fSAndroid Build Coastguard Worker       DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kCompareAndSet);
4524*795d594fSAndroid Build Coastguard Worker     } else {
4525*795d594fSAndroid Build Coastguard Worker       DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kCompareAndExchange);
4526*795d594fSAndroid Build Coastguard Worker     }
4527*795d594fSAndroid Build Coastguard Worker     return_success_ = return_success;
4528*795d594fSAndroid Build Coastguard Worker     strong_ = strong;
4529*795d594fSAndroid Build Coastguard Worker   }
4530*795d594fSAndroid Build Coastguard Worker 
SetGetAndUpdateOp(GetAndUpdateOp get_and_update_op)4531*795d594fSAndroid Build Coastguard Worker   void SetGetAndUpdateOp(GetAndUpdateOp get_and_update_op) {
4532*795d594fSAndroid Build Coastguard Worker     DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kGetAndUpdate);
4533*795d594fSAndroid Build Coastguard Worker     get_and_update_op_ = get_and_update_op;
4534*795d594fSAndroid Build Coastguard Worker   }
4535*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen_in)4536*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen_in) override {
4537*795d594fSAndroid Build Coastguard Worker     if (GetByteArrayViewCheckLabel()->IsLinked()) {
4538*795d594fSAndroid Build Coastguard Worker       EmitByteArrayViewCode(codegen_in);
4539*795d594fSAndroid Build Coastguard Worker     }
4540*795d594fSAndroid Build Coastguard Worker     IntrinsicSlowPathARM64::EmitNativeCode(codegen_in);
4541*795d594fSAndroid Build Coastguard Worker   }
4542*795d594fSAndroid Build Coastguard Worker 
4543*795d594fSAndroid Build Coastguard Worker  private:
GetInvoke() const4544*795d594fSAndroid Build Coastguard Worker   HInvoke* GetInvoke() const {
4545*795d594fSAndroid Build Coastguard Worker     return GetInstruction()->AsInvoke();
4546*795d594fSAndroid Build Coastguard Worker   }
4547*795d594fSAndroid Build Coastguard Worker 
GetAccessModeTemplate() const4548*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessModeTemplate GetAccessModeTemplate() const {
4549*795d594fSAndroid Build Coastguard Worker     return mirror::VarHandle::GetAccessModeTemplateByIntrinsic(GetInvoke()->GetIntrinsic());
4550*795d594fSAndroid Build Coastguard Worker   }
4551*795d594fSAndroid Build Coastguard Worker 
4552*795d594fSAndroid Build Coastguard Worker   void EmitByteArrayViewCode(CodeGenerator* codegen_in);
4553*795d594fSAndroid Build Coastguard Worker 
4554*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label byte_array_view_check_label_;
4555*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label native_byte_order_label_;
4556*795d594fSAndroid Build Coastguard Worker   // Shared parameter for all VarHandle intrinsics.
4557*795d594fSAndroid Build Coastguard Worker   std::memory_order order_;
4558*795d594fSAndroid Build Coastguard Worker   // Extra arguments for GenerateVarHandleCompareAndSetOrExchange().
4559*795d594fSAndroid Build Coastguard Worker   bool return_success_;
4560*795d594fSAndroid Build Coastguard Worker   bool strong_;
4561*795d594fSAndroid Build Coastguard Worker   // Extra argument for GenerateVarHandleGetAndUpdate().
4562*795d594fSAndroid Build Coastguard Worker   GetAndUpdateOp get_and_update_op_;
4563*795d594fSAndroid Build Coastguard Worker };
4564*795d594fSAndroid Build Coastguard Worker 
4565*795d594fSAndroid Build Coastguard Worker // Generate subtype check without read barriers.
GenerateSubTypeObjectCheckNoReadBarrier(CodeGeneratorARM64 * codegen,SlowPathCodeARM64 * slow_path,Register object,Register type,bool object_can_be_null=true)4566*795d594fSAndroid Build Coastguard Worker static void GenerateSubTypeObjectCheckNoReadBarrier(CodeGeneratorARM64* codegen,
4567*795d594fSAndroid Build Coastguard Worker                                                     SlowPathCodeARM64* slow_path,
4568*795d594fSAndroid Build Coastguard Worker                                                     Register object,
4569*795d594fSAndroid Build Coastguard Worker                                                     Register type,
4570*795d594fSAndroid Build Coastguard Worker                                                     bool object_can_be_null = true) {
4571*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4572*795d594fSAndroid Build Coastguard Worker 
4573*795d594fSAndroid Build Coastguard Worker   const MemberOffset class_offset = mirror::Object::ClassOffset();
4574*795d594fSAndroid Build Coastguard Worker   const MemberOffset super_class_offset = mirror::Class::SuperClassOffset();
4575*795d594fSAndroid Build Coastguard Worker 
4576*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label success;
4577*795d594fSAndroid Build Coastguard Worker   if (object_can_be_null) {
4578*795d594fSAndroid Build Coastguard Worker     __ Cbz(object, &success);
4579*795d594fSAndroid Build Coastguard Worker   }
4580*795d594fSAndroid Build Coastguard Worker 
4581*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
4582*795d594fSAndroid Build Coastguard Worker   Register temp = temps.AcquireW();
4583*795d594fSAndroid Build Coastguard Worker 
4584*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(object, class_offset.Int32Value()));
4585*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp);
4586*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label loop;
4587*795d594fSAndroid Build Coastguard Worker   __ Bind(&loop);
4588*795d594fSAndroid Build Coastguard Worker   __ Cmp(type, temp);
4589*795d594fSAndroid Build Coastguard Worker   __ B(&success, eq);
4590*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(temp, super_class_offset.Int32Value()));
4591*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp);
4592*795d594fSAndroid Build Coastguard Worker   __ Cbz(temp, slow_path->GetEntryLabel());
4593*795d594fSAndroid Build Coastguard Worker   __ B(&loop);
4594*795d594fSAndroid Build Coastguard Worker   __ Bind(&success);
4595*795d594fSAndroid Build Coastguard Worker }
4596*795d594fSAndroid Build Coastguard Worker 
4597*795d594fSAndroid Build Coastguard Worker // Check access mode and the primitive type from VarHandle.varType.
4598*795d594fSAndroid Build Coastguard Worker // Check reference arguments against the VarHandle.varType; for references this is a subclass
4599*795d594fSAndroid Build Coastguard Worker // check without read barrier, so it can have false negatives which we handle in the slow path.
GenerateVarHandleAccessModeAndVarTypeChecks(HInvoke * invoke,CodeGeneratorARM64 * codegen,SlowPathCodeARM64 * slow_path,DataType::Type type)4600*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleAccessModeAndVarTypeChecks(HInvoke* invoke,
4601*795d594fSAndroid Build Coastguard Worker                                                         CodeGeneratorARM64* codegen,
4602*795d594fSAndroid Build Coastguard Worker                                                         SlowPathCodeARM64* slow_path,
4603*795d594fSAndroid Build Coastguard Worker                                                         DataType::Type type) {
4604*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessMode access_mode =
4605*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic());
4606*795d594fSAndroid Build Coastguard Worker   Primitive::Type primitive_type = DataTypeToPrimitive(type);
4607*795d594fSAndroid Build Coastguard Worker 
4608*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4609*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
4610*795d594fSAndroid Build Coastguard Worker 
4611*795d594fSAndroid Build Coastguard Worker   const MemberOffset var_type_offset = mirror::VarHandle::VarTypeOffset();
4612*795d594fSAndroid Build Coastguard Worker   const MemberOffset access_mode_bit_mask_offset = mirror::VarHandle::AccessModesBitMaskOffset();
4613*795d594fSAndroid Build Coastguard Worker   const MemberOffset primitive_type_offset = mirror::Class::PrimitiveTypeOffset();
4614*795d594fSAndroid Build Coastguard Worker 
4615*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
4616*795d594fSAndroid Build Coastguard Worker   Register var_type_no_rb = temps.AcquireW();
4617*795d594fSAndroid Build Coastguard Worker   Register temp2 = temps.AcquireW();
4618*795d594fSAndroid Build Coastguard Worker 
4619*795d594fSAndroid Build Coastguard Worker   // Check that the operation is permitted and the primitive type of varhandle.varType.
4620*795d594fSAndroid Build Coastguard Worker   // We do not need a read barrier when loading a reference only for loading constant
4621*795d594fSAndroid Build Coastguard Worker   // primitive field through the reference. Use LDP to load the fields together.
4622*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(var_type_offset.Int32Value() + 4, access_mode_bit_mask_offset.Int32Value());
4623*795d594fSAndroid Build Coastguard Worker   __ Ldp(var_type_no_rb, temp2, HeapOperand(varhandle, var_type_offset.Int32Value()));
4624*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(var_type_no_rb);
4625*795d594fSAndroid Build Coastguard Worker   __ Tbz(temp2, static_cast<uint32_t>(access_mode), slow_path->GetEntryLabel());
4626*795d594fSAndroid Build Coastguard Worker   __ Ldrh(temp2, HeapOperand(var_type_no_rb, primitive_type_offset.Int32Value()));
4627*795d594fSAndroid Build Coastguard Worker   if (primitive_type == Primitive::kPrimNot) {
4628*795d594fSAndroid Build Coastguard Worker     static_assert(Primitive::kPrimNot == 0);
4629*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp2, slow_path->GetEntryLabel());
4630*795d594fSAndroid Build Coastguard Worker   } else {
4631*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp2, static_cast<uint16_t>(primitive_type));
4632*795d594fSAndroid Build Coastguard Worker     __ B(slow_path->GetEntryLabel(), ne);
4633*795d594fSAndroid Build Coastguard Worker   }
4634*795d594fSAndroid Build Coastguard Worker 
4635*795d594fSAndroid Build Coastguard Worker   temps.Release(temp2);
4636*795d594fSAndroid Build Coastguard Worker 
4637*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
4638*795d594fSAndroid Build Coastguard Worker     // Check reference arguments against the varType.
4639*795d594fSAndroid Build Coastguard Worker     // False negatives due to varType being an interface or array type
4640*795d594fSAndroid Build Coastguard Worker     // or due to the missing read barrier are handled by the slow path.
4641*795d594fSAndroid Build Coastguard Worker     size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4642*795d594fSAndroid Build Coastguard Worker     uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
4643*795d594fSAndroid Build Coastguard Worker     uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4644*795d594fSAndroid Build Coastguard Worker     for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
4645*795d594fSAndroid Build Coastguard Worker       HInstruction* arg = invoke->InputAt(arg_index);
4646*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(arg->GetType(), DataType::Type::kReference);
4647*795d594fSAndroid Build Coastguard Worker       if (!arg->IsNullConstant()) {
4648*795d594fSAndroid Build Coastguard Worker         Register arg_reg = WRegisterFrom(invoke->GetLocations()->InAt(arg_index));
4649*795d594fSAndroid Build Coastguard Worker         GenerateSubTypeObjectCheckNoReadBarrier(codegen, slow_path, arg_reg, var_type_no_rb);
4650*795d594fSAndroid Build Coastguard Worker       }
4651*795d594fSAndroid Build Coastguard Worker     }
4652*795d594fSAndroid Build Coastguard Worker   }
4653*795d594fSAndroid Build Coastguard Worker }
4654*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleStaticFieldCheck(HInvoke * invoke,CodeGeneratorARM64 * codegen,SlowPathCodeARM64 * slow_path)4655*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleStaticFieldCheck(HInvoke* invoke,
4656*795d594fSAndroid Build Coastguard Worker                                               CodeGeneratorARM64* codegen,
4657*795d594fSAndroid Build Coastguard Worker                                               SlowPathCodeARM64* slow_path) {
4658*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4659*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
4660*795d594fSAndroid Build Coastguard Worker 
4661*795d594fSAndroid Build Coastguard Worker   const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
4662*795d594fSAndroid Build Coastguard Worker 
4663*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
4664*795d594fSAndroid Build Coastguard Worker   Register temp = temps.AcquireW();
4665*795d594fSAndroid Build Coastguard Worker 
4666*795d594fSAndroid Build Coastguard Worker   // Check that the VarHandle references a static field by checking that coordinateType0 == null.
4667*795d594fSAndroid Build Coastguard Worker   // Do not emit read barrier (or unpoison the reference) for comparing to null.
4668*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(varhandle, coordinate_type0_offset.Int32Value()));
4669*795d594fSAndroid Build Coastguard Worker   __ Cbnz(temp, slow_path->GetEntryLabel());
4670*795d594fSAndroid Build Coastguard Worker }
4671*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleInstanceFieldChecks(HInvoke * invoke,CodeGeneratorARM64 * codegen,SlowPathCodeARM64 * slow_path)4672*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
4673*795d594fSAndroid Build Coastguard Worker                                                  CodeGeneratorARM64* codegen,
4674*795d594fSAndroid Build Coastguard Worker                                                  SlowPathCodeARM64* slow_path) {
4675*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
4676*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4677*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
4678*795d594fSAndroid Build Coastguard Worker   Register object = InputRegisterAt(invoke, 1);
4679*795d594fSAndroid Build Coastguard Worker 
4680*795d594fSAndroid Build Coastguard Worker   const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
4681*795d594fSAndroid Build Coastguard Worker   const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
4682*795d594fSAndroid Build Coastguard Worker 
4683*795d594fSAndroid Build Coastguard Worker   // Null-check the object.
4684*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSkipObjectNullCheck()) {
4685*795d594fSAndroid Build Coastguard Worker     __ Cbz(object, slow_path->GetEntryLabel());
4686*795d594fSAndroid Build Coastguard Worker   }
4687*795d594fSAndroid Build Coastguard Worker 
4688*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetUseKnownImageVarHandle()) {
4689*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
4690*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
4691*795d594fSAndroid Build Coastguard Worker     Register temp2 = temps.AcquireW();
4692*795d594fSAndroid Build Coastguard Worker 
4693*795d594fSAndroid Build Coastguard Worker     // Check that the VarHandle references an instance field by checking that
4694*795d594fSAndroid Build Coastguard Worker     // coordinateType1 == null. coordinateType0 should not be null, but this is handled by the
4695*795d594fSAndroid Build Coastguard Worker     // type compatibility check with the source object's type, which will fail for null.
4696*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(coordinate_type0_offset.Int32Value() + 4, coordinate_type1_offset.Int32Value());
4697*795d594fSAndroid Build Coastguard Worker     __ Ldp(temp, temp2, HeapOperand(varhandle, coordinate_type0_offset.Int32Value()));
4698*795d594fSAndroid Build Coastguard Worker     codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp);
4699*795d594fSAndroid Build Coastguard Worker     // No need for read barrier or unpoisoning of coordinateType1 for comparison with null.
4700*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp2, slow_path->GetEntryLabel());
4701*795d594fSAndroid Build Coastguard Worker 
4702*795d594fSAndroid Build Coastguard Worker     // Check that the object has the correct type.
4703*795d594fSAndroid Build Coastguard Worker     // We deliberately avoid the read barrier, letting the slow path handle the false negatives.
4704*795d594fSAndroid Build Coastguard Worker     temps.Release(temp2);  // Needed by GenerateSubTypeObjectCheckNoReadBarrier().
4705*795d594fSAndroid Build Coastguard Worker     GenerateSubTypeObjectCheckNoReadBarrier(
4706*795d594fSAndroid Build Coastguard Worker         codegen, slow_path, object, temp, /*object_can_be_null=*/ false);
4707*795d594fSAndroid Build Coastguard Worker   }
4708*795d594fSAndroid Build Coastguard Worker }
4709*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleArrayChecks(HInvoke * invoke,CodeGeneratorARM64 * codegen,VarHandleSlowPathARM64 * slow_path)4710*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleArrayChecks(HInvoke* invoke,
4711*795d594fSAndroid Build Coastguard Worker                                          CodeGeneratorARM64* codegen,
4712*795d594fSAndroid Build Coastguard Worker                                          VarHandleSlowPathARM64* slow_path) {
4713*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
4714*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4715*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
4716*795d594fSAndroid Build Coastguard Worker   Register object = InputRegisterAt(invoke, 1);
4717*795d594fSAndroid Build Coastguard Worker   Register index = InputRegisterAt(invoke, 2);
4718*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type =
4719*795d594fSAndroid Build Coastguard Worker       GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
4720*795d594fSAndroid Build Coastguard Worker   Primitive::Type primitive_type = DataTypeToPrimitive(value_type);
4721*795d594fSAndroid Build Coastguard Worker 
4722*795d594fSAndroid Build Coastguard Worker   const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
4723*795d594fSAndroid Build Coastguard Worker   const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
4724*795d594fSAndroid Build Coastguard Worker   const MemberOffset component_type_offset = mirror::Class::ComponentTypeOffset();
4725*795d594fSAndroid Build Coastguard Worker   const MemberOffset primitive_type_offset = mirror::Class::PrimitiveTypeOffset();
4726*795d594fSAndroid Build Coastguard Worker   const MemberOffset class_offset = mirror::Object::ClassOffset();
4727*795d594fSAndroid Build Coastguard Worker   const MemberOffset array_length_offset = mirror::Array::LengthOffset();
4728*795d594fSAndroid Build Coastguard Worker 
4729*795d594fSAndroid Build Coastguard Worker   // Null-check the object.
4730*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSkipObjectNullCheck()) {
4731*795d594fSAndroid Build Coastguard Worker     __ Cbz(object, slow_path->GetEntryLabel());
4732*795d594fSAndroid Build Coastguard Worker   }
4733*795d594fSAndroid Build Coastguard Worker 
4734*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
4735*795d594fSAndroid Build Coastguard Worker   Register temp = temps.AcquireW();
4736*795d594fSAndroid Build Coastguard Worker   Register temp2 = temps.AcquireW();
4737*795d594fSAndroid Build Coastguard Worker 
4738*795d594fSAndroid Build Coastguard Worker   // Check that the VarHandle references an array, byte array view or ByteBuffer by checking
4739*795d594fSAndroid Build Coastguard Worker   // that coordinateType1 != null. If that's true, coordinateType1 shall be int.class and
4740*795d594fSAndroid Build Coastguard Worker   // coordinateType0 shall not be null but we do not explicitly verify that.
4741*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(coordinate_type0_offset.Int32Value() + 4, coordinate_type1_offset.Int32Value());
4742*795d594fSAndroid Build Coastguard Worker   __ Ldp(temp, temp2, HeapOperand(varhandle, coordinate_type0_offset.Int32Value()));
4743*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp);
4744*795d594fSAndroid Build Coastguard Worker   // No need for read barrier or unpoisoning of coordinateType1 for comparison with null.
4745*795d594fSAndroid Build Coastguard Worker   __ Cbz(temp2, slow_path->GetEntryLabel());
4746*795d594fSAndroid Build Coastguard Worker 
4747*795d594fSAndroid Build Coastguard Worker   // Check object class against componentType0.
4748*795d594fSAndroid Build Coastguard Worker   //
4749*795d594fSAndroid Build Coastguard Worker   // This is an exact check and we defer other cases to the runtime. This includes
4750*795d594fSAndroid Build Coastguard Worker   // conversion to array of superclass references, which is valid but subsequently
4751*795d594fSAndroid Build Coastguard Worker   // requires all update operations to check that the value can indeed be stored.
4752*795d594fSAndroid Build Coastguard Worker   // We do not want to perform such extra checks in the intrinsified code.
4753*795d594fSAndroid Build Coastguard Worker   //
4754*795d594fSAndroid Build Coastguard Worker   // We do this check without read barrier, so there can be false negatives which we
4755*795d594fSAndroid Build Coastguard Worker   // defer to the slow path. There shall be no false negatives for array classes in the
4756*795d594fSAndroid Build Coastguard Worker   // boot image (including Object[] and primitive arrays) because they are non-movable.
4757*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp2, HeapOperand(object, class_offset.Int32Value()));
4758*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp2);
4759*795d594fSAndroid Build Coastguard Worker   __ Cmp(temp, temp2);
4760*795d594fSAndroid Build Coastguard Worker   __ B(slow_path->GetEntryLabel(), ne);
4761*795d594fSAndroid Build Coastguard Worker 
4762*795d594fSAndroid Build Coastguard Worker   // Check that the coordinateType0 is an array type. We do not need a read barrier
4763*795d594fSAndroid Build Coastguard Worker   // for loading constant reference fields (or chains of them) for comparison with null,
4764*795d594fSAndroid Build Coastguard Worker   // nor for finally loading a constant primitive field (primitive type) below.
4765*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp2, HeapOperand(temp, component_type_offset.Int32Value()));
4766*795d594fSAndroid Build Coastguard Worker   codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp2);
4767*795d594fSAndroid Build Coastguard Worker   __ Cbz(temp2, slow_path->GetEntryLabel());
4768*795d594fSAndroid Build Coastguard Worker 
4769*795d594fSAndroid Build Coastguard Worker   // Check that the array component type matches the primitive type.
4770*795d594fSAndroid Build Coastguard Worker   __ Ldrh(temp2, HeapOperand(temp2, primitive_type_offset.Int32Value()));
4771*795d594fSAndroid Build Coastguard Worker   if (primitive_type == Primitive::kPrimNot) {
4772*795d594fSAndroid Build Coastguard Worker     static_assert(Primitive::kPrimNot == 0);
4773*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp2, slow_path->GetEntryLabel());
4774*795d594fSAndroid Build Coastguard Worker   } else {
4775*795d594fSAndroid Build Coastguard Worker     // With the exception of `kPrimNot` (handled above), `kPrimByte` and `kPrimBoolean`,
4776*795d594fSAndroid Build Coastguard Worker     // we shall check for a byte array view in the slow path.
4777*795d594fSAndroid Build Coastguard Worker     // The check requires the ByteArrayViewVarHandle.class to be in the boot image,
4778*795d594fSAndroid Build Coastguard Worker     // so we cannot emit that if we're JITting without boot image.
4779*795d594fSAndroid Build Coastguard Worker     bool boot_image_available =
4780*795d594fSAndroid Build Coastguard Worker         codegen->GetCompilerOptions().IsBootImage() ||
4781*795d594fSAndroid Build Coastguard Worker         !Runtime::Current()->GetHeap()->GetBootImageSpaces().empty();
4782*795d594fSAndroid Build Coastguard Worker     bool can_be_view = (DataType::Size(value_type) != 1u) && boot_image_available;
4783*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Label* slow_path_label =
4784*795d594fSAndroid Build Coastguard Worker         can_be_view ? slow_path->GetByteArrayViewCheckLabel() : slow_path->GetEntryLabel();
4785*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp2, static_cast<uint16_t>(primitive_type));
4786*795d594fSAndroid Build Coastguard Worker     __ B(slow_path_label, ne);
4787*795d594fSAndroid Build Coastguard Worker   }
4788*795d594fSAndroid Build Coastguard Worker 
4789*795d594fSAndroid Build Coastguard Worker   // Check for array index out of bounds.
4790*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(object, array_length_offset.Int32Value()));
4791*795d594fSAndroid Build Coastguard Worker   __ Cmp(index, temp);
4792*795d594fSAndroid Build Coastguard Worker   __ B(slow_path->GetEntryLabel(), hs);
4793*795d594fSAndroid Build Coastguard Worker }
4794*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleCoordinateChecks(HInvoke * invoke,CodeGeneratorARM64 * codegen,VarHandleSlowPathARM64 * slow_path)4795*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCoordinateChecks(HInvoke* invoke,
4796*795d594fSAndroid Build Coastguard Worker                                               CodeGeneratorARM64* codegen,
4797*795d594fSAndroid Build Coastguard Worker                                               VarHandleSlowPathARM64* slow_path) {
4798*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4799*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 0u) {
4800*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleStaticFieldCheck(invoke, codegen, slow_path);
4801*795d594fSAndroid Build Coastguard Worker   } else if (expected_coordinates_count == 1u) {
4802*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleInstanceFieldChecks(invoke, codegen, slow_path);
4803*795d594fSAndroid Build Coastguard Worker   } else {
4804*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(expected_coordinates_count, 2u);
4805*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleArrayChecks(invoke, codegen, slow_path);
4806*795d594fSAndroid Build Coastguard Worker   }
4807*795d594fSAndroid Build Coastguard Worker }
4808*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleChecks(HInvoke * invoke,CodeGeneratorARM64 * codegen,std::memory_order order,DataType::Type type)4809*795d594fSAndroid Build Coastguard Worker static VarHandleSlowPathARM64* GenerateVarHandleChecks(HInvoke* invoke,
4810*795d594fSAndroid Build Coastguard Worker                                                        CodeGeneratorARM64* codegen,
4811*795d594fSAndroid Build Coastguard Worker                                                        std::memory_order order,
4812*795d594fSAndroid Build Coastguard Worker                                                        DataType::Type type) {
4813*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4814*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
4815*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetUseKnownImageVarHandle()) {
4816*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(expected_coordinates_count, 2u);
4817*795d594fSAndroid Build Coastguard Worker     if (expected_coordinates_count == 0u || optimizations.GetSkipObjectNullCheck()) {
4818*795d594fSAndroid Build Coastguard Worker       return nullptr;
4819*795d594fSAndroid Build Coastguard Worker     }
4820*795d594fSAndroid Build Coastguard Worker   }
4821*795d594fSAndroid Build Coastguard Worker 
4822*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64* slow_path =
4823*795d594fSAndroid Build Coastguard Worker       new (codegen->GetScopedAllocator()) VarHandleSlowPathARM64(invoke, order);
4824*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4825*795d594fSAndroid Build Coastguard Worker 
4826*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetUseKnownImageVarHandle()) {
4827*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleAccessModeAndVarTypeChecks(invoke, codegen, slow_path, type);
4828*795d594fSAndroid Build Coastguard Worker   }
4829*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCoordinateChecks(invoke, codegen, slow_path);
4830*795d594fSAndroid Build Coastguard Worker 
4831*795d594fSAndroid Build Coastguard Worker   return slow_path;
4832*795d594fSAndroid Build Coastguard Worker }
4833*795d594fSAndroid Build Coastguard Worker 
4834*795d594fSAndroid Build Coastguard Worker struct VarHandleTarget {
4835*795d594fSAndroid Build Coastguard Worker   Register object;  // The object holding the value to operate on.
4836*795d594fSAndroid Build Coastguard Worker   Register offset;  // The offset of the value to operate on.
4837*795d594fSAndroid Build Coastguard Worker };
4838*795d594fSAndroid Build Coastguard Worker 
GetVarHandleTarget(HInvoke * invoke)4839*795d594fSAndroid Build Coastguard Worker static VarHandleTarget GetVarHandleTarget(HInvoke* invoke) {
4840*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4841*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4842*795d594fSAndroid Build Coastguard Worker 
4843*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target;
4844*795d594fSAndroid Build Coastguard Worker   // The temporary allocated for loading the offset.
4845*795d594fSAndroid Build Coastguard Worker   target.offset = WRegisterFrom(locations->GetTemp(0u));
4846*795d594fSAndroid Build Coastguard Worker   // The reference to the object that holds the value to operate on.
4847*795d594fSAndroid Build Coastguard Worker   target.object = (expected_coordinates_count == 0u)
4848*795d594fSAndroid Build Coastguard Worker       ? WRegisterFrom(locations->GetTemp(1u))
4849*795d594fSAndroid Build Coastguard Worker       : InputRegisterAt(invoke, 1);
4850*795d594fSAndroid Build Coastguard Worker   return target;
4851*795d594fSAndroid Build Coastguard Worker }
4852*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleTarget(HInvoke * invoke,const VarHandleTarget & target,CodeGeneratorARM64 * codegen)4853*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleTarget(HInvoke* invoke,
4854*795d594fSAndroid Build Coastguard Worker                                     const VarHandleTarget& target,
4855*795d594fSAndroid Build Coastguard Worker                                     CodeGeneratorARM64* codegen) {
4856*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4857*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
4858*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4859*795d594fSAndroid Build Coastguard Worker 
4860*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count <= 1u) {
4861*795d594fSAndroid Build Coastguard Worker     if (VarHandleOptimizations(invoke).GetUseKnownImageVarHandle()) {
4862*795d594fSAndroid Build Coastguard Worker       ScopedObjectAccess soa(Thread::Current());
4863*795d594fSAndroid Build Coastguard Worker       ArtField* target_field = GetBootImageVarHandleField(invoke);
4864*795d594fSAndroid Build Coastguard Worker       if (expected_coordinates_count == 0u) {
4865*795d594fSAndroid Build Coastguard Worker         ObjPtr<mirror::Class> declaring_class = target_field->GetDeclaringClass();
4866*795d594fSAndroid Build Coastguard Worker         if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(declaring_class)) {
4867*795d594fSAndroid Build Coastguard Worker           uint32_t boot_image_offset = CodeGenerator::GetBootImageOffset(declaring_class);
4868*795d594fSAndroid Build Coastguard Worker           codegen->LoadBootImageRelRoEntry(target.object, boot_image_offset);
4869*795d594fSAndroid Build Coastguard Worker         } else {
4870*795d594fSAndroid Build Coastguard Worker           codegen->LoadTypeForBootImageIntrinsic(
4871*795d594fSAndroid Build Coastguard Worker               target.object,
4872*795d594fSAndroid Build Coastguard Worker               TypeReference(&declaring_class->GetDexFile(), declaring_class->GetDexTypeIndex()));
4873*795d594fSAndroid Build Coastguard Worker         }
4874*795d594fSAndroid Build Coastguard Worker       }
4875*795d594fSAndroid Build Coastguard Worker       __ Mov(target.offset, target_field->GetOffset().Uint32Value());
4876*795d594fSAndroid Build Coastguard Worker     } else {
4877*795d594fSAndroid Build Coastguard Worker       // For static fields, we need to fill the `target.object` with the declaring class,
4878*795d594fSAndroid Build Coastguard Worker       // so we can use `target.object` as temporary for the `ArtField*`. For instance fields,
4879*795d594fSAndroid Build Coastguard Worker       // we do not need the declaring class, so we can forget the `ArtField*` when
4880*795d594fSAndroid Build Coastguard Worker       // we load the `target.offset`, so use the `target.offset` to hold the `ArtField*`.
4881*795d594fSAndroid Build Coastguard Worker       Register field = (expected_coordinates_count == 0) ? target.object : target.offset;
4882*795d594fSAndroid Build Coastguard Worker 
4883*795d594fSAndroid Build Coastguard Worker       const MemberOffset art_field_offset = mirror::FieldVarHandle::ArtFieldOffset();
4884*795d594fSAndroid Build Coastguard Worker       const MemberOffset offset_offset = ArtField::OffsetOffset();
4885*795d594fSAndroid Build Coastguard Worker 
4886*795d594fSAndroid Build Coastguard Worker       // Load the ArtField*, the offset and, if needed, declaring class.
4887*795d594fSAndroid Build Coastguard Worker       __ Ldr(field.X(), HeapOperand(varhandle, art_field_offset.Int32Value()));
4888*795d594fSAndroid Build Coastguard Worker       __ Ldr(target.offset, MemOperand(field.X(), offset_offset.Int32Value()));
4889*795d594fSAndroid Build Coastguard Worker       if (expected_coordinates_count == 0u) {
4890*795d594fSAndroid Build Coastguard Worker         codegen->GenerateGcRootFieldLoad(invoke,
4891*795d594fSAndroid Build Coastguard Worker                                          LocationFrom(target.object),
4892*795d594fSAndroid Build Coastguard Worker                                          field.X(),
4893*795d594fSAndroid Build Coastguard Worker                                          ArtField::DeclaringClassOffset().Int32Value(),
4894*795d594fSAndroid Build Coastguard Worker                                          /*fixup_label=*/nullptr,
4895*795d594fSAndroid Build Coastguard Worker                                          codegen->GetCompilerReadBarrierOption());
4896*795d594fSAndroid Build Coastguard Worker       }
4897*795d594fSAndroid Build Coastguard Worker     }
4898*795d594fSAndroid Build Coastguard Worker   } else {
4899*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(expected_coordinates_count, 2u);
4900*795d594fSAndroid Build Coastguard Worker     DataType::Type value_type =
4901*795d594fSAndroid Build Coastguard Worker         GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
4902*795d594fSAndroid Build Coastguard Worker     size_t size_shift = DataType::SizeShift(value_type);
4903*795d594fSAndroid Build Coastguard Worker     MemberOffset data_offset = mirror::Array::DataOffset(DataType::Size(value_type));
4904*795d594fSAndroid Build Coastguard Worker 
4905*795d594fSAndroid Build Coastguard Worker     Register index = InputRegisterAt(invoke, 2);
4906*795d594fSAndroid Build Coastguard Worker     Register shifted_index = index;
4907*795d594fSAndroid Build Coastguard Worker     if (size_shift != 0u) {
4908*795d594fSAndroid Build Coastguard Worker       shifted_index = target.offset;
4909*795d594fSAndroid Build Coastguard Worker       __ Lsl(shifted_index, index, size_shift);
4910*795d594fSAndroid Build Coastguard Worker     }
4911*795d594fSAndroid Build Coastguard Worker     __ Add(target.offset, shifted_index, data_offset.Int32Value());
4912*795d594fSAndroid Build Coastguard Worker   }
4913*795d594fSAndroid Build Coastguard Worker }
4914*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleCommonLocations(HInvoke * invoke,CodeGeneratorARM64 * codegen)4915*795d594fSAndroid Build Coastguard Worker static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke,
4916*795d594fSAndroid Build Coastguard Worker                                                        CodeGeneratorARM64* codegen) {
4917*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4918*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
4919*795d594fSAndroid Build Coastguard Worker 
4920*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4921*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
4922*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4923*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4924*795d594fSAndroid Build Coastguard Worker   // Require coordinates in registers. These are the object holding the value
4925*795d594fSAndroid Build Coastguard Worker   // to operate on (except for static fields) and index (for arrays and views).
4926*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i != expected_coordinates_count; ++i) {
4927*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(/* VarHandle object */ 1u + i, Location::RequiresRegister());
4928*795d594fSAndroid Build Coastguard Worker   }
4929*795d594fSAndroid Build Coastguard Worker   if (return_type != DataType::Type::kVoid) {
4930*795d594fSAndroid Build Coastguard Worker     if (DataType::IsFloatingPointType(return_type)) {
4931*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
4932*795d594fSAndroid Build Coastguard Worker     } else {
4933*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister());
4934*795d594fSAndroid Build Coastguard Worker     }
4935*795d594fSAndroid Build Coastguard Worker   }
4936*795d594fSAndroid Build Coastguard Worker   uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
4937*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4938*795d594fSAndroid Build Coastguard Worker   for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
4939*795d594fSAndroid Build Coastguard Worker     HInstruction* arg = invoke->InputAt(arg_index);
4940*795d594fSAndroid Build Coastguard Worker     if (IsZeroBitPattern(arg)) {
4941*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(arg_index, Location::ConstantLocation(arg));
4942*795d594fSAndroid Build Coastguard Worker     } else if (DataType::IsFloatingPointType(arg->GetType())) {
4943*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(arg_index, Location::RequiresFpuRegister());
4944*795d594fSAndroid Build Coastguard Worker     } else {
4945*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(arg_index, Location::RequiresRegister());
4946*795d594fSAndroid Build Coastguard Worker     }
4947*795d594fSAndroid Build Coastguard Worker   }
4948*795d594fSAndroid Build Coastguard Worker 
4949*795d594fSAndroid Build Coastguard Worker   // Add a temporary for offset.
4950*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier() &&
4951*795d594fSAndroid Build Coastguard Worker       GetExpectedVarHandleCoordinatesCount(invoke) == 0u) {  // For static fields.
4952*795d594fSAndroid Build Coastguard Worker     // To preserve the offset value across the non-Baker read barrier slow path
4953*795d594fSAndroid Build Coastguard Worker     // for loading the declaring class, use a fixed callee-save register.
4954*795d594fSAndroid Build Coastguard Worker     constexpr int first_callee_save = CTZ(kArm64CalleeSaveRefSpills);
4955*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(first_callee_save));
4956*795d594fSAndroid Build Coastguard Worker   } else {
4957*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4958*795d594fSAndroid Build Coastguard Worker   }
4959*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 0u) {
4960*795d594fSAndroid Build Coastguard Worker     // Add a temporary to hold the declaring class.
4961*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4962*795d594fSAndroid Build Coastguard Worker   }
4963*795d594fSAndroid Build Coastguard Worker 
4964*795d594fSAndroid Build Coastguard Worker   return locations;
4965*795d594fSAndroid Build Coastguard Worker }
4966*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetLocations(HInvoke * invoke,CodeGeneratorARM64 * codegen)4967*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetLocations(HInvoke* invoke, CodeGeneratorARM64* codegen) {
4968*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
4969*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetDoNotIntrinsify()) {
4970*795d594fSAndroid Build Coastguard Worker     return;
4971*795d594fSAndroid Build Coastguard Worker   }
4972*795d594fSAndroid Build Coastguard Worker 
4973*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier() &&
4974*795d594fSAndroid Build Coastguard Worker       invoke->GetType() == DataType::Type::kReference &&
4975*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() != Intrinsics::kVarHandleGet &&
4976*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() != Intrinsics::kVarHandleGetOpaque) {
4977*795d594fSAndroid Build Coastguard Worker     // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
4978*795d594fSAndroid Build Coastguard Worker     // the passed reference and reloads it from the field. This gets the memory visibility
4979*795d594fSAndroid Build Coastguard Worker     // wrong for Acquire/Volatile operations. b/173104084
4980*795d594fSAndroid Build Coastguard Worker     return;
4981*795d594fSAndroid Build Coastguard Worker   }
4982*795d594fSAndroid Build Coastguard Worker 
4983*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCommonLocations(invoke, codegen);
4984*795d594fSAndroid Build Coastguard Worker }
4985*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGet(HInvoke * invoke,CodeGeneratorARM64 * codegen,std::memory_order order,bool byte_swap=false)4986*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGet(HInvoke* invoke,
4987*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorARM64* codegen,
4988*795d594fSAndroid Build Coastguard Worker                                  std::memory_order order,
4989*795d594fSAndroid Build Coastguard Worker                                  bool byte_swap = false) {
4990*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4991*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(type, DataType::Type::kVoid);
4992*795d594fSAndroid Build Coastguard Worker 
4993*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4994*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
4995*795d594fSAndroid Build Coastguard Worker   CPURegister out = helpers::OutputCPURegister(invoke);
4996*795d594fSAndroid Build Coastguard Worker 
4997*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target = GetVarHandleTarget(invoke);
4998*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64* slow_path = nullptr;
4999*795d594fSAndroid Build Coastguard Worker   if (!byte_swap) {
5000*795d594fSAndroid Build Coastguard Worker     slow_path = GenerateVarHandleChecks(invoke, codegen, order, type);
5001*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleTarget(invoke, target, codegen);
5002*795d594fSAndroid Build Coastguard Worker     if (slow_path != nullptr) {
5003*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetNativeByteOrderLabel());
5004*795d594fSAndroid Build Coastguard Worker     }
5005*795d594fSAndroid Build Coastguard Worker   }
5006*795d594fSAndroid Build Coastguard Worker 
5007*795d594fSAndroid Build Coastguard Worker   // ARM64 load-acquire instructions are implicitly sequentially consistent.
5008*795d594fSAndroid Build Coastguard Worker   bool use_load_acquire =
5009*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_acquire) || (order == std::memory_order_seq_cst);
5010*795d594fSAndroid Build Coastguard Worker   DCHECK(use_load_acquire || order == std::memory_order_relaxed);
5011*795d594fSAndroid Build Coastguard Worker 
5012*795d594fSAndroid Build Coastguard Worker   // Load the value from the target location.
5013*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference && codegen->EmitBakerReadBarrier()) {
5014*795d594fSAndroid Build Coastguard Worker     // Piggy-back on the field load path using introspection for the Baker read barrier.
5015*795d594fSAndroid Build Coastguard Worker     // The `target.offset` is a temporary, use it for field address.
5016*795d594fSAndroid Build Coastguard Worker     Register tmp_ptr = target.offset.X();
5017*795d594fSAndroid Build Coastguard Worker     __ Add(tmp_ptr, target.object.X(), target.offset.X());
5018*795d594fSAndroid Build Coastguard Worker     codegen->GenerateFieldLoadWithBakerReadBarrier(invoke,
5019*795d594fSAndroid Build Coastguard Worker                                                    locations->Out(),
5020*795d594fSAndroid Build Coastguard Worker                                                    target.object,
5021*795d594fSAndroid Build Coastguard Worker                                                    MemOperand(tmp_ptr),
5022*795d594fSAndroid Build Coastguard Worker                                                    /*needs_null_check=*/ false,
5023*795d594fSAndroid Build Coastguard Worker                                                    use_load_acquire);
5024*795d594fSAndroid Build Coastguard Worker     DCHECK(!byte_swap);
5025*795d594fSAndroid Build Coastguard Worker   } else {
5026*795d594fSAndroid Build Coastguard Worker     MemOperand address(target.object.X(), target.offset.X());
5027*795d594fSAndroid Build Coastguard Worker     CPURegister load_reg = out;
5028*795d594fSAndroid Build Coastguard Worker     DataType::Type load_type = type;
5029*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
5030*795d594fSAndroid Build Coastguard Worker     if (byte_swap) {
5031*795d594fSAndroid Build Coastguard Worker       if (type == DataType::Type::kInt16) {
5032*795d594fSAndroid Build Coastguard Worker         // Avoid unnecessary sign extension before REV16.
5033*795d594fSAndroid Build Coastguard Worker         load_type = DataType::Type::kUint16;
5034*795d594fSAndroid Build Coastguard Worker       } else if (type == DataType::Type::kFloat32) {
5035*795d594fSAndroid Build Coastguard Worker         load_type = DataType::Type::kInt32;
5036*795d594fSAndroid Build Coastguard Worker         load_reg = target.offset.W();
5037*795d594fSAndroid Build Coastguard Worker       } else if (type == DataType::Type::kFloat64) {
5038*795d594fSAndroid Build Coastguard Worker         load_type = DataType::Type::kInt64;
5039*795d594fSAndroid Build Coastguard Worker         load_reg = target.offset.X();
5040*795d594fSAndroid Build Coastguard Worker       }
5041*795d594fSAndroid Build Coastguard Worker     }
5042*795d594fSAndroid Build Coastguard Worker     if (use_load_acquire) {
5043*795d594fSAndroid Build Coastguard Worker       codegen->LoadAcquire(invoke, load_type, load_reg, address, /*needs_null_check=*/ false);
5044*795d594fSAndroid Build Coastguard Worker     } else {
5045*795d594fSAndroid Build Coastguard Worker       codegen->Load(load_type, load_reg, address);
5046*795d594fSAndroid Build Coastguard Worker     }
5047*795d594fSAndroid Build Coastguard Worker     if (type == DataType::Type::kReference) {
5048*795d594fSAndroid Build Coastguard Worker       DCHECK(!byte_swap);
5049*795d594fSAndroid Build Coastguard Worker       DCHECK(out.IsW());
5050*795d594fSAndroid Build Coastguard Worker       Location out_loc = locations->Out();
5051*795d594fSAndroid Build Coastguard Worker       Location object_loc = LocationFrom(target.object);
5052*795d594fSAndroid Build Coastguard Worker       Location offset_loc = LocationFrom(target.offset);
5053*795d594fSAndroid Build Coastguard Worker       codegen->MaybeGenerateReadBarrierSlow(invoke, out_loc, out_loc, object_loc, 0u, offset_loc);
5054*795d594fSAndroid Build Coastguard Worker     } else if (byte_swap) {
5055*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, type, load_reg, out);
5056*795d594fSAndroid Build Coastguard Worker     }
5057*795d594fSAndroid Build Coastguard Worker   }
5058*795d594fSAndroid Build Coastguard Worker 
5059*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
5060*795d594fSAndroid Build Coastguard Worker     DCHECK(!byte_swap);
5061*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
5062*795d594fSAndroid Build Coastguard Worker   }
5063*795d594fSAndroid Build Coastguard Worker }
5064*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGet(HInvoke * invoke)5065*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGet(HInvoke* invoke) {
5066*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
5067*795d594fSAndroid Build Coastguard Worker }
5068*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGet(HInvoke * invoke)5069*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGet(HInvoke* invoke) {
5070*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_, std::memory_order_relaxed);
5071*795d594fSAndroid Build Coastguard Worker }
5072*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetOpaque(HInvoke * invoke)5073*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetOpaque(HInvoke* invoke) {
5074*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
5075*795d594fSAndroid Build Coastguard Worker }
5076*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetOpaque(HInvoke * invoke)5077*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetOpaque(HInvoke* invoke) {
5078*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_, std::memory_order_relaxed);
5079*795d594fSAndroid Build Coastguard Worker }
5080*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAcquire(HInvoke * invoke)5081*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAcquire(HInvoke* invoke) {
5082*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
5083*795d594fSAndroid Build Coastguard Worker }
5084*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAcquire(HInvoke * invoke)5085*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAcquire(HInvoke* invoke) {
5086*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_, std::memory_order_acquire);
5087*795d594fSAndroid Build Coastguard Worker }
5088*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetVolatile(HInvoke * invoke)5089*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetVolatile(HInvoke* invoke) {
5090*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
5091*795d594fSAndroid Build Coastguard Worker }
5092*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetVolatile(HInvoke * invoke)5093*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetVolatile(HInvoke* invoke) {
5094*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_, std::memory_order_seq_cst);
5095*795d594fSAndroid Build Coastguard Worker }
5096*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleSetLocations(HInvoke * invoke,CodeGeneratorARM64 * codegen)5097*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleSetLocations(HInvoke* invoke, CodeGeneratorARM64* codegen) {
5098*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
5099*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetDoNotIntrinsify()) {
5100*795d594fSAndroid Build Coastguard Worker     return;
5101*795d594fSAndroid Build Coastguard Worker   }
5102*795d594fSAndroid Build Coastguard Worker 
5103*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCommonLocations(invoke, codegen);
5104*795d594fSAndroid Build Coastguard Worker }
5105*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleSet(HInvoke * invoke,CodeGeneratorARM64 * codegen,std::memory_order order,bool byte_swap=false)5106*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleSet(HInvoke* invoke,
5107*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorARM64* codegen,
5108*795d594fSAndroid Build Coastguard Worker                                  std::memory_order order,
5109*795d594fSAndroid Build Coastguard Worker                                  bool byte_swap = false) {
5110*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
5111*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
5112*795d594fSAndroid Build Coastguard Worker 
5113*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
5114*795d594fSAndroid Build Coastguard Worker   CPURegister value = InputCPURegisterOrZeroRegAt(invoke, value_index);
5115*795d594fSAndroid Build Coastguard Worker 
5116*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target = GetVarHandleTarget(invoke);
5117*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64* slow_path = nullptr;
5118*795d594fSAndroid Build Coastguard Worker   if (!byte_swap) {
5119*795d594fSAndroid Build Coastguard Worker     slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
5120*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleTarget(invoke, target, codegen);
5121*795d594fSAndroid Build Coastguard Worker     if (slow_path != nullptr) {
5122*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetNativeByteOrderLabel());
5123*795d594fSAndroid Build Coastguard Worker     }
5124*795d594fSAndroid Build Coastguard Worker   }
5125*795d594fSAndroid Build Coastguard Worker 
5126*795d594fSAndroid Build Coastguard Worker   // ARM64 store-release instructions are implicitly sequentially consistent.
5127*795d594fSAndroid Build Coastguard Worker   bool use_store_release =
5128*795d594fSAndroid Build Coastguard Worker       (order == std::memory_order_release) || (order == std::memory_order_seq_cst);
5129*795d594fSAndroid Build Coastguard Worker   DCHECK(use_store_release || order == std::memory_order_relaxed);
5130*795d594fSAndroid Build Coastguard Worker 
5131*795d594fSAndroid Build Coastguard Worker   // Store the value to the target location.
5132*795d594fSAndroid Build Coastguard Worker   {
5133*795d594fSAndroid Build Coastguard Worker     CPURegister source = value;
5134*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
5135*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
5136*795d594fSAndroid Build Coastguard Worker       DCHECK(value.IsW());
5137*795d594fSAndroid Build Coastguard Worker       Register temp = temps.AcquireW();
5138*795d594fSAndroid Build Coastguard Worker       __ Mov(temp, value.W());
5139*795d594fSAndroid Build Coastguard Worker       codegen->GetAssembler()->PoisonHeapReference(temp);
5140*795d594fSAndroid Build Coastguard Worker       source = temp;
5141*795d594fSAndroid Build Coastguard Worker     }
5142*795d594fSAndroid Build Coastguard Worker     if (byte_swap) {
5143*795d594fSAndroid Build Coastguard Worker       DCHECK(!source.IsZero());  // We use the main path for zero as it does not need a byte swap.
5144*795d594fSAndroid Build Coastguard Worker       Register temp = source.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
5145*795d594fSAndroid Build Coastguard Worker       if (value_type == DataType::Type::kInt16) {
5146*795d594fSAndroid Build Coastguard Worker         // Avoid unnecessary sign extension before storing.
5147*795d594fSAndroid Build Coastguard Worker         value_type = DataType::Type::kUint16;
5148*795d594fSAndroid Build Coastguard Worker       } else if (DataType::IsFloatingPointType(value_type)) {
5149*795d594fSAndroid Build Coastguard Worker         __ Fmov(temp, source.Is64Bits() ? source.D() : source.S());
5150*795d594fSAndroid Build Coastguard Worker         value_type = source.Is64Bits() ? DataType::Type::kInt64 : DataType::Type::kInt32;
5151*795d594fSAndroid Build Coastguard Worker         source = temp;  // Source for the `GenerateReverseBytes()` below.
5152*795d594fSAndroid Build Coastguard Worker       }
5153*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, value_type, source, temp);
5154*795d594fSAndroid Build Coastguard Worker       source = temp;
5155*795d594fSAndroid Build Coastguard Worker     }
5156*795d594fSAndroid Build Coastguard Worker     MemOperand address(target.object.X(), target.offset.X());
5157*795d594fSAndroid Build Coastguard Worker     if (use_store_release) {
5158*795d594fSAndroid Build Coastguard Worker       codegen->StoreRelease(invoke, value_type, source, address, /*needs_null_check=*/ false);
5159*795d594fSAndroid Build Coastguard Worker     } else {
5160*795d594fSAndroid Build Coastguard Worker       codegen->Store(value_type, source, address);
5161*795d594fSAndroid Build Coastguard Worker     }
5162*795d594fSAndroid Build Coastguard Worker   }
5163*795d594fSAndroid Build Coastguard Worker 
5164*795d594fSAndroid Build Coastguard Worker   if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(value_index))) {
5165*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(target.object, Register(value), /* emit_null_check= */ true);
5166*795d594fSAndroid Build Coastguard Worker   }
5167*795d594fSAndroid Build Coastguard Worker 
5168*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
5169*795d594fSAndroid Build Coastguard Worker     DCHECK(!byte_swap);
5170*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
5171*795d594fSAndroid Build Coastguard Worker   }
5172*795d594fSAndroid Build Coastguard Worker }
5173*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSet(HInvoke * invoke)5174*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleSet(HInvoke* invoke) {
5175*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
5176*795d594fSAndroid Build Coastguard Worker }
5177*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSet(HInvoke * invoke)5178*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleSet(HInvoke* invoke) {
5179*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_, std::memory_order_relaxed);
5180*795d594fSAndroid Build Coastguard Worker }
5181*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetOpaque(HInvoke * invoke)5182*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleSetOpaque(HInvoke* invoke) {
5183*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
5184*795d594fSAndroid Build Coastguard Worker }
5185*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetOpaque(HInvoke * invoke)5186*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleSetOpaque(HInvoke* invoke) {
5187*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_, std::memory_order_relaxed);
5188*795d594fSAndroid Build Coastguard Worker }
5189*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetRelease(HInvoke * invoke)5190*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleSetRelease(HInvoke* invoke) {
5191*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
5192*795d594fSAndroid Build Coastguard Worker }
5193*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetRelease(HInvoke * invoke)5194*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleSetRelease(HInvoke* invoke) {
5195*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_, std::memory_order_release);
5196*795d594fSAndroid Build Coastguard Worker }
5197*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetVolatile(HInvoke * invoke)5198*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleSetVolatile(HInvoke* invoke) {
5199*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
5200*795d594fSAndroid Build Coastguard Worker }
5201*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetVolatile(HInvoke * invoke)5202*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleSetVolatile(HInvoke* invoke) {
5203*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_, std::memory_order_seq_cst);
5204*795d594fSAndroid Build Coastguard Worker }
5205*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke * invoke,CodeGeneratorARM64 * codegen,bool return_success)5206*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke,
5207*795d594fSAndroid Build Coastguard Worker                                                             CodeGeneratorARM64* codegen,
5208*795d594fSAndroid Build Coastguard Worker                                                             bool return_success) {
5209*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
5210*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetDoNotIntrinsify()) {
5211*795d594fSAndroid Build Coastguard Worker     return;
5212*795d594fSAndroid Build Coastguard Worker   }
5213*795d594fSAndroid Build Coastguard Worker 
5214*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
5215*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1u);
5216*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
5217*795d594fSAndroid Build Coastguard Worker     // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
5218*795d594fSAndroid Build Coastguard Worker     // the passed reference and reloads it from the field. This breaks the read barriers
5219*795d594fSAndroid Build Coastguard Worker     // in slow path in different ways. The marked old value may not actually be a to-space
5220*795d594fSAndroid Build Coastguard Worker     // reference to the same object as `old_value`, breaking slow path assumptions. And
5221*795d594fSAndroid Build Coastguard Worker     // for CompareAndExchange, marking the old value after comparison failure may actually
5222*795d594fSAndroid Build Coastguard Worker     // return the reference to `expected`, erroneously indicating success even though we
5223*795d594fSAndroid Build Coastguard Worker     // did not set the new value. (And it also gets the memory visibility wrong.) b/173104084
5224*795d594fSAndroid Build Coastguard Worker     return;
5225*795d594fSAndroid Build Coastguard Worker   }
5226*795d594fSAndroid Build Coastguard Worker 
5227*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
5228*795d594fSAndroid Build Coastguard Worker 
5229*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
5230*795d594fSAndroid Build Coastguard Worker     // We need callee-save registers for both the class object and offset instead of
5231*795d594fSAndroid Build Coastguard Worker     // the temporaries reserved in CreateVarHandleCommonLocations().
5232*795d594fSAndroid Build Coastguard Worker     static_assert(POPCOUNT(kArm64CalleeSaveRefSpills) >= 2u);
5233*795d594fSAndroid Build Coastguard Worker     uint32_t first_callee_save = CTZ(kArm64CalleeSaveRefSpills);
5234*795d594fSAndroid Build Coastguard Worker     uint32_t second_callee_save = CTZ(kArm64CalleeSaveRefSpills ^ (1u << first_callee_save));
5235*795d594fSAndroid Build Coastguard Worker     if (GetExpectedVarHandleCoordinatesCount(invoke) == 0u) {  // For static fields.
5236*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(locations->GetTempCount(), 2u);
5237*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->GetTemp(0u).Equals(Location::RequiresRegister()));
5238*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->GetTemp(1u).Equals(Location::RegisterLocation(first_callee_save)));
5239*795d594fSAndroid Build Coastguard Worker       locations->SetTempAt(0u, Location::RegisterLocation(second_callee_save));
5240*795d594fSAndroid Build Coastguard Worker     } else {
5241*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(locations->GetTempCount(), 1u);
5242*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->GetTemp(0u).Equals(Location::RequiresRegister()));
5243*795d594fSAndroid Build Coastguard Worker       locations->SetTempAt(0u, Location::RegisterLocation(first_callee_save));
5244*795d594fSAndroid Build Coastguard Worker     }
5245*795d594fSAndroid Build Coastguard Worker   }
5246*795d594fSAndroid Build Coastguard Worker   size_t old_temp_count = locations->GetTempCount();
5247*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(old_temp_count, (GetExpectedVarHandleCoordinatesCount(invoke) == 0) ? 2u : 1u);
5248*795d594fSAndroid Build Coastguard Worker   if (!return_success) {
5249*795d594fSAndroid Build Coastguard Worker     if (DataType::IsFloatingPointType(value_type)) {
5250*795d594fSAndroid Build Coastguard Worker       // Add a temporary for old value and exclusive store result if floating point
5251*795d594fSAndroid Build Coastguard Worker       // `expected` and/or `new_value` take scratch registers.
5252*795d594fSAndroid Build Coastguard Worker       size_t available_scratch_registers =
5253*795d594fSAndroid Build Coastguard Worker           (IsZeroBitPattern(invoke->InputAt(number_of_arguments - 1u)) ? 1u : 0u) +
5254*795d594fSAndroid Build Coastguard Worker           (IsZeroBitPattern(invoke->InputAt(number_of_arguments - 2u)) ? 1u : 0u);
5255*795d594fSAndroid Build Coastguard Worker       size_t temps_needed = /* pointer, old value, store result */ 3u - available_scratch_registers;
5256*795d594fSAndroid Build Coastguard Worker       // We can reuse the declaring class (if present) and offset temporary.
5257*795d594fSAndroid Build Coastguard Worker       if (temps_needed > old_temp_count) {
5258*795d594fSAndroid Build Coastguard Worker         locations->AddRegisterTemps(temps_needed - old_temp_count);
5259*795d594fSAndroid Build Coastguard Worker       }
5260*795d594fSAndroid Build Coastguard Worker     } else if ((value_type != DataType::Type::kReference && DataType::Size(value_type) != 1u) &&
5261*795d594fSAndroid Build Coastguard Worker                !IsZeroBitPattern(invoke->InputAt(number_of_arguments - 2u)) &&
5262*795d594fSAndroid Build Coastguard Worker                !IsZeroBitPattern(invoke->InputAt(number_of_arguments - 1u)) &&
5263*795d594fSAndroid Build Coastguard Worker                GetExpectedVarHandleCoordinatesCount(invoke) == 2u) {
5264*795d594fSAndroid Build Coastguard Worker       // Allocate a normal temporary for store result in the non-native byte order path
5265*795d594fSAndroid Build Coastguard Worker       // because scratch registers are used by the byte-swapped `expected` and `new_value`.
5266*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(old_temp_count, 1u);
5267*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
5268*795d594fSAndroid Build Coastguard Worker     }
5269*795d594fSAndroid Build Coastguard Worker   }
5270*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
5271*795d594fSAndroid Build Coastguard Worker     // Add a temporary for the `old_value_temp` in slow path.
5272*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
5273*795d594fSAndroid Build Coastguard Worker   }
5274*795d594fSAndroid Build Coastguard Worker }
5275*795d594fSAndroid Build Coastguard Worker 
MoveToTempIfFpRegister(const CPURegister & cpu_reg,DataType::Type type,MacroAssembler * masm,UseScratchRegisterScope * temps)5276*795d594fSAndroid Build Coastguard Worker static Register MoveToTempIfFpRegister(const CPURegister& cpu_reg,
5277*795d594fSAndroid Build Coastguard Worker                                        DataType::Type type,
5278*795d594fSAndroid Build Coastguard Worker                                        MacroAssembler* masm,
5279*795d594fSAndroid Build Coastguard Worker                                        UseScratchRegisterScope* temps) {
5280*795d594fSAndroid Build Coastguard Worker   if (cpu_reg.IsS()) {
5281*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kFloat32);
5282*795d594fSAndroid Build Coastguard Worker     Register reg = temps->AcquireW();
5283*795d594fSAndroid Build Coastguard Worker     __ Fmov(reg, cpu_reg.S());
5284*795d594fSAndroid Build Coastguard Worker     return reg;
5285*795d594fSAndroid Build Coastguard Worker   } else if (cpu_reg.IsD()) {
5286*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kFloat64);
5287*795d594fSAndroid Build Coastguard Worker     Register reg = temps->AcquireX();
5288*795d594fSAndroid Build Coastguard Worker     __ Fmov(reg, cpu_reg.D());
5289*795d594fSAndroid Build Coastguard Worker     return reg;
5290*795d594fSAndroid Build Coastguard Worker   } else {
5291*795d594fSAndroid Build Coastguard Worker     return DataType::Is64BitType(type) ? cpu_reg.X() : cpu_reg.W();
5292*795d594fSAndroid Build Coastguard Worker   }
5293*795d594fSAndroid Build Coastguard Worker }
5294*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleCompareAndSetOrExchange(HInvoke * invoke,CodeGeneratorARM64 * codegen,std::memory_order order,bool return_success,bool strong,bool byte_swap=false)5295*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCompareAndSetOrExchange(HInvoke* invoke,
5296*795d594fSAndroid Build Coastguard Worker                                                      CodeGeneratorARM64* codegen,
5297*795d594fSAndroid Build Coastguard Worker                                                      std::memory_order order,
5298*795d594fSAndroid Build Coastguard Worker                                                      bool return_success,
5299*795d594fSAndroid Build Coastguard Worker                                                      bool strong,
5300*795d594fSAndroid Build Coastguard Worker                                                      bool byte_swap = false) {
5301*795d594fSAndroid Build Coastguard Worker   DCHECK(return_success || strong);
5302*795d594fSAndroid Build Coastguard Worker 
5303*795d594fSAndroid Build Coastguard Worker   uint32_t expected_index = invoke->GetNumberOfArguments() - 2;
5304*795d594fSAndroid Build Coastguard Worker   uint32_t new_value_index = invoke->GetNumberOfArguments() - 1;
5305*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
5306*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, expected_index));
5307*795d594fSAndroid Build Coastguard Worker 
5308*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
5309*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
5310*795d594fSAndroid Build Coastguard Worker   CPURegister expected = InputCPURegisterOrZeroRegAt(invoke, expected_index);
5311*795d594fSAndroid Build Coastguard Worker   CPURegister new_value = InputCPURegisterOrZeroRegAt(invoke, new_value_index);
5312*795d594fSAndroid Build Coastguard Worker   CPURegister out = helpers::OutputCPURegister(invoke);
5313*795d594fSAndroid Build Coastguard Worker 
5314*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target = GetVarHandleTarget(invoke);
5315*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64* slow_path = nullptr;
5316*795d594fSAndroid Build Coastguard Worker   if (!byte_swap) {
5317*795d594fSAndroid Build Coastguard Worker     slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
5318*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleTarget(invoke, target, codegen);
5319*795d594fSAndroid Build Coastguard Worker     if (slow_path != nullptr) {
5320*795d594fSAndroid Build Coastguard Worker       slow_path->SetCompareAndSetOrExchangeArgs(return_success, strong);
5321*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetNativeByteOrderLabel());
5322*795d594fSAndroid Build Coastguard Worker     }
5323*795d594fSAndroid Build Coastguard Worker   }
5324*795d594fSAndroid Build Coastguard Worker 
5325*795d594fSAndroid Build Coastguard Worker   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
5326*795d594fSAndroid Build Coastguard Worker   if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(new_value_index))) {
5327*795d594fSAndroid Build Coastguard Worker     // Mark card for object assuming new value is stored.
5328*795d594fSAndroid Build Coastguard Worker     bool new_value_can_be_null = true;  // TODO: Worth finding out this information?
5329*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(target.object, new_value.W(), new_value_can_be_null);
5330*795d594fSAndroid Build Coastguard Worker   }
5331*795d594fSAndroid Build Coastguard Worker 
5332*795d594fSAndroid Build Coastguard Worker   // Reuse the `offset` temporary for the pointer to the target location,
5333*795d594fSAndroid Build Coastguard Worker   // except for references that need the offset for the read barrier.
5334*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
5335*795d594fSAndroid Build Coastguard Worker   Register tmp_ptr = target.offset.X();
5336*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
5337*795d594fSAndroid Build Coastguard Worker     tmp_ptr = temps.AcquireX();
5338*795d594fSAndroid Build Coastguard Worker   }
5339*795d594fSAndroid Build Coastguard Worker   __ Add(tmp_ptr, target.object.X(), target.offset.X());
5340*795d594fSAndroid Build Coastguard Worker 
5341*795d594fSAndroid Build Coastguard Worker   // Move floating point values to scratch registers.
5342*795d594fSAndroid Build Coastguard Worker   // Note that float/double CAS uses bitwise comparison, rather than the operator==.
5343*795d594fSAndroid Build Coastguard Worker   Register expected_reg = MoveToTempIfFpRegister(expected, value_type, masm, &temps);
5344*795d594fSAndroid Build Coastguard Worker   Register new_value_reg = MoveToTempIfFpRegister(new_value, value_type, masm, &temps);
5345*795d594fSAndroid Build Coastguard Worker   bool is_fp = DataType::IsFloatingPointType(value_type);
5346*795d594fSAndroid Build Coastguard Worker   DataType::Type cas_type = is_fp
5347*795d594fSAndroid Build Coastguard Worker       ? ((value_type == DataType::Type::kFloat64) ? DataType::Type::kInt64 : DataType::Type::kInt32)
5348*795d594fSAndroid Build Coastguard Worker       : value_type;
5349*795d594fSAndroid Build Coastguard Worker   // Avoid sign extension in the CAS loop by zero-extending `expected` before the loop. This adds
5350*795d594fSAndroid Build Coastguard Worker   // one instruction for CompareAndExchange as we shall need to sign-extend the returned value.
5351*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kInt16 && !expected.IsZero()) {
5352*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
5353*795d594fSAndroid Build Coastguard Worker     __ Uxth(temp, expected_reg);
5354*795d594fSAndroid Build Coastguard Worker     expected_reg = temp;
5355*795d594fSAndroid Build Coastguard Worker     cas_type = DataType::Type::kUint16;
5356*795d594fSAndroid Build Coastguard Worker   } else if (value_type == DataType::Type::kInt8 && !expected.IsZero()) {
5357*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
5358*795d594fSAndroid Build Coastguard Worker     __ Uxtb(temp, expected_reg);
5359*795d594fSAndroid Build Coastguard Worker     expected_reg = temp;
5360*795d594fSAndroid Build Coastguard Worker     cas_type = DataType::Type::kUint8;
5361*795d594fSAndroid Build Coastguard Worker   }
5362*795d594fSAndroid Build Coastguard Worker 
5363*795d594fSAndroid Build Coastguard Worker   if (byte_swap) {
5364*795d594fSAndroid Build Coastguard Worker     // Do the byte swap and move values to scratch registers if needed.
5365*795d594fSAndroid Build Coastguard Worker     // Non-zero FP values and non-zero `expected` for `kInt16` are already in scratch registers.
5366*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(value_type, DataType::Type::kInt8);
5367*795d594fSAndroid Build Coastguard Worker     if (!expected.IsZero()) {
5368*795d594fSAndroid Build Coastguard Worker       bool is_scratch = is_fp || (value_type == DataType::Type::kInt16);
5369*795d594fSAndroid Build Coastguard Worker       Register temp = is_scratch ? expected_reg : temps.AcquireSameSizeAs(expected_reg);
5370*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, cas_type, expected_reg, temp);
5371*795d594fSAndroid Build Coastguard Worker       expected_reg = temp;
5372*795d594fSAndroid Build Coastguard Worker     }
5373*795d594fSAndroid Build Coastguard Worker     if (!new_value.IsZero()) {
5374*795d594fSAndroid Build Coastguard Worker       Register temp = is_fp ? new_value_reg : temps.AcquireSameSizeAs(new_value_reg);
5375*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, cas_type, new_value_reg, temp);
5376*795d594fSAndroid Build Coastguard Worker       new_value_reg = temp;
5377*795d594fSAndroid Build Coastguard Worker     }
5378*795d594fSAndroid Build Coastguard Worker   }
5379*795d594fSAndroid Build Coastguard Worker 
5380*795d594fSAndroid Build Coastguard Worker   // Prepare registers for old value and the result of the exclusive store.
5381*795d594fSAndroid Build Coastguard Worker   Register old_value;
5382*795d594fSAndroid Build Coastguard Worker   Register store_result;
5383*795d594fSAndroid Build Coastguard Worker   if (return_success) {
5384*795d594fSAndroid Build Coastguard Worker     // Use the output register for both old value and exclusive store result.
5385*795d594fSAndroid Build Coastguard Worker     old_value = (cas_type == DataType::Type::kInt64) ? out.X() : out.W();
5386*795d594fSAndroid Build Coastguard Worker     store_result = out.W();
5387*795d594fSAndroid Build Coastguard Worker   } else if (DataType::IsFloatingPointType(value_type)) {
5388*795d594fSAndroid Build Coastguard Worker     // We need two temporary registers but we have already used scratch registers for
5389*795d594fSAndroid Build Coastguard Worker     // holding the expected and new value unless they are zero bit pattern (+0.0f or
5390*795d594fSAndroid Build Coastguard Worker     // +0.0). We have allocated sufficient normal temporaries to handle that.
5391*795d594fSAndroid Build Coastguard Worker     size_t next_temp = 1u;
5392*795d594fSAndroid Build Coastguard Worker     if (expected.IsZero()) {
5393*795d594fSAndroid Build Coastguard Worker       old_value = (cas_type == DataType::Type::kInt64) ? temps.AcquireX() : temps.AcquireW();
5394*795d594fSAndroid Build Coastguard Worker     } else {
5395*795d594fSAndroid Build Coastguard Worker       Location temp = locations->GetTemp(next_temp);
5396*795d594fSAndroid Build Coastguard Worker       ++next_temp;
5397*795d594fSAndroid Build Coastguard Worker       old_value = (cas_type == DataType::Type::kInt64) ? XRegisterFrom(temp) : WRegisterFrom(temp);
5398*795d594fSAndroid Build Coastguard Worker     }
5399*795d594fSAndroid Build Coastguard Worker     store_result =
5400*795d594fSAndroid Build Coastguard Worker         new_value.IsZero() ? temps.AcquireW() : WRegisterFrom(locations->GetTemp(next_temp));
5401*795d594fSAndroid Build Coastguard Worker     DCHECK(!old_value.Is(tmp_ptr));
5402*795d594fSAndroid Build Coastguard Worker     DCHECK(!store_result.Is(tmp_ptr));
5403*795d594fSAndroid Build Coastguard Worker   } else {
5404*795d594fSAndroid Build Coastguard Worker     // Use the output register for the old value.
5405*795d594fSAndroid Build Coastguard Worker     old_value = (cas_type == DataType::Type::kInt64) ? out.X() : out.W();
5406*795d594fSAndroid Build Coastguard Worker     // Use scratch register for the store result, except when we have used up
5407*795d594fSAndroid Build Coastguard Worker     // scratch registers for byte-swapped `expected` and `new_value`.
5408*795d594fSAndroid Build Coastguard Worker     // In that case, we have allocated a normal temporary.
5409*795d594fSAndroid Build Coastguard Worker     store_result = (byte_swap && !expected.IsZero() && !new_value.IsZero())
5410*795d594fSAndroid Build Coastguard Worker         ? WRegisterFrom(locations->GetTemp(1))
5411*795d594fSAndroid Build Coastguard Worker         : temps.AcquireW();
5412*795d594fSAndroid Build Coastguard Worker     DCHECK(!store_result.Is(tmp_ptr));
5413*795d594fSAndroid Build Coastguard Worker   }
5414*795d594fSAndroid Build Coastguard Worker 
5415*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label exit_loop_label;
5416*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* exit_loop = &exit_loop_label;
5417*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::Label* cmp_failure = &exit_loop_label;
5418*795d594fSAndroid Build Coastguard Worker 
5419*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
5420*795d594fSAndroid Build Coastguard Worker     // The `old_value_temp` is used first for the marked `old_value` and then for the unmarked
5421*795d594fSAndroid Build Coastguard Worker     // reloaded old value for subsequent CAS in the slow path. It cannot be a scratch register.
5422*795d594fSAndroid Build Coastguard Worker     size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
5423*795d594fSAndroid Build Coastguard Worker     Register old_value_temp =
5424*795d594fSAndroid Build Coastguard Worker         WRegisterFrom(locations->GetTemp((expected_coordinates_count == 0u) ? 2u : 1u));
5425*795d594fSAndroid Build Coastguard Worker     // For strong CAS, use a scratch register for the store result in slow path.
5426*795d594fSAndroid Build Coastguard Worker     // For weak CAS, we need to check the store result, so store it in `store_result`.
5427*795d594fSAndroid Build Coastguard Worker     Register slow_path_store_result = strong ? Register() : store_result;
5428*795d594fSAndroid Build Coastguard Worker     ReadBarrierCasSlowPathARM64* rb_slow_path =
5429*795d594fSAndroid Build Coastguard Worker         new (codegen->GetScopedAllocator()) ReadBarrierCasSlowPathARM64(
5430*795d594fSAndroid Build Coastguard Worker             invoke,
5431*795d594fSAndroid Build Coastguard Worker             order,
5432*795d594fSAndroid Build Coastguard Worker             strong,
5433*795d594fSAndroid Build Coastguard Worker             target.object,
5434*795d594fSAndroid Build Coastguard Worker             target.offset.X(),
5435*795d594fSAndroid Build Coastguard Worker             expected_reg,
5436*795d594fSAndroid Build Coastguard Worker             new_value_reg,
5437*795d594fSAndroid Build Coastguard Worker             old_value,
5438*795d594fSAndroid Build Coastguard Worker             old_value_temp,
5439*795d594fSAndroid Build Coastguard Worker             slow_path_store_result,
5440*795d594fSAndroid Build Coastguard Worker             /*update_old_value=*/ !return_success,
5441*795d594fSAndroid Build Coastguard Worker             codegen);
5442*795d594fSAndroid Build Coastguard Worker     codegen->AddSlowPath(rb_slow_path);
5443*795d594fSAndroid Build Coastguard Worker     exit_loop = rb_slow_path->GetExitLabel();
5444*795d594fSAndroid Build Coastguard Worker     cmp_failure = rb_slow_path->GetEntryLabel();
5445*795d594fSAndroid Build Coastguard Worker   }
5446*795d594fSAndroid Build Coastguard Worker 
5447*795d594fSAndroid Build Coastguard Worker   GenerateCompareAndSet(codegen,
5448*795d594fSAndroid Build Coastguard Worker                         cas_type,
5449*795d594fSAndroid Build Coastguard Worker                         order,
5450*795d594fSAndroid Build Coastguard Worker                         strong,
5451*795d594fSAndroid Build Coastguard Worker                         cmp_failure,
5452*795d594fSAndroid Build Coastguard Worker                         tmp_ptr,
5453*795d594fSAndroid Build Coastguard Worker                         new_value_reg,
5454*795d594fSAndroid Build Coastguard Worker                         old_value,
5455*795d594fSAndroid Build Coastguard Worker                         store_result,
5456*795d594fSAndroid Build Coastguard Worker                         expected_reg);
5457*795d594fSAndroid Build Coastguard Worker   __ Bind(exit_loop);
5458*795d594fSAndroid Build Coastguard Worker 
5459*795d594fSAndroid Build Coastguard Worker   if (return_success) {
5460*795d594fSAndroid Build Coastguard Worker     if (strong) {
5461*795d594fSAndroid Build Coastguard Worker       __ Cset(out.W(), eq);
5462*795d594fSAndroid Build Coastguard Worker     } else {
5463*795d594fSAndroid Build Coastguard Worker       // On success, the Z flag is set and the store result is 1, see GenerateCompareAndSet().
5464*795d594fSAndroid Build Coastguard Worker       // On failure, either the Z flag is clear or the store result is 0.
5465*795d594fSAndroid Build Coastguard Worker       // Determine the final success value with a CSEL.
5466*795d594fSAndroid Build Coastguard Worker       __ Csel(out.W(), store_result, wzr, eq);
5467*795d594fSAndroid Build Coastguard Worker     }
5468*795d594fSAndroid Build Coastguard Worker   } else if (byte_swap) {
5469*795d594fSAndroid Build Coastguard Worker     // Also handles moving to FP registers.
5470*795d594fSAndroid Build Coastguard Worker     GenerateReverseBytes(masm, value_type, old_value, out);
5471*795d594fSAndroid Build Coastguard Worker   } else if (DataType::IsFloatingPointType(value_type)) {
5472*795d594fSAndroid Build Coastguard Worker     __ Fmov((value_type == DataType::Type::kFloat64) ? out.D() : out.S(), old_value);
5473*795d594fSAndroid Build Coastguard Worker   } else if (value_type == DataType::Type::kInt8) {
5474*795d594fSAndroid Build Coastguard Worker     __ Sxtb(out.W(), old_value);
5475*795d594fSAndroid Build Coastguard Worker   } else if (value_type == DataType::Type::kInt16) {
5476*795d594fSAndroid Build Coastguard Worker     __ Sxth(out.W(), old_value);
5477*795d594fSAndroid Build Coastguard Worker   }
5478*795d594fSAndroid Build Coastguard Worker 
5479*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
5480*795d594fSAndroid Build Coastguard Worker     DCHECK(!byte_swap);
5481*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
5482*795d594fSAndroid Build Coastguard Worker   }
5483*795d594fSAndroid Build Coastguard Worker }
5484*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchange(HInvoke * invoke)5485*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
5486*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
5487*795d594fSAndroid Build Coastguard Worker }
5488*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchange(HInvoke * invoke)5489*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
5490*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5491*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ false, /*strong=*/ true);
5492*795d594fSAndroid Build Coastguard Worker }
5493*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)5494*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
5495*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
5496*795d594fSAndroid Build Coastguard Worker }
5497*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)5498*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
5499*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5500*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_acquire, /*return_success=*/ false, /*strong=*/ true);
5501*795d594fSAndroid Build Coastguard Worker }
5502*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)5503*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
5504*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
5505*795d594fSAndroid Build Coastguard Worker }
5506*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)5507*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
5508*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5509*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_release, /*return_success=*/ false, /*strong=*/ true);
5510*795d594fSAndroid Build Coastguard Worker }
5511*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndSet(HInvoke * invoke)5512*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleCompareAndSet(HInvoke* invoke) {
5513*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
5514*795d594fSAndroid Build Coastguard Worker }
5515*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndSet(HInvoke * invoke)5516*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleCompareAndSet(HInvoke* invoke) {
5517*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5518*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ true, /*strong=*/ true);
5519*795d594fSAndroid Build Coastguard Worker }
5520*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)5521*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
5522*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
5523*795d594fSAndroid Build Coastguard Worker }
5524*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)5525*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
5526*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5527*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ true, /*strong=*/ false);
5528*795d594fSAndroid Build Coastguard Worker }
5529*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)5530*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
5531*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
5532*795d594fSAndroid Build Coastguard Worker }
5533*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)5534*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
5535*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5536*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_acquire, /*return_success=*/ true, /*strong=*/ false);
5537*795d594fSAndroid Build Coastguard Worker }
5538*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)5539*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
5540*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
5541*795d594fSAndroid Build Coastguard Worker }
5542*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)5543*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
5544*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5545*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_relaxed, /*return_success=*/ true, /*strong=*/ false);
5546*795d594fSAndroid Build Coastguard Worker }
5547*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)5548*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
5549*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
5550*795d594fSAndroid Build Coastguard Worker }
5551*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)5552*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
5553*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(
5554*795d594fSAndroid Build Coastguard Worker       invoke, codegen_, std::memory_order_release, /*return_success=*/ true, /*strong=*/ false);
5555*795d594fSAndroid Build Coastguard Worker }
5556*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetAndUpdateLocations(HInvoke * invoke,CodeGeneratorARM64 * codegen,GetAndUpdateOp get_and_update_op)5557*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
5558*795d594fSAndroid Build Coastguard Worker                                                  CodeGeneratorARM64* codegen,
5559*795d594fSAndroid Build Coastguard Worker                                                  GetAndUpdateOp get_and_update_op) {
5560*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
5561*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetDoNotIntrinsify()) {
5562*795d594fSAndroid Build Coastguard Worker     return;
5563*795d594fSAndroid Build Coastguard Worker   }
5564*795d594fSAndroid Build Coastguard Worker 
5565*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
5566*795d594fSAndroid Build Coastguard Worker   uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
5567*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
5568*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
5569*795d594fSAndroid Build Coastguard Worker     // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
5570*795d594fSAndroid Build Coastguard Worker     // the passed reference and reloads it from the field, thus seeing the new value
5571*795d594fSAndroid Build Coastguard Worker     // that we have just stored. (And it also gets the memory visibility wrong.) b/173104084
5572*795d594fSAndroid Build Coastguard Worker     return;
5573*795d594fSAndroid Build Coastguard Worker   }
5574*795d594fSAndroid Build Coastguard Worker 
5575*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
5576*795d594fSAndroid Build Coastguard Worker   size_t old_temp_count = locations->GetTempCount();
5577*795d594fSAndroid Build Coastguard Worker 
5578*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(old_temp_count, (GetExpectedVarHandleCoordinatesCount(invoke) == 0) ? 2u : 1u);
5579*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(value_type)) {
5580*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAdd) {
5581*795d594fSAndroid Build Coastguard Worker       // For ADD, do not use ZR for zero bit pattern (+0.0f or +0.0).
5582*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(invoke->GetNumberOfArguments() - 1u, Location::RequiresFpuRegister());
5583*795d594fSAndroid Build Coastguard Worker     } else {
5584*795d594fSAndroid Build Coastguard Worker       DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
5585*795d594fSAndroid Build Coastguard Worker       // We can reuse the declaring class temporary if present.
5586*795d594fSAndroid Build Coastguard Worker       if (old_temp_count == 1u &&
5587*795d594fSAndroid Build Coastguard Worker           !IsZeroBitPattern(invoke->InputAt(invoke->GetNumberOfArguments() - 1u))) {
5588*795d594fSAndroid Build Coastguard Worker         // Add a temporary for `old_value` if floating point `new_value` takes a scratch register.
5589*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresRegister());
5590*795d594fSAndroid Build Coastguard Worker       }
5591*795d594fSAndroid Build Coastguard Worker     }
5592*795d594fSAndroid Build Coastguard Worker   }
5593*795d594fSAndroid Build Coastguard Worker   // We need a temporary for the byte-swap path for bitwise operations unless the argument is a
5594*795d594fSAndroid Build Coastguard Worker   // zero which does not need a byte-swap. We can reuse the declaring class temporary if present.
5595*795d594fSAndroid Build Coastguard Worker   if (old_temp_count == 1u &&
5596*795d594fSAndroid Build Coastguard Worker       (get_and_update_op != GetAndUpdateOp::kSet && get_and_update_op != GetAndUpdateOp::kAdd) &&
5597*795d594fSAndroid Build Coastguard Worker       GetExpectedVarHandleCoordinatesCount(invoke) == 2u &&
5598*795d594fSAndroid Build Coastguard Worker       !IsZeroBitPattern(invoke->InputAt(invoke->GetNumberOfArguments() - 1u))) {
5599*795d594fSAndroid Build Coastguard Worker     if (value_type != DataType::Type::kReference && DataType::Size(value_type) != 1u) {
5600*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
5601*795d594fSAndroid Build Coastguard Worker     }
5602*795d594fSAndroid Build Coastguard Worker   }
5603*795d594fSAndroid Build Coastguard Worker 
5604*795d594fSAndroid Build Coastguard Worker   // Request another temporary register for methods that don't return a value.
5605*795d594fSAndroid Build Coastguard Worker   // For the non-void case, we already set `out` in `CreateVarHandleCommonLocations`.
5606*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
5607*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
5608*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
5609*795d594fSAndroid Build Coastguard Worker   if (is_void) {
5610*795d594fSAndroid Build Coastguard Worker     if (DataType::IsFloatingPointType(value_type)) {
5611*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
5612*795d594fSAndroid Build Coastguard Worker     } else {
5613*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
5614*795d594fSAndroid Build Coastguard Worker     }
5615*795d594fSAndroid Build Coastguard Worker   }
5616*795d594fSAndroid Build Coastguard Worker }
5617*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGetAndUpdate(HInvoke * invoke,CodeGeneratorARM64 * codegen,GetAndUpdateOp get_and_update_op,std::memory_order order,bool byte_swap=false)5618*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
5619*795d594fSAndroid Build Coastguard Worker                                           CodeGeneratorARM64* codegen,
5620*795d594fSAndroid Build Coastguard Worker                                           GetAndUpdateOp get_and_update_op,
5621*795d594fSAndroid Build Coastguard Worker                                           std::memory_order order,
5622*795d594fSAndroid Build Coastguard Worker                                           bool byte_swap = false) {
5623*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
5624*795d594fSAndroid Build Coastguard Worker   uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
5625*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
5626*795d594fSAndroid Build Coastguard Worker   bool is_fp = DataType::IsFloatingPointType(value_type);
5627*795d594fSAndroid Build Coastguard Worker 
5628*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
5629*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
5630*795d594fSAndroid Build Coastguard Worker   CPURegister arg = (is_fp && get_and_update_op == GetAndUpdateOp::kAdd)
5631*795d594fSAndroid Build Coastguard Worker       ? InputCPURegisterAt(invoke, arg_index)
5632*795d594fSAndroid Build Coastguard Worker       : InputCPURegisterOrZeroRegAt(invoke, arg_index);
5633*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
5634*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
5635*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
5636*795d594fSAndroid Build Coastguard Worker   // We use a temporary for void methods, as we don't return the value.
5637*795d594fSAndroid Build Coastguard Worker   CPURegister out_or_temp =
5638*795d594fSAndroid Build Coastguard Worker       is_void ? CPURegisterFrom(locations->GetTemp(locations->GetTempCount() - 1u), value_type) :
5639*795d594fSAndroid Build Coastguard Worker                 helpers::OutputCPURegister(invoke);
5640*795d594fSAndroid Build Coastguard Worker 
5641*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target = GetVarHandleTarget(invoke);
5642*795d594fSAndroid Build Coastguard Worker   VarHandleSlowPathARM64* slow_path = nullptr;
5643*795d594fSAndroid Build Coastguard Worker   if (!byte_swap) {
5644*795d594fSAndroid Build Coastguard Worker     slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
5645*795d594fSAndroid Build Coastguard Worker     GenerateVarHandleTarget(invoke, target, codegen);
5646*795d594fSAndroid Build Coastguard Worker     if (slow_path != nullptr) {
5647*795d594fSAndroid Build Coastguard Worker       slow_path->SetGetAndUpdateOp(get_and_update_op);
5648*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetNativeByteOrderLabel());
5649*795d594fSAndroid Build Coastguard Worker     }
5650*795d594fSAndroid Build Coastguard Worker   }
5651*795d594fSAndroid Build Coastguard Worker 
5652*795d594fSAndroid Build Coastguard Worker   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
5653*795d594fSAndroid Build Coastguard Worker   if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(arg_index))) {
5654*795d594fSAndroid Build Coastguard Worker     DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
5655*795d594fSAndroid Build Coastguard Worker     // Mark card for object, the new value shall be stored.
5656*795d594fSAndroid Build Coastguard Worker     bool new_value_can_be_null = true;  // TODO: Worth finding out this information?
5657*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(target.object, arg.W(), new_value_can_be_null);
5658*795d594fSAndroid Build Coastguard Worker   }
5659*795d594fSAndroid Build Coastguard Worker 
5660*795d594fSAndroid Build Coastguard Worker   // Reuse the `target.offset` temporary for the pointer to the target location,
5661*795d594fSAndroid Build Coastguard Worker   // except for references that need the offset for the non-Baker read barrier.
5662*795d594fSAndroid Build Coastguard Worker   UseScratchRegisterScope temps(masm);
5663*795d594fSAndroid Build Coastguard Worker   Register tmp_ptr = target.offset.X();
5664*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
5665*795d594fSAndroid Build Coastguard Worker     tmp_ptr = temps.AcquireX();
5666*795d594fSAndroid Build Coastguard Worker   }
5667*795d594fSAndroid Build Coastguard Worker   __ Add(tmp_ptr, target.object.X(), target.offset.X());
5668*795d594fSAndroid Build Coastguard Worker 
5669*795d594fSAndroid Build Coastguard Worker   // The load/store type is never floating point.
5670*795d594fSAndroid Build Coastguard Worker   DataType::Type load_store_type = is_fp
5671*795d594fSAndroid Build Coastguard Worker       ? ((value_type == DataType::Type::kFloat32) ? DataType::Type::kInt32 : DataType::Type::kInt64)
5672*795d594fSAndroid Build Coastguard Worker       : value_type;
5673*795d594fSAndroid Build Coastguard Worker   // Avoid sign extension in the CAS loop. Sign-extend after the loop.
5674*795d594fSAndroid Build Coastguard Worker   // Note: Using unsigned values yields the same value to store (we do not store higher bits).
5675*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kInt8) {
5676*795d594fSAndroid Build Coastguard Worker     load_store_type = DataType::Type::kUint8;
5677*795d594fSAndroid Build Coastguard Worker   } else if (value_type == DataType::Type::kInt16) {
5678*795d594fSAndroid Build Coastguard Worker     load_store_type = DataType::Type::kUint16;
5679*795d594fSAndroid Build Coastguard Worker   }
5680*795d594fSAndroid Build Coastguard Worker 
5681*795d594fSAndroid Build Coastguard Worker   // Prepare register for old value.
5682*795d594fSAndroid Build Coastguard Worker   CPURegister old_value = out_or_temp;
5683*795d594fSAndroid Build Coastguard Worker   if (get_and_update_op == GetAndUpdateOp::kSet) {
5684*795d594fSAndroid Build Coastguard Worker     // For floating point GetAndSet, do the GenerateGetAndUpdate() with core registers,
5685*795d594fSAndroid Build Coastguard Worker     // rather than moving between core and FP registers in the loop.
5686*795d594fSAndroid Build Coastguard Worker     arg = MoveToTempIfFpRegister(arg, value_type, masm, &temps);
5687*795d594fSAndroid Build Coastguard Worker     if (is_fp && !arg.IsZero()) {
5688*795d594fSAndroid Build Coastguard Worker       // We need a temporary register but we have already used a scratch register for
5689*795d594fSAndroid Build Coastguard Worker       // the new value unless it is zero bit pattern (+0.0f or +0.0) and need another one
5690*795d594fSAndroid Build Coastguard Worker       // in GenerateGetAndUpdate(). We have allocated a normal temporary to handle that.
5691*795d594fSAndroid Build Coastguard Worker       old_value = CPURegisterFrom(locations->GetTemp(1u), load_store_type);
5692*795d594fSAndroid Build Coastguard Worker     } else if (value_type == DataType::Type::kReference && codegen->EmitBakerReadBarrier()) {
5693*795d594fSAndroid Build Coastguard Worker       // Load the old value initially to a scratch register.
5694*795d594fSAndroid Build Coastguard Worker       // We shall move it to `out` later with a read barrier.
5695*795d594fSAndroid Build Coastguard Worker       old_value = temps.AcquireW();
5696*795d594fSAndroid Build Coastguard Worker     }
5697*795d594fSAndroid Build Coastguard Worker   }
5698*795d594fSAndroid Build Coastguard Worker 
5699*795d594fSAndroid Build Coastguard Worker   if (byte_swap) {
5700*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(value_type, DataType::Type::kReference);
5701*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(DataType::Size(value_type), 1u);
5702*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAdd) {
5703*795d594fSAndroid Build Coastguard Worker       // We need to do the byte swapping in the CAS loop for GetAndAdd.
5704*795d594fSAndroid Build Coastguard Worker       get_and_update_op = GetAndUpdateOp::kAddWithByteSwap;
5705*795d594fSAndroid Build Coastguard Worker     } else if (!arg.IsZero()) {
5706*795d594fSAndroid Build Coastguard Worker       // For other operations, avoid byte swap inside the CAS loop by providing an adjusted `arg`.
5707*795d594fSAndroid Build Coastguard Worker       // For GetAndSet use a scratch register; FP argument is already in a scratch register.
5708*795d594fSAndroid Build Coastguard Worker       // For bitwise operations GenerateGetAndUpdate() needs both scratch registers;
5709*795d594fSAndroid Build Coastguard Worker       // we have allocated a normal temporary to handle that.
5710*795d594fSAndroid Build Coastguard Worker       CPURegister temp = (get_and_update_op == GetAndUpdateOp::kSet)
5711*795d594fSAndroid Build Coastguard Worker           ? (is_fp ? arg : (arg.Is64Bits() ? temps.AcquireX() : temps.AcquireW()))
5712*795d594fSAndroid Build Coastguard Worker           : CPURegisterFrom(locations->GetTemp(1u), load_store_type);
5713*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, load_store_type, arg, temp);
5714*795d594fSAndroid Build Coastguard Worker       arg = temp;
5715*795d594fSAndroid Build Coastguard Worker     }
5716*795d594fSAndroid Build Coastguard Worker   }
5717*795d594fSAndroid Build Coastguard Worker 
5718*795d594fSAndroid Build Coastguard Worker   GenerateGetAndUpdate(codegen, get_and_update_op, load_store_type, order, tmp_ptr, arg, old_value);
5719*795d594fSAndroid Build Coastguard Worker 
5720*795d594fSAndroid Build Coastguard Worker   if (!is_void) {
5721*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAddWithByteSwap) {
5722*795d594fSAndroid Build Coastguard Worker       // The only adjustment needed is sign-extension for `kInt16`.
5723*795d594fSAndroid Build Coastguard Worker       // Everything else has been done by the `GenerateGetAndUpdate()`.
5724*795d594fSAndroid Build Coastguard Worker       DCHECK(byte_swap);
5725*795d594fSAndroid Build Coastguard Worker       if (value_type == DataType::Type::kInt16) {
5726*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(load_store_type, DataType::Type::kUint16);
5727*795d594fSAndroid Build Coastguard Worker         __ Sxth(out_or_temp.W(), old_value.W());
5728*795d594fSAndroid Build Coastguard Worker       }
5729*795d594fSAndroid Build Coastguard Worker     } else if (byte_swap) {
5730*795d594fSAndroid Build Coastguard Worker       // Also handles moving to FP registers.
5731*795d594fSAndroid Build Coastguard Worker       GenerateReverseBytes(masm, value_type, old_value, out_or_temp);
5732*795d594fSAndroid Build Coastguard Worker     } else if (get_and_update_op == GetAndUpdateOp::kSet &&
5733*795d594fSAndroid Build Coastguard Worker                value_type == DataType::Type::kFloat64) {
5734*795d594fSAndroid Build Coastguard Worker       __ Fmov(out_or_temp.D(), old_value.X());
5735*795d594fSAndroid Build Coastguard Worker     } else if (get_and_update_op == GetAndUpdateOp::kSet &&
5736*795d594fSAndroid Build Coastguard Worker                value_type == DataType::Type::kFloat32) {
5737*795d594fSAndroid Build Coastguard Worker       __ Fmov(out_or_temp.S(), old_value.W());
5738*795d594fSAndroid Build Coastguard Worker     } else if (value_type == DataType::Type::kInt8) {
5739*795d594fSAndroid Build Coastguard Worker       __ Sxtb(out_or_temp.W(), old_value.W());
5740*795d594fSAndroid Build Coastguard Worker     } else if (value_type == DataType::Type::kInt16) {
5741*795d594fSAndroid Build Coastguard Worker       __ Sxth(out_or_temp.W(), old_value.W());
5742*795d594fSAndroid Build Coastguard Worker     } else if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
5743*795d594fSAndroid Build Coastguard Worker       if (kUseBakerReadBarrier) {
5744*795d594fSAndroid Build Coastguard Worker         codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out_or_temp.W(), old_value.W());
5745*795d594fSAndroid Build Coastguard Worker       } else {
5746*795d594fSAndroid Build Coastguard Worker         codegen->GenerateReadBarrierSlow(
5747*795d594fSAndroid Build Coastguard Worker             invoke,
5748*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(out_or_temp.GetCode()),
5749*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(old_value.GetCode()),
5750*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(target.object.GetCode()),
5751*795d594fSAndroid Build Coastguard Worker             /*offset=*/0u,
5752*795d594fSAndroid Build Coastguard Worker             /*index=*/Location::RegisterLocation(target.offset.GetCode()));
5753*795d594fSAndroid Build Coastguard Worker       }
5754*795d594fSAndroid Build Coastguard Worker     }
5755*795d594fSAndroid Build Coastguard Worker   }
5756*795d594fSAndroid Build Coastguard Worker 
5757*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
5758*795d594fSAndroid Build Coastguard Worker     DCHECK(!byte_swap);
5759*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
5760*795d594fSAndroid Build Coastguard Worker   }
5761*795d594fSAndroid Build Coastguard Worker }
5762*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSet(HInvoke * invoke)5763*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndSet(HInvoke* invoke) {
5764*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
5765*795d594fSAndroid Build Coastguard Worker }
5766*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSet(HInvoke * invoke)5767*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndSet(HInvoke* invoke) {
5768*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_seq_cst);
5769*795d594fSAndroid Build Coastguard Worker }
5770*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)5771*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
5772*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
5773*795d594fSAndroid Build Coastguard Worker }
5774*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)5775*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
5776*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_acquire);
5777*795d594fSAndroid Build Coastguard Worker }
5778*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetRelease(HInvoke * invoke)5779*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
5780*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
5781*795d594fSAndroid Build Coastguard Worker }
5782*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetRelease(HInvoke * invoke)5783*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
5784*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_release);
5785*795d594fSAndroid Build Coastguard Worker }
5786*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAdd(HInvoke * invoke)5787*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndAdd(HInvoke* invoke) {
5788*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
5789*795d594fSAndroid Build Coastguard Worker }
5790*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAdd(HInvoke * invoke)5791*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndAdd(HInvoke* invoke) {
5792*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_seq_cst);
5793*795d594fSAndroid Build Coastguard Worker }
5794*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)5795*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
5796*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
5797*795d594fSAndroid Build Coastguard Worker }
5798*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)5799*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
5800*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_acquire);
5801*795d594fSAndroid Build Coastguard Worker }
5802*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddRelease(HInvoke * invoke)5803*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
5804*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
5805*795d594fSAndroid Build Coastguard Worker }
5806*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddRelease(HInvoke * invoke)5807*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
5808*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_release);
5809*795d594fSAndroid Build Coastguard Worker }
5810*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)5811*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
5812*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
5813*795d594fSAndroid Build Coastguard Worker }
5814*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)5815*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
5816*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_seq_cst);
5817*795d594fSAndroid Build Coastguard Worker }
5818*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)5819*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
5820*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
5821*795d594fSAndroid Build Coastguard Worker }
5822*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)5823*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
5824*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_acquire);
5825*795d594fSAndroid Build Coastguard Worker }
5826*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)5827*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
5828*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
5829*795d594fSAndroid Build Coastguard Worker }
5830*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)5831*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
5832*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_release);
5833*795d594fSAndroid Build Coastguard Worker }
5834*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)5835*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
5836*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
5837*795d594fSAndroid Build Coastguard Worker }
5838*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)5839*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
5840*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_seq_cst);
5841*795d594fSAndroid Build Coastguard Worker }
5842*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)5843*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
5844*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
5845*795d594fSAndroid Build Coastguard Worker }
5846*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)5847*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
5848*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_acquire);
5849*795d594fSAndroid Build Coastguard Worker }
5850*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5851*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5852*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
5853*795d594fSAndroid Build Coastguard Worker }
5854*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5855*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5856*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_release);
5857*795d594fSAndroid Build Coastguard Worker }
5858*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5859*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5860*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5861*795d594fSAndroid Build Coastguard Worker }
5862*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5863*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5864*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_seq_cst);
5865*795d594fSAndroid Build Coastguard Worker }
5866*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5867*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5868*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5869*795d594fSAndroid Build Coastguard Worker }
5870*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5871*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5872*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_acquire);
5873*795d594fSAndroid Build Coastguard Worker }
5874*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5875*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5876*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5877*795d594fSAndroid Build Coastguard Worker }
5878*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5879*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5880*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_release);
5881*795d594fSAndroid Build Coastguard Worker }
5882*795d594fSAndroid Build Coastguard Worker 
EmitByteArrayViewCode(CodeGenerator * codegen_in)5883*795d594fSAndroid Build Coastguard Worker void VarHandleSlowPathARM64::EmitByteArrayViewCode(CodeGenerator* codegen_in) {
5884*795d594fSAndroid Build Coastguard Worker   DCHECK(GetByteArrayViewCheckLabel()->IsLinked());
5885*795d594fSAndroid Build Coastguard Worker   CodeGeneratorARM64* codegen = down_cast<CodeGeneratorARM64*>(codegen_in);
5886*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen->GetVIXLAssembler();
5887*795d594fSAndroid Build Coastguard Worker   HInvoke* invoke = GetInvoke();
5888*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessModeTemplate access_mode_template = GetAccessModeTemplate();
5889*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type =
5890*795d594fSAndroid Build Coastguard Worker       GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
5891*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(value_type, DataType::Type::kReference);
5892*795d594fSAndroid Build Coastguard Worker   size_t size = DataType::Size(value_type);
5893*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(size, 1u);
5894*795d594fSAndroid Build Coastguard Worker   Register varhandle = InputRegisterAt(invoke, 0);
5895*795d594fSAndroid Build Coastguard Worker   Register object = InputRegisterAt(invoke, 1);
5896*795d594fSAndroid Build Coastguard Worker   Register index = InputRegisterAt(invoke, 2);
5897*795d594fSAndroid Build Coastguard Worker 
5898*795d594fSAndroid Build Coastguard Worker   MemberOffset class_offset = mirror::Object::ClassOffset();
5899*795d594fSAndroid Build Coastguard Worker   MemberOffset array_length_offset = mirror::Array::LengthOffset();
5900*795d594fSAndroid Build Coastguard Worker   MemberOffset data_offset = mirror::Array::DataOffset(Primitive::kPrimByte);
5901*795d594fSAndroid Build Coastguard Worker   MemberOffset native_byte_order_offset = mirror::ByteArrayViewVarHandle::NativeByteOrderOffset();
5902*795d594fSAndroid Build Coastguard Worker 
5903*795d594fSAndroid Build Coastguard Worker   __ Bind(GetByteArrayViewCheckLabel());
5904*795d594fSAndroid Build Coastguard Worker 
5905*795d594fSAndroid Build Coastguard Worker   VarHandleTarget target = GetVarHandleTarget(invoke);
5906*795d594fSAndroid Build Coastguard Worker   {
5907*795d594fSAndroid Build Coastguard Worker     UseScratchRegisterScope temps(masm);
5908*795d594fSAndroid Build Coastguard Worker     Register temp = temps.AcquireW();
5909*795d594fSAndroid Build Coastguard Worker     Register temp2 = temps.AcquireW();
5910*795d594fSAndroid Build Coastguard Worker 
5911*795d594fSAndroid Build Coastguard Worker     // The main path checked that the coordinateType0 is an array class that matches
5912*795d594fSAndroid Build Coastguard Worker     // the class of the actual coordinate argument but it does not match the value type.
5913*795d594fSAndroid Build Coastguard Worker     // Check if the `varhandle` references a ByteArrayViewVarHandle instance.
5914*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, HeapOperand(varhandle, class_offset.Int32Value()));
5915*795d594fSAndroid Build Coastguard Worker     codegen->GetAssembler()->MaybeUnpoisonHeapReference(temp);
5916*795d594fSAndroid Build Coastguard Worker     codegen->LoadClassRootForIntrinsic(temp2, ClassRoot::kJavaLangInvokeByteArrayViewVarHandle);
5917*795d594fSAndroid Build Coastguard Worker     __ Cmp(temp, temp2);
5918*795d594fSAndroid Build Coastguard Worker     __ B(GetEntryLabel(), ne);
5919*795d594fSAndroid Build Coastguard Worker 
5920*795d594fSAndroid Build Coastguard Worker     // Check for array index out of bounds.
5921*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, HeapOperand(object, array_length_offset.Int32Value()));
5922*795d594fSAndroid Build Coastguard Worker     __ Subs(temp, temp, index);
5923*795d594fSAndroid Build Coastguard Worker     __ Ccmp(temp, size, NoFlag, hs);  // If SUBS yields LO (C=false), keep the C flag clear.
5924*795d594fSAndroid Build Coastguard Worker     __ B(GetEntryLabel(), lo);
5925*795d594fSAndroid Build Coastguard Worker 
5926*795d594fSAndroid Build Coastguard Worker     // Construct the target.
5927*795d594fSAndroid Build Coastguard Worker     __ Add(target.offset, index, data_offset.Int32Value());
5928*795d594fSAndroid Build Coastguard Worker 
5929*795d594fSAndroid Build Coastguard Worker     // Alignment check. For unaligned access, go to the runtime.
5930*795d594fSAndroid Build Coastguard Worker     DCHECK(IsPowerOfTwo(size));
5931*795d594fSAndroid Build Coastguard Worker     if (size == 2u) {
5932*795d594fSAndroid Build Coastguard Worker       __ Tbnz(target.offset, 0, GetEntryLabel());
5933*795d594fSAndroid Build Coastguard Worker     } else {
5934*795d594fSAndroid Build Coastguard Worker       __ Tst(target.offset, size - 1u);
5935*795d594fSAndroid Build Coastguard Worker       __ B(GetEntryLabel(), ne);
5936*795d594fSAndroid Build Coastguard Worker     }
5937*795d594fSAndroid Build Coastguard Worker 
5938*795d594fSAndroid Build Coastguard Worker     // Byte order check. For native byte order return to the main path.
5939*795d594fSAndroid Build Coastguard Worker     if (access_mode_template == mirror::VarHandle::AccessModeTemplate::kSet &&
5940*795d594fSAndroid Build Coastguard Worker         IsZeroBitPattern(invoke->InputAt(invoke->GetNumberOfArguments() - 1u))) {
5941*795d594fSAndroid Build Coastguard Worker       // There is no reason to differentiate between native byte order and byte-swap
5942*795d594fSAndroid Build Coastguard Worker       // for setting a zero bit pattern. Just return to the main path.
5943*795d594fSAndroid Build Coastguard Worker       __ B(GetNativeByteOrderLabel());
5944*795d594fSAndroid Build Coastguard Worker       return;
5945*795d594fSAndroid Build Coastguard Worker     }
5946*795d594fSAndroid Build Coastguard Worker     __ Ldr(temp, HeapOperand(varhandle, native_byte_order_offset.Int32Value()));
5947*795d594fSAndroid Build Coastguard Worker     __ Cbnz(temp, GetNativeByteOrderLabel());
5948*795d594fSAndroid Build Coastguard Worker   }
5949*795d594fSAndroid Build Coastguard Worker 
5950*795d594fSAndroid Build Coastguard Worker   switch (access_mode_template) {
5951*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kGet:
5952*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleGet(invoke, codegen, order_, /*byte_swap=*/ true);
5953*795d594fSAndroid Build Coastguard Worker       break;
5954*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kSet:
5955*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleSet(invoke, codegen, order_, /*byte_swap=*/ true);
5956*795d594fSAndroid Build Coastguard Worker       break;
5957*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kCompareAndSet:
5958*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange:
5959*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleCompareAndSetOrExchange(
5960*795d594fSAndroid Build Coastguard Worker           invoke, codegen, order_, return_success_, strong_, /*byte_swap=*/ true);
5961*795d594fSAndroid Build Coastguard Worker       break;
5962*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate:
5963*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleGetAndUpdate(
5964*795d594fSAndroid Build Coastguard Worker           invoke, codegen, get_and_update_op_, order_, /*byte_swap=*/ true);
5965*795d594fSAndroid Build Coastguard Worker       break;
5966*795d594fSAndroid Build Coastguard Worker   }
5967*795d594fSAndroid Build Coastguard Worker   __ B(GetExitLabel());
5968*795d594fSAndroid Build Coastguard Worker }
5969*795d594fSAndroid Build Coastguard Worker 
VisitMethodHandleInvokeExact(HInvoke * invoke)5970*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderARM64::VisitMethodHandleInvokeExact(HInvoke* invoke) {
5971*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
5972*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator)
5973*795d594fSAndroid Build Coastguard Worker       LocationSummary(invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
5974*795d594fSAndroid Build Coastguard Worker 
5975*795d594fSAndroid Build Coastguard Worker   InvokeDexCallingConventionVisitorARM64 calling_convention;
5976*795d594fSAndroid Build Coastguard Worker   locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
5977*795d594fSAndroid Build Coastguard Worker 
5978*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
5979*795d594fSAndroid Build Coastguard Worker 
5980*795d594fSAndroid Build Coastguard Worker   // Accomodating LocationSummary for underlying invoke-* call.
5981*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_args = invoke->GetNumberOfArguments();
5982*795d594fSAndroid Build Coastguard Worker   for (uint32_t i = 1; i < number_of_args; ++i) {
5983*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(i, calling_convention.GetNextLocation(invoke->InputAt(i)->GetType()));
5984*795d594fSAndroid Build Coastguard Worker   }
5985*795d594fSAndroid Build Coastguard Worker 
5986*795d594fSAndroid Build Coastguard Worker   // The last input is MethodType object corresponding to the call-site.
5987*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(number_of_args, Location::RequiresRegister());
5988*795d594fSAndroid Build Coastguard Worker 
5989*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
5990*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(calling_convention.GetMethodLocation());
5991*795d594fSAndroid Build Coastguard Worker }
5992*795d594fSAndroid Build Coastguard Worker 
VisitMethodHandleInvokeExact(HInvoke * invoke)5993*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorARM64::VisitMethodHandleInvokeExact(HInvoke* invoke) {
5994*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
5995*795d594fSAndroid Build Coastguard Worker 
5996*795d594fSAndroid Build Coastguard Worker   Register method_handle = InputRegisterAt(invoke, 0);
5997*795d594fSAndroid Build Coastguard Worker 
5998*795d594fSAndroid Build Coastguard Worker   SlowPathCodeARM64* slow_path =
5999*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) InvokePolymorphicSlowPathARM64(invoke, method_handle);
6000*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
6001*795d594fSAndroid Build Coastguard Worker   MacroAssembler* masm = codegen_->GetVIXLAssembler();
6002*795d594fSAndroid Build Coastguard Worker 
6003*795d594fSAndroid Build Coastguard Worker   Register call_site_type = InputRegisterAt(invoke, invoke->GetNumberOfArguments());
6004*795d594fSAndroid Build Coastguard Worker 
6005*795d594fSAndroid Build Coastguard Worker   // Call site should match with MethodHandle's type.
6006*795d594fSAndroid Build Coastguard Worker   Register temp = WRegisterFrom(locations->GetTemp(0));
6007*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(method_handle.W(), mirror::MethodHandle::MethodTypeOffset()));
6008*795d594fSAndroid Build Coastguard Worker   codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp);
6009*795d594fSAndroid Build Coastguard Worker   __ Cmp(call_site_type, temp);
6010*795d594fSAndroid Build Coastguard Worker   __ B(ne, slow_path->GetEntryLabel());
6011*795d594fSAndroid Build Coastguard Worker 
6012*795d594fSAndroid Build Coastguard Worker   __ Ldr(temp, HeapOperand(method_handle.W(), mirror::MethodHandle::HandleKindOffset()));
6013*795d594fSAndroid Build Coastguard Worker   __ Cmp(temp, Operand(mirror::MethodHandle::Kind::kInvokeStatic));
6014*795d594fSAndroid Build Coastguard Worker   __ B(ne, slow_path->GetEntryLabel());
6015*795d594fSAndroid Build Coastguard Worker 
6016*795d594fSAndroid Build Coastguard Worker   Register method = XRegisterFrom(locations->GetTemp(1));
6017*795d594fSAndroid Build Coastguard Worker   __ Ldr(method, HeapOperand(method_handle.W(), mirror::MethodHandle::ArtFieldOrMethodOffset()));
6018*795d594fSAndroid Build Coastguard Worker   Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize);
6019*795d594fSAndroid Build Coastguard Worker   __ Ldr(lr, MemOperand(method, entry_point.SizeValue()));
6020*795d594fSAndroid Build Coastguard Worker   __ Blr(lr);
6021*795d594fSAndroid Build Coastguard Worker   codegen_->RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
6022*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
6023*795d594fSAndroid Build Coastguard Worker }
6024*795d594fSAndroid Build Coastguard Worker 
6025*795d594fSAndroid Build Coastguard Worker #define MARK_UNIMPLEMENTED(Name) UNIMPLEMENTED_INTRINSIC(ARM64, Name)
6026*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED_INTRINSIC_LIST_ARM64(MARK_UNIMPLEMENTED);
6027*795d594fSAndroid Build Coastguard Worker #undef MARK_UNIMPLEMENTED
6028*795d594fSAndroid Build Coastguard Worker 
6029*795d594fSAndroid Build Coastguard Worker UNREACHABLE_INTRINSICS(ARM64)
6030*795d594fSAndroid Build Coastguard Worker 
6031*795d594fSAndroid Build Coastguard Worker #undef __
6032*795d594fSAndroid Build Coastguard Worker 
6033*795d594fSAndroid Build Coastguard Worker }  // namespace arm64
6034*795d594fSAndroid Build Coastguard Worker }  // namespace art
6035