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