xref: /aosp_15_r20/art/compiler/optimizing/intrinsics_x86.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "intrinsics_x86.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <limits>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "arch/x86/instruction_set_features_x86.h"
22*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "code_generator_x86.h"
25*795d594fSAndroid Build Coastguard Worker #include "data_type-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
27*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
28*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
29*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
30*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
31*795d594fSAndroid Build Coastguard Worker #include "lock_word.h"
32*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-inl.h"
34*795d594fSAndroid Build Coastguard Worker #include "mirror/reference.h"
35*795d594fSAndroid Build Coastguard Worker #include "mirror/string.h"
36*795d594fSAndroid Build Coastguard Worker #include "mirror/var_handle.h"
37*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
38*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
39*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
40*795d594fSAndroid Build Coastguard Worker #include "utils/x86/assembler_x86.h"
41*795d594fSAndroid Build Coastguard Worker #include "utils/x86/constants_x86.h"
42*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker namespace x86 {
47*795d594fSAndroid Build Coastguard Worker 
IntrinsicLocationsBuilderX86(CodeGeneratorX86 * codegen)48*795d594fSAndroid Build Coastguard Worker IntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen)
49*795d594fSAndroid Build Coastguard Worker   : allocator_(codegen->GetGraph()->GetAllocator()),
50*795d594fSAndroid Build Coastguard Worker     codegen_(codegen) {
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker 
GetAssembler()54*795d594fSAndroid Build Coastguard Worker X86Assembler* IntrinsicCodeGeneratorX86::GetAssembler() {
55*795d594fSAndroid Build Coastguard Worker   return down_cast<X86Assembler*>(codegen_->GetAssembler());
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
GetAllocator()58*795d594fSAndroid Build Coastguard Worker ArenaAllocator* IntrinsicCodeGeneratorX86::GetAllocator() {
59*795d594fSAndroid Build Coastguard Worker   return codegen_->GetGraph()->GetAllocator();
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker 
TryDispatch(HInvoke * invoke)62*795d594fSAndroid Build Coastguard Worker bool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) {
63*795d594fSAndroid Build Coastguard Worker   Dispatch(invoke);
64*795d594fSAndroid Build Coastguard Worker   LocationSummary* res = invoke->GetLocations();
65*795d594fSAndroid Build Coastguard Worker   if (res == nullptr) {
66*795d594fSAndroid Build Coastguard Worker     return false;
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker   return res->Intrinsified();
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker using IntrinsicSlowPathX86 = IntrinsicSlowPath<InvokeDexCallingConventionVisitorX86>;
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker #define __ assembler->
74*795d594fSAndroid Build Coastguard Worker 
GenArrayAddress(X86Assembler * assembler,Register dest,Register base,Location pos,DataType::Type type,uint32_t data_offset)75*795d594fSAndroid Build Coastguard Worker static void GenArrayAddress(X86Assembler* assembler,
76*795d594fSAndroid Build Coastguard Worker                             Register dest,
77*795d594fSAndroid Build Coastguard Worker                             Register base,
78*795d594fSAndroid Build Coastguard Worker                             Location pos,
79*795d594fSAndroid Build Coastguard Worker                             DataType::Type type,
80*795d594fSAndroid Build Coastguard Worker                             uint32_t data_offset) {
81*795d594fSAndroid Build Coastguard Worker   if (pos.IsConstant()) {
82*795d594fSAndroid Build Coastguard Worker     int32_t constant = pos.GetConstant()->AsIntConstant()->GetValue();
83*795d594fSAndroid Build Coastguard Worker     __ leal(dest, Address(base, DataType::Size(type) * constant + data_offset));
84*795d594fSAndroid Build Coastguard Worker   } else {
85*795d594fSAndroid Build Coastguard Worker     const ScaleFactor scale_factor = static_cast<ScaleFactor>(DataType::SizeShift(type));
86*795d594fSAndroid Build Coastguard Worker     __ leal(dest, Address(base, pos.AsRegister<Register>(), scale_factor, data_offset));
87*795d594fSAndroid Build Coastguard Worker   }
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker // Slow path implementing the SystemArrayCopy intrinsic copy loop with read barriers.
91*795d594fSAndroid Build Coastguard Worker class ReadBarrierSystemArrayCopySlowPathX86 : public SlowPathCode {
92*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierSystemArrayCopySlowPathX86(HInstruction * instruction)93*795d594fSAndroid Build Coastguard Worker   explicit ReadBarrierSystemArrayCopySlowPathX86(HInstruction* instruction)
94*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction) {
95*795d594fSAndroid Build Coastguard Worker   }
96*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)97*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
98*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen->EmitBakerReadBarrier());
99*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
100*795d594fSAndroid Build Coastguard Worker     X86Assembler* assembler = x86_codegen->GetAssembler();
101*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
102*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
103*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsInvokeStaticOrDirect())
104*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier arraycopy slow path: "
105*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
106*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->GetLocations()->Intrinsified());
107*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
108*795d594fSAndroid Build Coastguard Worker     Location length = locations->InAt(4);
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker     const DataType::Type type = DataType::Type::kReference;
111*795d594fSAndroid Build Coastguard Worker     const int32_t element_size = DataType::Size(type);
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker     Register src_curr_addr = locations->GetTemp(0).AsRegister<Register>();
114*795d594fSAndroid Build Coastguard Worker     Register dst_curr_addr = locations->GetTemp(1).AsRegister<Register>();
115*795d594fSAndroid Build Coastguard Worker     Register src_stop_addr = locations->GetTemp(2).AsRegister<Register>();
116*795d594fSAndroid Build Coastguard Worker     Register value = locations->GetTemp(3).AsRegister<Register>();
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
119*795d594fSAndroid Build Coastguard Worker     // The `src_curr_addr` and `dst_curr_addr` were initialized before entering the slow-path.
120*795d594fSAndroid Build Coastguard Worker     GenArrayAddress(assembler, src_stop_addr, src_curr_addr, length, type, /*data_offset=*/ 0u);
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker     NearLabel loop;
123*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop);
124*795d594fSAndroid Build Coastguard Worker     __ movl(value, Address(src_curr_addr, 0));
125*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(value);
126*795d594fSAndroid Build Coastguard Worker     // TODO: Inline the mark bit check before calling the runtime?
127*795d594fSAndroid Build Coastguard Worker     // value = ReadBarrier::Mark(value)
128*795d594fSAndroid Build Coastguard Worker     // No need to save live registers; it's taken care of by the
129*795d594fSAndroid Build Coastguard Worker     // entrypoint. Also, there is no need to update the stack mask,
130*795d594fSAndroid Build Coastguard Worker     // as this runtime call will not trigger a garbage collection.
131*795d594fSAndroid Build Coastguard Worker     // (See ReadBarrierMarkSlowPathX86::EmitNativeCode for more
132*795d594fSAndroid Build Coastguard Worker     // explanations.)
133*795d594fSAndroid Build Coastguard Worker     int32_t entry_point_offset = Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(value);
134*795d594fSAndroid Build Coastguard Worker     // This runtime call does not require a stack map.
135*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
136*795d594fSAndroid Build Coastguard Worker     __ MaybePoisonHeapReference(value);
137*795d594fSAndroid Build Coastguard Worker     __ movl(Address(dst_curr_addr, 0), value);
138*795d594fSAndroid Build Coastguard Worker     __ addl(src_curr_addr, Immediate(element_size));
139*795d594fSAndroid Build Coastguard Worker     __ addl(dst_curr_addr, Immediate(element_size));
140*795d594fSAndroid Build Coastguard Worker     __ cmpl(src_curr_addr, src_stop_addr);
141*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, &loop);
142*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
143*795d594fSAndroid Build Coastguard Worker   }
144*795d594fSAndroid Build Coastguard Worker 
GetDescription() const145*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierSystemArrayCopySlowPathX86"; }
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker  private:
148*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierSystemArrayCopySlowPathX86);
149*795d594fSAndroid Build Coastguard Worker };
150*795d594fSAndroid Build Coastguard Worker 
CreateFPToIntLocations(ArenaAllocator * allocator,HInvoke * invoke,bool is64bit)151*795d594fSAndroid Build Coastguard Worker static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke, bool is64bit) {
152*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
153*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
154*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
155*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
156*795d594fSAndroid Build Coastguard Worker   if (is64bit) {
157*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker 
CreateIntToFPLocations(ArenaAllocator * allocator,HInvoke * invoke,bool is64bit)161*795d594fSAndroid Build Coastguard Worker static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke, bool is64bit) {
162*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
163*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
164*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
165*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister());
166*795d594fSAndroid Build Coastguard Worker   if (is64bit) {
167*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
168*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
169*795d594fSAndroid Build Coastguard Worker   }
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker 
MoveFPToInt(LocationSummary * locations,bool is64bit,X86Assembler * assembler)172*795d594fSAndroid Build Coastguard Worker static void MoveFPToInt(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
173*795d594fSAndroid Build Coastguard Worker   Location input = locations->InAt(0);
174*795d594fSAndroid Build Coastguard Worker   Location output = locations->Out();
175*795d594fSAndroid Build Coastguard Worker   if (is64bit) {
176*795d594fSAndroid Build Coastguard Worker     // Need to use the temporary.
177*795d594fSAndroid Build Coastguard Worker     XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
178*795d594fSAndroid Build Coastguard Worker     __ movsd(temp, input.AsFpuRegister<XmmRegister>());
179*795d594fSAndroid Build Coastguard Worker     __ movd(output.AsRegisterPairLow<Register>(), temp);
180*795d594fSAndroid Build Coastguard Worker     __ psrlq(temp, Immediate(32));
181*795d594fSAndroid Build Coastguard Worker     __ movd(output.AsRegisterPairHigh<Register>(), temp);
182*795d594fSAndroid Build Coastguard Worker   } else {
183*795d594fSAndroid Build Coastguard Worker     __ movd(output.AsRegister<Register>(), input.AsFpuRegister<XmmRegister>());
184*795d594fSAndroid Build Coastguard Worker   }
185*795d594fSAndroid Build Coastguard Worker }
186*795d594fSAndroid Build Coastguard Worker 
MoveIntToFP(LocationSummary * locations,bool is64bit,X86Assembler * assembler)187*795d594fSAndroid Build Coastguard Worker static void MoveIntToFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
188*795d594fSAndroid Build Coastguard Worker   Location input = locations->InAt(0);
189*795d594fSAndroid Build Coastguard Worker   Location output = locations->Out();
190*795d594fSAndroid Build Coastguard Worker   if (is64bit) {
191*795d594fSAndroid Build Coastguard Worker     // Need to use the temporary.
192*795d594fSAndroid Build Coastguard Worker     XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
193*795d594fSAndroid Build Coastguard Worker     XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
194*795d594fSAndroid Build Coastguard Worker     __ movd(temp1, input.AsRegisterPairLow<Register>());
195*795d594fSAndroid Build Coastguard Worker     __ movd(temp2, input.AsRegisterPairHigh<Register>());
196*795d594fSAndroid Build Coastguard Worker     __ punpckldq(temp1, temp2);
197*795d594fSAndroid Build Coastguard Worker     __ movsd(output.AsFpuRegister<XmmRegister>(), temp1);
198*795d594fSAndroid Build Coastguard Worker   } else {
199*795d594fSAndroid Build Coastguard Worker     __ movd(output.AsFpuRegister<XmmRegister>(), input.AsRegister<Register>());
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)203*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
204*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke, /* is64bit= */ true);
205*795d594fSAndroid Build Coastguard Worker }
VisitDoubleLongBitsToDouble(HInvoke * invoke)206*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
207*795d594fSAndroid Build Coastguard Worker   CreateIntToFPLocations(allocator_, invoke, /* is64bit= */ true);
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)210*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
211*795d594fSAndroid Build Coastguard Worker   MoveFPToInt(invoke->GetLocations(), /* is64bit= */ true, GetAssembler());
212*795d594fSAndroid Build Coastguard Worker }
VisitDoubleLongBitsToDouble(HInvoke * invoke)213*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
214*795d594fSAndroid Build Coastguard Worker   MoveIntToFP(invoke->GetLocations(), /* is64bit= */ true, GetAssembler());
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
VisitFloatFloatToRawIntBits(HInvoke * invoke)217*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
218*795d594fSAndroid Build Coastguard Worker   CreateFPToIntLocations(allocator_, invoke, /* is64bit= */ false);
219*795d594fSAndroid Build Coastguard Worker }
VisitFloatIntBitsToFloat(HInvoke * invoke)220*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
221*795d594fSAndroid Build Coastguard Worker   CreateIntToFPLocations(allocator_, invoke, /* is64bit= */ false);
222*795d594fSAndroid Build Coastguard Worker }
223*795d594fSAndroid Build Coastguard Worker 
VisitFloatFloatToRawIntBits(HInvoke * invoke)224*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
225*795d594fSAndroid Build Coastguard Worker   MoveFPToInt(invoke->GetLocations(), /* is64bit= */ false, GetAssembler());
226*795d594fSAndroid Build Coastguard Worker }
VisitFloatIntBitsToFloat(HInvoke * invoke)227*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
228*795d594fSAndroid Build Coastguard Worker   MoveIntToFP(invoke->GetLocations(), /* is64bit= */ false, GetAssembler());
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker 
CreateIntToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)231*795d594fSAndroid Build Coastguard Worker static void CreateIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
232*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
233*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
234*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
235*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
CreateLongToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)238*795d594fSAndroid Build Coastguard Worker static void CreateLongToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
239*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
240*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
241*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
242*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
243*795d594fSAndroid Build Coastguard Worker }
244*795d594fSAndroid Build Coastguard Worker 
CreateLongToLongLocations(ArenaAllocator * allocator,HInvoke * invoke)245*795d594fSAndroid Build Coastguard Worker static void CreateLongToLongLocations(ArenaAllocator* allocator, HInvoke* invoke) {
246*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
247*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
248*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
249*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker 
GenReverseBytes(LocationSummary * locations,DataType::Type size,X86Assembler * assembler)252*795d594fSAndroid Build Coastguard Worker static void GenReverseBytes(LocationSummary* locations,
253*795d594fSAndroid Build Coastguard Worker                             DataType::Type size,
254*795d594fSAndroid Build Coastguard Worker                             X86Assembler* assembler) {
255*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker   switch (size) {
258*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
259*795d594fSAndroid Build Coastguard Worker       // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
260*795d594fSAndroid Build Coastguard Worker       __ bswapl(out);
261*795d594fSAndroid Build Coastguard Worker       __ sarl(out, Immediate(16));
262*795d594fSAndroid Build Coastguard Worker       break;
263*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
264*795d594fSAndroid Build Coastguard Worker       __ bswapl(out);
265*795d594fSAndroid Build Coastguard Worker       break;
266*795d594fSAndroid Build Coastguard Worker     default:
267*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected size for reverse-bytes: " << size;
268*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
269*795d594fSAndroid Build Coastguard Worker   }
270*795d594fSAndroid Build Coastguard Worker }
271*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverseBytes(HInvoke * invoke)272*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerReverseBytes(HInvoke* invoke) {
273*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
274*795d594fSAndroid Build Coastguard Worker }
275*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverseBytes(HInvoke * invoke)276*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerReverseBytes(HInvoke* invoke) {
277*795d594fSAndroid Build Coastguard Worker   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker 
VisitLongReverseBytes(HInvoke * invoke)280*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongReverseBytes(HInvoke* invoke) {
281*795d594fSAndroid Build Coastguard Worker   CreateLongToLongLocations(allocator_, invoke);
282*795d594fSAndroid Build Coastguard Worker }
283*795d594fSAndroid Build Coastguard Worker 
VisitLongReverseBytes(HInvoke * invoke)284*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongReverseBytes(HInvoke* invoke) {
285*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
286*795d594fSAndroid Build Coastguard Worker   Location input = locations->InAt(0);
287*795d594fSAndroid Build Coastguard Worker   Register input_lo = input.AsRegisterPairLow<Register>();
288*795d594fSAndroid Build Coastguard Worker   Register input_hi = input.AsRegisterPairHigh<Register>();
289*795d594fSAndroid Build Coastguard Worker   Location output = locations->Out();
290*795d594fSAndroid Build Coastguard Worker   Register output_lo = output.AsRegisterPairLow<Register>();
291*795d594fSAndroid Build Coastguard Worker   Register output_hi = output.AsRegisterPairHigh<Register>();
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
294*795d594fSAndroid Build Coastguard Worker   // Assign the inputs to the outputs, mixing low/high.
295*795d594fSAndroid Build Coastguard Worker   __ movl(output_lo, input_hi);
296*795d594fSAndroid Build Coastguard Worker   __ movl(output_hi, input_lo);
297*795d594fSAndroid Build Coastguard Worker   __ bswapl(output_lo);
298*795d594fSAndroid Build Coastguard Worker   __ bswapl(output_hi);
299*795d594fSAndroid Build Coastguard Worker }
300*795d594fSAndroid Build Coastguard Worker 
VisitShortReverseBytes(HInvoke * invoke)301*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitShortReverseBytes(HInvoke* invoke) {
302*795d594fSAndroid Build Coastguard Worker   CreateIntToIntLocations(allocator_, invoke);
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker 
VisitShortReverseBytes(HInvoke * invoke)305*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) {
306*795d594fSAndroid Build Coastguard Worker   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
307*795d594fSAndroid Build Coastguard Worker }
308*795d594fSAndroid Build Coastguard Worker 
CreateFPToFPLocations(ArenaAllocator * allocator,HInvoke * invoke)309*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
310*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
311*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
312*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
313*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker 
VisitMathSqrt(HInvoke * invoke)316*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathSqrt(HInvoke* invoke) {
317*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator_, invoke);
318*795d594fSAndroid Build Coastguard Worker }
319*795d594fSAndroid Build Coastguard Worker 
VisitMathSqrt(HInvoke * invoke)320*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathSqrt(HInvoke* invoke) {
321*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
322*795d594fSAndroid Build Coastguard Worker   XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
323*795d594fSAndroid Build Coastguard Worker   XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
324*795d594fSAndroid Build Coastguard Worker 
325*795d594fSAndroid Build Coastguard Worker   GetAssembler()->sqrtsd(out, in);
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker 
CreateSSE41FPToFPLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorX86 * codegen)328*795d594fSAndroid Build Coastguard Worker static void CreateSSE41FPToFPLocations(ArenaAllocator* allocator,
329*795d594fSAndroid Build Coastguard Worker                                        HInvoke* invoke,
330*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorX86* codegen) {
331*795d594fSAndroid Build Coastguard Worker   // Do we have instruction support?
332*795d594fSAndroid Build Coastguard Worker   if (!codegen->GetInstructionSetFeatures().HasSSE4_1()) {
333*795d594fSAndroid Build Coastguard Worker     return;
334*795d594fSAndroid Build Coastguard Worker   }
335*795d594fSAndroid Build Coastguard Worker 
336*795d594fSAndroid Build Coastguard Worker   CreateFPToFPLocations(allocator, invoke);
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker 
GenSSE41FPToFPIntrinsic(HInvoke * invoke,X86Assembler * assembler,int round_mode)339*795d594fSAndroid Build Coastguard Worker static void GenSSE41FPToFPIntrinsic(HInvoke* invoke, X86Assembler* assembler, int round_mode) {
340*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
341*795d594fSAndroid Build Coastguard Worker   DCHECK(!locations->WillCall());
342*795d594fSAndroid Build Coastguard Worker   XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
343*795d594fSAndroid Build Coastguard Worker   XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
344*795d594fSAndroid Build Coastguard Worker   __ roundsd(out, in, Immediate(round_mode));
345*795d594fSAndroid Build Coastguard Worker }
346*795d594fSAndroid Build Coastguard Worker 
VisitMathCeil(HInvoke * invoke)347*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathCeil(HInvoke* invoke) {
348*795d594fSAndroid Build Coastguard Worker   CreateSSE41FPToFPLocations(allocator_, invoke, codegen_);
349*795d594fSAndroid Build Coastguard Worker }
350*795d594fSAndroid Build Coastguard Worker 
VisitMathCeil(HInvoke * invoke)351*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathCeil(HInvoke* invoke) {
352*795d594fSAndroid Build Coastguard Worker   GenSSE41FPToFPIntrinsic(invoke, GetAssembler(), 2);
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker 
VisitMathFloor(HInvoke * invoke)355*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathFloor(HInvoke* invoke) {
356*795d594fSAndroid Build Coastguard Worker   CreateSSE41FPToFPLocations(allocator_, invoke, codegen_);
357*795d594fSAndroid Build Coastguard Worker }
358*795d594fSAndroid Build Coastguard Worker 
VisitMathFloor(HInvoke * invoke)359*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathFloor(HInvoke* invoke) {
360*795d594fSAndroid Build Coastguard Worker   GenSSE41FPToFPIntrinsic(invoke, GetAssembler(), 1);
361*795d594fSAndroid Build Coastguard Worker }
362*795d594fSAndroid Build Coastguard Worker 
VisitMathRint(HInvoke * invoke)363*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathRint(HInvoke* invoke) {
364*795d594fSAndroid Build Coastguard Worker   CreateSSE41FPToFPLocations(allocator_, invoke, codegen_);
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker 
VisitMathRint(HInvoke * invoke)367*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathRint(HInvoke* invoke) {
368*795d594fSAndroid Build Coastguard Worker   GenSSE41FPToFPIntrinsic(invoke, GetAssembler(), 0);
369*795d594fSAndroid Build Coastguard Worker }
370*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundFloat(HInvoke * invoke)371*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathRoundFloat(HInvoke* invoke) {
372*795d594fSAndroid Build Coastguard Worker   // Do we have instruction support?
373*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GetInstructionSetFeatures().HasSSE4_1()) {
374*795d594fSAndroid Build Coastguard Worker     return;
375*795d594fSAndroid Build Coastguard Worker   }
376*795d594fSAndroid Build Coastguard Worker 
377*795d594fSAndroid Build Coastguard Worker   HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
378*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
379*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
380*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
381*795d594fSAndroid Build Coastguard Worker   if (static_or_direct->HasSpecialInput() &&
382*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(
383*795d594fSAndroid Build Coastguard Worker           static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
384*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
385*795d594fSAndroid Build Coastguard Worker   }
386*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
387*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresFpuRegister());
388*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresFpuRegister());
389*795d594fSAndroid Build Coastguard Worker }
390*795d594fSAndroid Build Coastguard Worker 
VisitMathRoundFloat(HInvoke * invoke)391*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathRoundFloat(HInvoke* invoke) {
392*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
393*795d594fSAndroid Build Coastguard Worker   DCHECK(!locations->WillCall());
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker   XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
396*795d594fSAndroid Build Coastguard Worker   XmmRegister t1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
397*795d594fSAndroid Build Coastguard Worker   XmmRegister t2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
398*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
399*795d594fSAndroid Build Coastguard Worker   NearLabel skip_incr, done;
400*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
401*795d594fSAndroid Build Coastguard Worker 
402*795d594fSAndroid Build Coastguard Worker   // Since no direct x86 rounding instruction matches the required semantics,
403*795d594fSAndroid Build Coastguard Worker   // this intrinsic is implemented as follows:
404*795d594fSAndroid Build Coastguard Worker   //  result = floor(in);
405*795d594fSAndroid Build Coastguard Worker   //  if (in - result >= 0.5f)
406*795d594fSAndroid Build Coastguard Worker   //    result = result + 1.0f;
407*795d594fSAndroid Build Coastguard Worker   __ movss(t2, in);
408*795d594fSAndroid Build Coastguard Worker   __ roundss(t1, in, Immediate(1));
409*795d594fSAndroid Build Coastguard Worker   __ subss(t2, t1);
410*795d594fSAndroid Build Coastguard Worker   if (locations->GetInputCount() == 2 && locations->InAt(1).IsValid()) {
411*795d594fSAndroid Build Coastguard Worker     // Direct constant area available.
412*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* method_address =
413*795d594fSAndroid Build Coastguard Worker         invoke->InputAt(1)->AsX86ComputeBaseMethodAddress();
414*795d594fSAndroid Build Coastguard Worker     Register constant_area = locations->InAt(1).AsRegister<Register>();
415*795d594fSAndroid Build Coastguard Worker     __ comiss(t2, codegen_->LiteralInt32Address(bit_cast<int32_t, float>(0.5f),
416*795d594fSAndroid Build Coastguard Worker                                                 method_address,
417*795d594fSAndroid Build Coastguard Worker                                                 constant_area));
418*795d594fSAndroid Build Coastguard Worker     __ j(kBelow, &skip_incr);
419*795d594fSAndroid Build Coastguard Worker     __ addss(t1, codegen_->LiteralInt32Address(bit_cast<int32_t, float>(1.0f),
420*795d594fSAndroid Build Coastguard Worker                                                method_address,
421*795d594fSAndroid Build Coastguard Worker                                                constant_area));
422*795d594fSAndroid Build Coastguard Worker     __ Bind(&skip_incr);
423*795d594fSAndroid Build Coastguard Worker   } else {
424*795d594fSAndroid Build Coastguard Worker     // No constant area: go through stack.
425*795d594fSAndroid Build Coastguard Worker     __ pushl(Immediate(bit_cast<int32_t, float>(0.5f)));
426*795d594fSAndroid Build Coastguard Worker     __ pushl(Immediate(bit_cast<int32_t, float>(1.0f)));
427*795d594fSAndroid Build Coastguard Worker     __ comiss(t2, Address(ESP, 4));
428*795d594fSAndroid Build Coastguard Worker     __ j(kBelow, &skip_incr);
429*795d594fSAndroid Build Coastguard Worker     __ addss(t1, Address(ESP, 0));
430*795d594fSAndroid Build Coastguard Worker     __ Bind(&skip_incr);
431*795d594fSAndroid Build Coastguard Worker     __ addl(ESP, Immediate(8));
432*795d594fSAndroid Build Coastguard Worker   }
433*795d594fSAndroid Build Coastguard Worker 
434*795d594fSAndroid Build Coastguard Worker   // Final conversion to an integer. Unfortunately this also does not have a
435*795d594fSAndroid Build Coastguard Worker   // direct x86 instruction, since NaN should map to 0 and large positive
436*795d594fSAndroid Build Coastguard Worker   // values need to be clipped to the extreme value.
437*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(kPrimIntMax));
438*795d594fSAndroid Build Coastguard Worker   __ cvtsi2ss(t2, out);
439*795d594fSAndroid Build Coastguard Worker   __ comiss(t1, t2);
440*795d594fSAndroid Build Coastguard Worker   __ j(kAboveEqual, &done);  // clipped to max (already in out), does not jump on unordered
441*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(0));  // does not change flags
442*795d594fSAndroid Build Coastguard Worker   __ j(kUnordered, &done);  // NaN mapped to 0 (just moved in out)
443*795d594fSAndroid Build Coastguard Worker   __ cvttss2si(out, t1);
444*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
445*795d594fSAndroid Build Coastguard Worker }
446*795d594fSAndroid Build Coastguard Worker 
CreateFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)447*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
448*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
449*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
450*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
451*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
452*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::FpuRegisterLocation(XMM0));
453*795d594fSAndroid Build Coastguard Worker }
454*795d594fSAndroid Build Coastguard Worker 
GenFPToFPCall(HInvoke * invoke,CodeGeneratorX86 * codegen,QuickEntrypointEnum entry)455*795d594fSAndroid Build Coastguard Worker static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86* codegen, QuickEntrypointEnum entry) {
456*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
457*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->WillCall());
458*795d594fSAndroid Build Coastguard Worker   DCHECK(invoke->IsInvokeStaticOrDirect());
459*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
460*795d594fSAndroid Build Coastguard Worker 
461*795d594fSAndroid Build Coastguard Worker   // We need some place to pass the parameters.
462*795d594fSAndroid Build Coastguard Worker   __ subl(ESP, Immediate(16));
463*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(16);
464*795d594fSAndroid Build Coastguard Worker 
465*795d594fSAndroid Build Coastguard Worker   // Pass the parameters at the bottom of the stack.
466*795d594fSAndroid Build Coastguard Worker   __ movsd(Address(ESP, 0), XMM0);
467*795d594fSAndroid Build Coastguard Worker 
468*795d594fSAndroid Build Coastguard Worker   // If we have a second parameter, pass it next.
469*795d594fSAndroid Build Coastguard Worker   if (invoke->GetNumberOfArguments() == 2) {
470*795d594fSAndroid Build Coastguard Worker     __ movsd(Address(ESP, 8), XMM1);
471*795d594fSAndroid Build Coastguard Worker   }
472*795d594fSAndroid Build Coastguard Worker 
473*795d594fSAndroid Build Coastguard Worker   // Now do the actual call.
474*795d594fSAndroid Build Coastguard Worker   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker   // Extract the return value from the FP stack.
477*795d594fSAndroid Build Coastguard Worker   __ fstpl(Address(ESP, 0));
478*795d594fSAndroid Build Coastguard Worker   __ movsd(XMM0, Address(ESP, 0));
479*795d594fSAndroid Build Coastguard Worker 
480*795d594fSAndroid Build Coastguard Worker   // And clean up the stack.
481*795d594fSAndroid Build Coastguard Worker   __ addl(ESP, Immediate(16));
482*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(-16);
483*795d594fSAndroid Build Coastguard Worker }
484*795d594fSAndroid Build Coastguard Worker 
CreateLowestOneBitLocations(ArenaAllocator * allocator,bool is_long,HInvoke * invoke)485*795d594fSAndroid Build Coastguard Worker static void CreateLowestOneBitLocations(ArenaAllocator* allocator, bool is_long, HInvoke* invoke) {
486*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
487*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
488*795d594fSAndroid Build Coastguard Worker   if (is_long) {
489*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
490*795d594fSAndroid Build Coastguard Worker   } else {
491*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::Any());
492*795d594fSAndroid Build Coastguard Worker   }
493*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
494*795d594fSAndroid Build Coastguard Worker }
495*795d594fSAndroid Build Coastguard Worker 
GenLowestOneBit(X86Assembler * assembler,CodeGeneratorX86 * codegen,bool is_long,HInvoke * invoke)496*795d594fSAndroid Build Coastguard Worker static void GenLowestOneBit(X86Assembler* assembler,
497*795d594fSAndroid Build Coastguard Worker                       CodeGeneratorX86* codegen,
498*795d594fSAndroid Build Coastguard Worker                       bool is_long,
499*795d594fSAndroid Build Coastguard Worker                       HInvoke* invoke) {
500*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
501*795d594fSAndroid Build Coastguard Worker   Location src = locations->InAt(0);
502*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
503*795d594fSAndroid Build Coastguard Worker 
504*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsConstant()) {
505*795d594fSAndroid Build Coastguard Worker     // Evaluate this at compile time.
506*795d594fSAndroid Build Coastguard Worker     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
507*795d594fSAndroid Build Coastguard Worker     if (value == 0) {
508*795d594fSAndroid Build Coastguard Worker       if (is_long) {
509*795d594fSAndroid Build Coastguard Worker         __ xorl(out_loc.AsRegisterPairLow<Register>(), out_loc.AsRegisterPairLow<Register>());
510*795d594fSAndroid Build Coastguard Worker         __ xorl(out_loc.AsRegisterPairHigh<Register>(), out_loc.AsRegisterPairHigh<Register>());
511*795d594fSAndroid Build Coastguard Worker       } else {
512*795d594fSAndroid Build Coastguard Worker         __ xorl(out_loc.AsRegister<Register>(), out_loc.AsRegister<Register>());
513*795d594fSAndroid Build Coastguard Worker       }
514*795d594fSAndroid Build Coastguard Worker       return;
515*795d594fSAndroid Build Coastguard Worker     }
516*795d594fSAndroid Build Coastguard Worker     // Nonzero value.
517*795d594fSAndroid Build Coastguard Worker     value = is_long ? CTZ(static_cast<uint64_t>(value))
518*795d594fSAndroid Build Coastguard Worker                     : CTZ(static_cast<uint32_t>(value));
519*795d594fSAndroid Build Coastguard Worker     if (is_long) {
520*795d594fSAndroid Build Coastguard Worker       if (value >= 32) {
521*795d594fSAndroid Build Coastguard Worker         int shift = value-32;
522*795d594fSAndroid Build Coastguard Worker         codegen->Load32BitValue(out_loc.AsRegisterPairLow<Register>(), 0);
523*795d594fSAndroid Build Coastguard Worker         codegen->Load32BitValue(out_loc.AsRegisterPairHigh<Register>(), 1 << shift);
524*795d594fSAndroid Build Coastguard Worker       } else {
525*795d594fSAndroid Build Coastguard Worker         codegen->Load32BitValue(out_loc.AsRegisterPairLow<Register>(), 1 << value);
526*795d594fSAndroid Build Coastguard Worker         codegen->Load32BitValue(out_loc.AsRegisterPairHigh<Register>(), 0);
527*795d594fSAndroid Build Coastguard Worker       }
528*795d594fSAndroid Build Coastguard Worker     } else {
529*795d594fSAndroid Build Coastguard Worker       codegen->Load32BitValue(out_loc.AsRegister<Register>(), 1 << value);
530*795d594fSAndroid Build Coastguard Worker     }
531*795d594fSAndroid Build Coastguard Worker     return;
532*795d594fSAndroid Build Coastguard Worker   }
533*795d594fSAndroid Build Coastguard Worker   // Handle non constant case
534*795d594fSAndroid Build Coastguard Worker   if (is_long) {
535*795d594fSAndroid Build Coastguard Worker     DCHECK(src.IsRegisterPair());
536*795d594fSAndroid Build Coastguard Worker     Register src_lo = src.AsRegisterPairLow<Register>();
537*795d594fSAndroid Build Coastguard Worker     Register src_hi = src.AsRegisterPairHigh<Register>();
538*795d594fSAndroid Build Coastguard Worker 
539*795d594fSAndroid Build Coastguard Worker     Register out_lo = out_loc.AsRegisterPairLow<Register>();
540*795d594fSAndroid Build Coastguard Worker     Register out_hi = out_loc.AsRegisterPairHigh<Register>();
541*795d594fSAndroid Build Coastguard Worker 
542*795d594fSAndroid Build Coastguard Worker     __ movl(out_lo, src_lo);
543*795d594fSAndroid Build Coastguard Worker     __ movl(out_hi, src_hi);
544*795d594fSAndroid Build Coastguard Worker 
545*795d594fSAndroid Build Coastguard Worker     __ negl(out_lo);
546*795d594fSAndroid Build Coastguard Worker     __ adcl(out_hi, Immediate(0));
547*795d594fSAndroid Build Coastguard Worker     __ negl(out_hi);
548*795d594fSAndroid Build Coastguard Worker 
549*795d594fSAndroid Build Coastguard Worker     __ andl(out_lo, src_lo);
550*795d594fSAndroid Build Coastguard Worker     __ andl(out_hi, src_hi);
551*795d594fSAndroid Build Coastguard Worker   } else {
552*795d594fSAndroid Build Coastguard Worker     if (codegen->GetInstructionSetFeatures().HasAVX2() && src.IsRegister()) {
553*795d594fSAndroid Build Coastguard Worker       Register out = out_loc.AsRegister<Register>();
554*795d594fSAndroid Build Coastguard Worker       __ blsi(out, src.AsRegister<Register>());
555*795d594fSAndroid Build Coastguard Worker     } else {
556*795d594fSAndroid Build Coastguard Worker       Register out = out_loc.AsRegister<Register>();
557*795d594fSAndroid Build Coastguard Worker       // Do tmp & -tmp
558*795d594fSAndroid Build Coastguard Worker       if (src.IsRegister()) {
559*795d594fSAndroid Build Coastguard Worker         __ movl(out, src.AsRegister<Register>());
560*795d594fSAndroid Build Coastguard Worker       } else {
561*795d594fSAndroid Build Coastguard Worker         DCHECK(src.IsStackSlot());
562*795d594fSAndroid Build Coastguard Worker         __ movl(out, Address(ESP, src.GetStackIndex()));
563*795d594fSAndroid Build Coastguard Worker       }
564*795d594fSAndroid Build Coastguard Worker       __ negl(out);
565*795d594fSAndroid Build Coastguard Worker 
566*795d594fSAndroid Build Coastguard Worker       if (src.IsRegister()) {
567*795d594fSAndroid Build Coastguard Worker         __ andl(out, src.AsRegister<Register>());
568*795d594fSAndroid Build Coastguard Worker       } else {
569*795d594fSAndroid Build Coastguard Worker         __ andl(out, Address(ESP, src.GetStackIndex()));
570*795d594fSAndroid Build Coastguard Worker       }
571*795d594fSAndroid Build Coastguard Worker     }
572*795d594fSAndroid Build Coastguard Worker   }
573*795d594fSAndroid Build Coastguard Worker }
574*795d594fSAndroid Build Coastguard Worker 
VisitMathCos(HInvoke * invoke)575*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathCos(HInvoke* invoke) {
576*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker 
VisitMathCos(HInvoke * invoke)579*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathCos(HInvoke* invoke) {
580*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCos);
581*795d594fSAndroid Build Coastguard Worker }
582*795d594fSAndroid Build Coastguard Worker 
VisitMathSin(HInvoke * invoke)583*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathSin(HInvoke* invoke) {
584*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
585*795d594fSAndroid Build Coastguard Worker }
586*795d594fSAndroid Build Coastguard Worker 
VisitMathSin(HInvoke * invoke)587*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathSin(HInvoke* invoke) {
588*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickSin);
589*795d594fSAndroid Build Coastguard Worker }
590*795d594fSAndroid Build Coastguard Worker 
VisitMathAcos(HInvoke * invoke)591*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathAcos(HInvoke* invoke) {
592*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
593*795d594fSAndroid Build Coastguard Worker }
594*795d594fSAndroid Build Coastguard Worker 
VisitMathAcos(HInvoke * invoke)595*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathAcos(HInvoke* invoke) {
596*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAcos);
597*795d594fSAndroid Build Coastguard Worker }
598*795d594fSAndroid Build Coastguard Worker 
VisitMathAsin(HInvoke * invoke)599*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathAsin(HInvoke* invoke) {
600*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
601*795d594fSAndroid Build Coastguard Worker }
602*795d594fSAndroid Build Coastguard Worker 
VisitMathAsin(HInvoke * invoke)603*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathAsin(HInvoke* invoke) {
604*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAsin);
605*795d594fSAndroid Build Coastguard Worker }
606*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan(HInvoke * invoke)607*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathAtan(HInvoke* invoke) {
608*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
609*795d594fSAndroid Build Coastguard Worker }
610*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan(HInvoke * invoke)611*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathAtan(HInvoke* invoke) {
612*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAtan);
613*795d594fSAndroid Build Coastguard Worker }
614*795d594fSAndroid Build Coastguard Worker 
VisitMathCbrt(HInvoke * invoke)615*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathCbrt(HInvoke* invoke) {
616*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
617*795d594fSAndroid Build Coastguard Worker }
618*795d594fSAndroid Build Coastguard Worker 
VisitMathCbrt(HInvoke * invoke)619*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathCbrt(HInvoke* invoke) {
620*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCbrt);
621*795d594fSAndroid Build Coastguard Worker }
622*795d594fSAndroid Build Coastguard Worker 
VisitMathCosh(HInvoke * invoke)623*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathCosh(HInvoke* invoke) {
624*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker 
VisitMathCosh(HInvoke * invoke)627*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathCosh(HInvoke* invoke) {
628*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickCosh);
629*795d594fSAndroid Build Coastguard Worker }
630*795d594fSAndroid Build Coastguard Worker 
VisitMathExp(HInvoke * invoke)631*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathExp(HInvoke* invoke) {
632*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
633*795d594fSAndroid Build Coastguard Worker }
634*795d594fSAndroid Build Coastguard Worker 
VisitMathExp(HInvoke * invoke)635*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathExp(HInvoke* invoke) {
636*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickExp);
637*795d594fSAndroid Build Coastguard Worker }
638*795d594fSAndroid Build Coastguard Worker 
VisitMathExpm1(HInvoke * invoke)639*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathExpm1(HInvoke* invoke) {
640*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
641*795d594fSAndroid Build Coastguard Worker }
642*795d594fSAndroid Build Coastguard Worker 
VisitMathExpm1(HInvoke * invoke)643*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathExpm1(HInvoke* invoke) {
644*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickExpm1);
645*795d594fSAndroid Build Coastguard Worker }
646*795d594fSAndroid Build Coastguard Worker 
VisitMathLog(HInvoke * invoke)647*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathLog(HInvoke* invoke) {
648*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
649*795d594fSAndroid Build Coastguard Worker }
650*795d594fSAndroid Build Coastguard Worker 
VisitMathLog(HInvoke * invoke)651*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathLog(HInvoke* invoke) {
652*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickLog);
653*795d594fSAndroid Build Coastguard Worker }
654*795d594fSAndroid Build Coastguard Worker 
VisitMathLog10(HInvoke * invoke)655*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathLog10(HInvoke* invoke) {
656*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
657*795d594fSAndroid Build Coastguard Worker }
658*795d594fSAndroid Build Coastguard Worker 
VisitMathLog10(HInvoke * invoke)659*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathLog10(HInvoke* invoke) {
660*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickLog10);
661*795d594fSAndroid Build Coastguard Worker }
662*795d594fSAndroid Build Coastguard Worker 
VisitMathSinh(HInvoke * invoke)663*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathSinh(HInvoke* invoke) {
664*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
665*795d594fSAndroid Build Coastguard Worker }
666*795d594fSAndroid Build Coastguard Worker 
VisitMathSinh(HInvoke * invoke)667*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathSinh(HInvoke* invoke) {
668*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickSinh);
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker 
VisitMathTan(HInvoke * invoke)671*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathTan(HInvoke* invoke) {
672*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
673*795d594fSAndroid Build Coastguard Worker }
674*795d594fSAndroid Build Coastguard Worker 
VisitMathTan(HInvoke * invoke)675*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathTan(HInvoke* invoke) {
676*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickTan);
677*795d594fSAndroid Build Coastguard Worker }
678*795d594fSAndroid Build Coastguard Worker 
VisitMathTanh(HInvoke * invoke)679*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathTanh(HInvoke* invoke) {
680*795d594fSAndroid Build Coastguard Worker   CreateFPToFPCallLocations(allocator_, invoke);
681*795d594fSAndroid Build Coastguard Worker }
682*795d594fSAndroid Build Coastguard Worker 
VisitMathTanh(HInvoke * invoke)683*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathTanh(HInvoke* invoke) {
684*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickTanh);
685*795d594fSAndroid Build Coastguard Worker }
686*795d594fSAndroid Build Coastguard Worker 
VisitIntegerLowestOneBit(HInvoke * invoke)687*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerLowestOneBit(HInvoke* invoke) {
688*795d594fSAndroid Build Coastguard Worker   CreateLowestOneBitLocations(allocator_, /*is_long=*/ false, invoke);
689*795d594fSAndroid Build Coastguard Worker }
VisitIntegerLowestOneBit(HInvoke * invoke)690*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerLowestOneBit(HInvoke* invoke) {
691*795d594fSAndroid Build Coastguard Worker   GenLowestOneBit(GetAssembler(), codegen_, /*is_long=*/ false, invoke);
692*795d594fSAndroid Build Coastguard Worker }
693*795d594fSAndroid Build Coastguard Worker 
VisitLongLowestOneBit(HInvoke * invoke)694*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongLowestOneBit(HInvoke* invoke) {
695*795d594fSAndroid Build Coastguard Worker   CreateLowestOneBitLocations(allocator_, /*is_long=*/ true, invoke);
696*795d594fSAndroid Build Coastguard Worker }
697*795d594fSAndroid Build Coastguard Worker 
VisitLongLowestOneBit(HInvoke * invoke)698*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongLowestOneBit(HInvoke* invoke) {
699*795d594fSAndroid Build Coastguard Worker   GenLowestOneBit(GetAssembler(), codegen_, /*is_long=*/ true, invoke);
700*795d594fSAndroid Build Coastguard Worker }
701*795d594fSAndroid Build Coastguard Worker 
CreateFPFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)702*795d594fSAndroid Build Coastguard Worker static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
703*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
704*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
705*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
706*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
707*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
708*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::FpuRegisterLocation(XMM0));
709*795d594fSAndroid Build Coastguard Worker }
710*795d594fSAndroid Build Coastguard Worker 
CreateFPFPFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)711*795d594fSAndroid Build Coastguard Worker static void CreateFPFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
712*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(invoke->GetNumberOfArguments(), 3U);
713*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
714*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
715*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
716*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
717*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresFpuRegister());
718*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresFpuRegister());
719*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
720*795d594fSAndroid Build Coastguard Worker }
721*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan2(HInvoke * invoke)722*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathAtan2(HInvoke* invoke) {
723*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
724*795d594fSAndroid Build Coastguard Worker }
725*795d594fSAndroid Build Coastguard Worker 
VisitMathAtan2(HInvoke * invoke)726*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathAtan2(HInvoke* invoke) {
727*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickAtan2);
728*795d594fSAndroid Build Coastguard Worker }
729*795d594fSAndroid Build Coastguard Worker 
VisitMathPow(HInvoke * invoke)730*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathPow(HInvoke* invoke) {
731*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
732*795d594fSAndroid Build Coastguard Worker }
733*795d594fSAndroid Build Coastguard Worker 
VisitMathPow(HInvoke * invoke)734*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathPow(HInvoke* invoke) {
735*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickPow);
736*795d594fSAndroid Build Coastguard Worker }
737*795d594fSAndroid Build Coastguard Worker 
VisitMathHypot(HInvoke * invoke)738*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathHypot(HInvoke* invoke) {
739*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
740*795d594fSAndroid Build Coastguard Worker }
741*795d594fSAndroid Build Coastguard Worker 
VisitMathHypot(HInvoke * invoke)742*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathHypot(HInvoke* invoke) {
743*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickHypot);
744*795d594fSAndroid Build Coastguard Worker }
745*795d594fSAndroid Build Coastguard Worker 
VisitMathNextAfter(HInvoke * invoke)746*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathNextAfter(HInvoke* invoke) {
747*795d594fSAndroid Build Coastguard Worker   CreateFPFPToFPCallLocations(allocator_, invoke);
748*795d594fSAndroid Build Coastguard Worker }
749*795d594fSAndroid Build Coastguard Worker 
VisitMathNextAfter(HInvoke * invoke)750*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathNextAfter(HInvoke* invoke) {
751*795d594fSAndroid Build Coastguard Worker   GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker 
CreateSystemArrayCopyLocations(HInvoke * invoke)754*795d594fSAndroid Build Coastguard Worker static void CreateSystemArrayCopyLocations(HInvoke* invoke) {
755*795d594fSAndroid Build Coastguard Worker   // We need at least two of the positions or length to be an integer constant,
756*795d594fSAndroid Build Coastguard Worker   // or else we won't have enough free registers.
757*795d594fSAndroid Build Coastguard Worker   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstantOrNull();
758*795d594fSAndroid Build Coastguard Worker   HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstantOrNull();
759*795d594fSAndroid Build Coastguard Worker   HIntConstant* length = invoke->InputAt(4)->AsIntConstantOrNull();
760*795d594fSAndroid Build Coastguard Worker 
761*795d594fSAndroid Build Coastguard Worker   int num_constants =
762*795d594fSAndroid Build Coastguard Worker       ((src_pos != nullptr) ? 1 : 0)
763*795d594fSAndroid Build Coastguard Worker       + ((dest_pos != nullptr) ? 1 : 0)
764*795d594fSAndroid Build Coastguard Worker       + ((length != nullptr) ? 1 : 0);
765*795d594fSAndroid Build Coastguard Worker 
766*795d594fSAndroid Build Coastguard Worker   if (num_constants < 2) {
767*795d594fSAndroid Build Coastguard Worker     // Not enough free registers.
768*795d594fSAndroid Build Coastguard Worker     return;
769*795d594fSAndroid Build Coastguard Worker   }
770*795d594fSAndroid Build Coastguard Worker 
771*795d594fSAndroid Build Coastguard Worker   // As long as we are checking, we might as well check to see if the src and dest
772*795d594fSAndroid Build Coastguard Worker   // positions are >= 0.
773*795d594fSAndroid Build Coastguard Worker   if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
774*795d594fSAndroid Build Coastguard Worker       (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
775*795d594fSAndroid Build Coastguard Worker     // We will have to fail anyways.
776*795d594fSAndroid Build Coastguard Worker     return;
777*795d594fSAndroid Build Coastguard Worker   }
778*795d594fSAndroid Build Coastguard Worker 
779*795d594fSAndroid Build Coastguard Worker   // And since we are already checking, check the length too.
780*795d594fSAndroid Build Coastguard Worker   if (length != nullptr) {
781*795d594fSAndroid Build Coastguard Worker     int32_t len = length->GetValue();
782*795d594fSAndroid Build Coastguard Worker     if (len < 0) {
783*795d594fSAndroid Build Coastguard Worker       // Just call as normal.
784*795d594fSAndroid Build Coastguard Worker       return;
785*795d594fSAndroid Build Coastguard Worker     }
786*795d594fSAndroid Build Coastguard Worker   }
787*795d594fSAndroid Build Coastguard Worker 
788*795d594fSAndroid Build Coastguard Worker   // Okay, it is safe to generate inline code.
789*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
790*795d594fSAndroid Build Coastguard Worker       new (invoke->GetBlock()->GetGraph()->GetAllocator())
791*795d594fSAndroid Build Coastguard Worker       LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
792*795d594fSAndroid Build Coastguard Worker   // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
793*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
794*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
795*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
796*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
797*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
798*795d594fSAndroid Build Coastguard Worker 
799*795d594fSAndroid Build Coastguard Worker   // And we need some temporaries.  We will use REP MOVS{B,W,L}, so we need fixed registers.
800*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ESI));
801*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDI));
802*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ECX));
803*795d594fSAndroid Build Coastguard Worker }
804*795d594fSAndroid Build Coastguard Worker 
805*795d594fSAndroid Build Coastguard Worker template <typename LhsType>
EmitCmplJLess(X86Assembler * assembler,LhsType lhs,Location rhs,Label * label)806*795d594fSAndroid Build Coastguard Worker static void EmitCmplJLess(X86Assembler* assembler,
807*795d594fSAndroid Build Coastguard Worker                           LhsType lhs,
808*795d594fSAndroid Build Coastguard Worker                           Location rhs,
809*795d594fSAndroid Build Coastguard Worker                           Label* label) {
810*795d594fSAndroid Build Coastguard Worker   static_assert(std::is_same_v<LhsType, Register> || std::is_same_v<LhsType, Address>);
811*795d594fSAndroid Build Coastguard Worker   if (rhs.IsConstant()) {
812*795d594fSAndroid Build Coastguard Worker     int32_t rhs_constant = rhs.GetConstant()->AsIntConstant()->GetValue();
813*795d594fSAndroid Build Coastguard Worker     __ cmpl(lhs, Immediate(rhs_constant));
814*795d594fSAndroid Build Coastguard Worker   } else {
815*795d594fSAndroid Build Coastguard Worker     __ cmpl(lhs, rhs.AsRegister<Register>());
816*795d594fSAndroid Build Coastguard Worker   }
817*795d594fSAndroid Build Coastguard Worker   __ j(kLess, label);
818*795d594fSAndroid Build Coastguard Worker }
819*795d594fSAndroid Build Coastguard Worker 
CheckSystemArrayCopyPosition(X86Assembler * assembler,Register array,Location pos,Location length,SlowPathCode * slow_path,Register temp,bool length_is_array_length,bool position_sign_checked)820*795d594fSAndroid Build Coastguard Worker static void CheckSystemArrayCopyPosition(X86Assembler* assembler,
821*795d594fSAndroid Build Coastguard Worker                                          Register array,
822*795d594fSAndroid Build Coastguard Worker                                          Location pos,
823*795d594fSAndroid Build Coastguard Worker                                          Location length,
824*795d594fSAndroid Build Coastguard Worker                                          SlowPathCode* slow_path,
825*795d594fSAndroid Build Coastguard Worker                                          Register temp,
826*795d594fSAndroid Build Coastguard Worker                                          bool length_is_array_length,
827*795d594fSAndroid Build Coastguard Worker                                          bool position_sign_checked) {
828*795d594fSAndroid Build Coastguard Worker   // Where is the length in the Array?
829*795d594fSAndroid Build Coastguard Worker   const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
830*795d594fSAndroid Build Coastguard Worker 
831*795d594fSAndroid Build Coastguard Worker   if (pos.IsConstant()) {
832*795d594fSAndroid Build Coastguard Worker     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
833*795d594fSAndroid Build Coastguard Worker     if (pos_const == 0) {
834*795d594fSAndroid Build Coastguard Worker       if (!length_is_array_length) {
835*795d594fSAndroid Build Coastguard Worker         // Check that length(array) >= length.
836*795d594fSAndroid Build Coastguard Worker         EmitCmplJLess(assembler, Address(array, length_offset), length, slow_path->GetEntryLabel());
837*795d594fSAndroid Build Coastguard Worker       }
838*795d594fSAndroid Build Coastguard Worker     } else {
839*795d594fSAndroid Build Coastguard Worker       // Calculate length(array) - pos.
840*795d594fSAndroid Build Coastguard Worker       // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
841*795d594fSAndroid Build Coastguard Worker       // as `int32_t`. If the result is negative, the JL below shall go to the slow path.
842*795d594fSAndroid Build Coastguard Worker       __ movl(temp, Address(array, length_offset));
843*795d594fSAndroid Build Coastguard Worker       __ subl(temp, Immediate(pos_const));
844*795d594fSAndroid Build Coastguard Worker 
845*795d594fSAndroid Build Coastguard Worker       // Check that (length(array) - pos) >= length.
846*795d594fSAndroid Build Coastguard Worker       EmitCmplJLess(assembler, temp, length, slow_path->GetEntryLabel());
847*795d594fSAndroid Build Coastguard Worker     }
848*795d594fSAndroid Build Coastguard Worker   } else if (length_is_array_length) {
849*795d594fSAndroid Build Coastguard Worker     // The only way the copy can succeed is if pos is zero.
850*795d594fSAndroid Build Coastguard Worker     Register pos_reg = pos.AsRegister<Register>();
851*795d594fSAndroid Build Coastguard Worker     __ testl(pos_reg, pos_reg);
852*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, slow_path->GetEntryLabel());
853*795d594fSAndroid Build Coastguard Worker   } else {
854*795d594fSAndroid Build Coastguard Worker     // Check that pos >= 0.
855*795d594fSAndroid Build Coastguard Worker     Register pos_reg = pos.AsRegister<Register>();
856*795d594fSAndroid Build Coastguard Worker     if (!position_sign_checked) {
857*795d594fSAndroid Build Coastguard Worker       __ testl(pos_reg, pos_reg);
858*795d594fSAndroid Build Coastguard Worker       __ j(kLess, slow_path->GetEntryLabel());
859*795d594fSAndroid Build Coastguard Worker     }
860*795d594fSAndroid Build Coastguard Worker 
861*795d594fSAndroid Build Coastguard Worker     // Calculate length(array) - pos.
862*795d594fSAndroid Build Coastguard Worker     // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
863*795d594fSAndroid Build Coastguard Worker     // as `int32_t`. If the result is negative, the JL below shall go to the slow path.
864*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(array, length_offset));
865*795d594fSAndroid Build Coastguard Worker     __ subl(temp, pos_reg);
866*795d594fSAndroid Build Coastguard Worker 
867*795d594fSAndroid Build Coastguard Worker     // Check that (length(array) - pos) >= length.
868*795d594fSAndroid Build Coastguard Worker     EmitCmplJLess(assembler, temp, length, slow_path->GetEntryLabel());
869*795d594fSAndroid Build Coastguard Worker   }
870*795d594fSAndroid Build Coastguard Worker }
871*795d594fSAndroid Build Coastguard Worker 
SystemArrayCopyPrimitive(HInvoke * invoke,X86Assembler * assembler,CodeGeneratorX86 * codegen,DataType::Type type)872*795d594fSAndroid Build Coastguard Worker static void SystemArrayCopyPrimitive(HInvoke* invoke,
873*795d594fSAndroid Build Coastguard Worker                                      X86Assembler* assembler,
874*795d594fSAndroid Build Coastguard Worker                                      CodeGeneratorX86* codegen,
875*795d594fSAndroid Build Coastguard Worker                                      DataType::Type type) {
876*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
877*795d594fSAndroid Build Coastguard Worker   Register src = locations->InAt(0).AsRegister<Register>();
878*795d594fSAndroid Build Coastguard Worker   Location src_pos = locations->InAt(1);
879*795d594fSAndroid Build Coastguard Worker   Register dest = locations->InAt(2).AsRegister<Register>();
880*795d594fSAndroid Build Coastguard Worker   Location dest_pos = locations->InAt(3);
881*795d594fSAndroid Build Coastguard Worker   Location length = locations->InAt(4);
882*795d594fSAndroid Build Coastguard Worker 
883*795d594fSAndroid Build Coastguard Worker   // Temporaries that we need for MOVSB/W/L.
884*795d594fSAndroid Build Coastguard Worker   Register src_base = locations->GetTemp(0).AsRegister<Register>();
885*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(src_base, ESI);
886*795d594fSAndroid Build Coastguard Worker   Register dest_base = locations->GetTemp(1).AsRegister<Register>();
887*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(dest_base, EDI);
888*795d594fSAndroid Build Coastguard Worker   Register count = locations->GetTemp(2).AsRegister<Register>();
889*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(count, ECX);
890*795d594fSAndroid Build Coastguard Worker 
891*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
892*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
893*795d594fSAndroid Build Coastguard Worker 
894*795d594fSAndroid Build Coastguard Worker   // Bail out if the source and destination are the same (to handle overlap).
895*795d594fSAndroid Build Coastguard Worker   __ cmpl(src, dest);
896*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
897*795d594fSAndroid Build Coastguard Worker 
898*795d594fSAndroid Build Coastguard Worker   // Bail out if the source is null.
899*795d594fSAndroid Build Coastguard Worker   __ testl(src, src);
900*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
901*795d594fSAndroid Build Coastguard Worker 
902*795d594fSAndroid Build Coastguard Worker   // Bail out if the destination is null.
903*795d594fSAndroid Build Coastguard Worker   __ testl(dest, dest);
904*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
905*795d594fSAndroid Build Coastguard Worker 
906*795d594fSAndroid Build Coastguard Worker   // If the length is negative, bail out.
907*795d594fSAndroid Build Coastguard Worker   // We have already checked in the LocationsBuilder for the constant case.
908*795d594fSAndroid Build Coastguard Worker   if (!length.IsConstant()) {
909*795d594fSAndroid Build Coastguard Worker     __ cmpl(length.AsRegister<Register>(), length.AsRegister<Register>());
910*795d594fSAndroid Build Coastguard Worker     __ j(kLess, slow_path->GetEntryLabel());
911*795d594fSAndroid Build Coastguard Worker   }
912*795d594fSAndroid Build Coastguard Worker 
913*795d594fSAndroid Build Coastguard Worker   // We need the count in ECX.
914*795d594fSAndroid Build Coastguard Worker   if (length.IsConstant()) {
915*795d594fSAndroid Build Coastguard Worker     __ movl(count, Immediate(length.GetConstant()->AsIntConstant()->GetValue()));
916*795d594fSAndroid Build Coastguard Worker   } else {
917*795d594fSAndroid Build Coastguard Worker     __ movl(count, length.AsRegister<Register>());
918*795d594fSAndroid Build Coastguard Worker   }
919*795d594fSAndroid Build Coastguard Worker 
920*795d594fSAndroid Build Coastguard Worker   // Validity checks: source. Use src_base as a temporary register.
921*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(assembler,
922*795d594fSAndroid Build Coastguard Worker                                src,
923*795d594fSAndroid Build Coastguard Worker                                src_pos,
924*795d594fSAndroid Build Coastguard Worker                                Location::RegisterLocation(count),
925*795d594fSAndroid Build Coastguard Worker                                slow_path,
926*795d594fSAndroid Build Coastguard Worker                                src_base,
927*795d594fSAndroid Build Coastguard Worker                                /*length_is_array_length=*/ false,
928*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
929*795d594fSAndroid Build Coastguard Worker 
930*795d594fSAndroid Build Coastguard Worker   // Validity checks: dest. Use src_base as a temporary register.
931*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(assembler,
932*795d594fSAndroid Build Coastguard Worker                                dest,
933*795d594fSAndroid Build Coastguard Worker                                dest_pos,
934*795d594fSAndroid Build Coastguard Worker                                Location::RegisterLocation(count),
935*795d594fSAndroid Build Coastguard Worker                                slow_path,
936*795d594fSAndroid Build Coastguard Worker                                src_base,
937*795d594fSAndroid Build Coastguard Worker                                /*length_is_array_length=*/ false,
938*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
939*795d594fSAndroid Build Coastguard Worker 
940*795d594fSAndroid Build Coastguard Worker   // Okay, everything checks out.  Finally time to do the copy.
941*795d594fSAndroid Build Coastguard Worker   // Check assumption that sizeof(Char) is 2 (used in scaling below).
942*795d594fSAndroid Build Coastguard Worker   const size_t data_size = DataType::Size(type);
943*795d594fSAndroid Build Coastguard Worker   const uint32_t data_offset = mirror::Array::DataOffset(data_size).Uint32Value();
944*795d594fSAndroid Build Coastguard Worker 
945*795d594fSAndroid Build Coastguard Worker   GenArrayAddress(assembler, src_base, src, src_pos, type, data_offset);
946*795d594fSAndroid Build Coastguard Worker   GenArrayAddress(assembler, dest_base, dest, dest_pos, type, data_offset);
947*795d594fSAndroid Build Coastguard Worker 
948*795d594fSAndroid Build Coastguard Worker   // Do the move.
949*795d594fSAndroid Build Coastguard Worker   switch (type) {
950*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
951*795d594fSAndroid Build Coastguard Worker        __ rep_movsb();
952*795d594fSAndroid Build Coastguard Worker        break;
953*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
954*795d594fSAndroid Build Coastguard Worker        __ rep_movsw();
955*795d594fSAndroid Build Coastguard Worker        break;
956*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
957*795d594fSAndroid Build Coastguard Worker        __ rep_movsl();
958*795d594fSAndroid Build Coastguard Worker        break;
959*795d594fSAndroid Build Coastguard Worker     default:
960*795d594fSAndroid Build Coastguard Worker        LOG(FATAL) << "Unexpected data type for intrinsic";
961*795d594fSAndroid Build Coastguard Worker   }
962*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
963*795d594fSAndroid Build Coastguard Worker }
964*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyChar(HInvoke * invoke)965*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
966*795d594fSAndroid Build Coastguard Worker   CreateSystemArrayCopyLocations(invoke);
967*795d594fSAndroid Build Coastguard Worker }
968*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyChar(HInvoke * invoke)969*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
970*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
971*795d594fSAndroid Build Coastguard Worker   SystemArrayCopyPrimitive(invoke, assembler, codegen_, DataType::Type::kUint16);
972*795d594fSAndroid Build Coastguard Worker }
973*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyByte(HInvoke * invoke)974*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitSystemArrayCopyByte(HInvoke* invoke) {
975*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
976*795d594fSAndroid Build Coastguard Worker   SystemArrayCopyPrimitive(invoke, assembler, codegen_, DataType::Type::kInt8);
977*795d594fSAndroid Build Coastguard Worker }
978*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyByte(HInvoke * invoke)979*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitSystemArrayCopyByte(HInvoke* invoke) {
980*795d594fSAndroid Build Coastguard Worker   CreateSystemArrayCopyLocations(invoke);
981*795d594fSAndroid Build Coastguard Worker }
982*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyInt(HInvoke * invoke)983*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitSystemArrayCopyInt(HInvoke* invoke) {
984*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
985*795d594fSAndroid Build Coastguard Worker   SystemArrayCopyPrimitive(invoke, assembler, codegen_, DataType::Type::kInt32);
986*795d594fSAndroid Build Coastguard Worker }
987*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopyInt(HInvoke * invoke)988*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitSystemArrayCopyInt(HInvoke* invoke) {
989*795d594fSAndroid Build Coastguard Worker   CreateSystemArrayCopyLocations(invoke);
990*795d594fSAndroid Build Coastguard Worker }
991*795d594fSAndroid Build Coastguard Worker 
VisitStringCompareTo(HInvoke * invoke)992*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
993*795d594fSAndroid Build Coastguard Worker   // The inputs plus one temp.
994*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
995*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
996*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
997*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
998*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
999*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
1000*795d594fSAndroid Build Coastguard Worker }
1001*795d594fSAndroid Build Coastguard Worker 
VisitStringCompareTo(HInvoke * invoke)1002*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringCompareTo(HInvoke* invoke) {
1003*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
1004*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1005*795d594fSAndroid Build Coastguard Worker 
1006*795d594fSAndroid Build Coastguard Worker   // Note that the null check must have been done earlier.
1007*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1008*795d594fSAndroid Build Coastguard Worker 
1009*795d594fSAndroid Build Coastguard Worker   Register argument = locations->InAt(1).AsRegister<Register>();
1010*795d594fSAndroid Build Coastguard Worker   __ testl(argument, argument);
1011*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
1012*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
1013*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
1014*795d594fSAndroid Build Coastguard Worker 
1015*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
1016*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
1017*795d594fSAndroid Build Coastguard Worker }
1018*795d594fSAndroid Build Coastguard Worker 
VisitStringEquals(HInvoke * invoke)1019*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringEquals(HInvoke* invoke) {
1020*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1021*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1022*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
1023*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1024*795d594fSAndroid Build Coastguard Worker 
1025*795d594fSAndroid Build Coastguard Worker   // Request temporary registers, ECX and EDI needed for repe_cmpsl instruction.
1026*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ECX));
1027*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDI));
1028*795d594fSAndroid Build Coastguard Worker 
1029*795d594fSAndroid Build Coastguard Worker   // Set output, ESI needed for repe_cmpsl instruction anyways.
1030*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(ESI), Location::kOutputOverlap);
1031*795d594fSAndroid Build Coastguard Worker }
1032*795d594fSAndroid Build Coastguard Worker 
VisitStringEquals(HInvoke * invoke)1033*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringEquals(HInvoke* invoke) {
1034*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
1035*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1036*795d594fSAndroid Build Coastguard Worker 
1037*795d594fSAndroid Build Coastguard Worker   Register str = locations->InAt(0).AsRegister<Register>();
1038*795d594fSAndroid Build Coastguard Worker   Register arg = locations->InAt(1).AsRegister<Register>();
1039*795d594fSAndroid Build Coastguard Worker   Register ecx = locations->GetTemp(0).AsRegister<Register>();
1040*795d594fSAndroid Build Coastguard Worker   Register edi = locations->GetTemp(1).AsRegister<Register>();
1041*795d594fSAndroid Build Coastguard Worker   Register esi = locations->Out().AsRegister<Register>();
1042*795d594fSAndroid Build Coastguard Worker 
1043*795d594fSAndroid Build Coastguard Worker   NearLabel end, return_true, return_false;
1044*795d594fSAndroid Build Coastguard Worker 
1045*795d594fSAndroid Build Coastguard Worker   // Get offsets of count, value, and class fields within a string object.
1046*795d594fSAndroid Build Coastguard Worker   const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1047*795d594fSAndroid Build Coastguard Worker   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1048*795d594fSAndroid Build Coastguard Worker   const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
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   StringEqualsOptimizations optimizations(invoke);
1054*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetArgumentNotNull()) {
1055*795d594fSAndroid Build Coastguard Worker     // Check if input is null, return false if it is.
1056*795d594fSAndroid Build Coastguard Worker     __ testl(arg, arg);
1057*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &return_false);
1058*795d594fSAndroid Build Coastguard Worker   }
1059*795d594fSAndroid Build Coastguard Worker 
1060*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetArgumentIsString()) {
1061*795d594fSAndroid Build Coastguard Worker     // Instanceof check for the argument by comparing class fields.
1062*795d594fSAndroid Build Coastguard Worker     // All string objects must have the same type since String cannot be subclassed.
1063*795d594fSAndroid Build Coastguard Worker     // Receiver must be a string object, so its class field is equal to all strings' class fields.
1064*795d594fSAndroid Build Coastguard Worker     // If the argument is a string object, its class field must be equal to receiver's class field.
1065*795d594fSAndroid Build Coastguard Worker     //
1066*795d594fSAndroid Build Coastguard Worker     // As the String class is expected to be non-movable, we can read the class
1067*795d594fSAndroid Build Coastguard Worker     // field from String.equals' arguments without read barriers.
1068*795d594fSAndroid Build Coastguard Worker     AssertNonMovableStringClass();
1069*795d594fSAndroid Build Coastguard Worker     // Also, because we use the loaded class references only to compare them, we
1070*795d594fSAndroid Build Coastguard Worker     // don't need to unpoison them.
1071*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ ecx = str->klass_
1072*795d594fSAndroid Build Coastguard Worker     __ movl(ecx, Address(str, class_offset));
1073*795d594fSAndroid Build Coastguard Worker     // if (ecx != /* HeapReference<Class> */ arg->klass_) return false
1074*795d594fSAndroid Build Coastguard Worker     __ cmpl(ecx, Address(arg, class_offset));
1075*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, &return_false);
1076*795d594fSAndroid Build Coastguard Worker   }
1077*795d594fSAndroid Build Coastguard Worker 
1078*795d594fSAndroid Build Coastguard Worker   // Reference equality check, return true if same reference.
1079*795d594fSAndroid Build Coastguard Worker   __ cmpl(str, arg);
1080*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &return_true);
1081*795d594fSAndroid Build Coastguard Worker 
1082*795d594fSAndroid Build Coastguard Worker   // Load length and compression flag of receiver string.
1083*795d594fSAndroid Build Coastguard Worker   __ movl(ecx, Address(str, count_offset));
1084*795d594fSAndroid Build Coastguard Worker   // Check if lengths and compression flags are equal, return false if they're not.
1085*795d594fSAndroid Build Coastguard Worker   // Two identical strings will always have same compression style since
1086*795d594fSAndroid Build Coastguard Worker   // compression style is decided on alloc.
1087*795d594fSAndroid Build Coastguard Worker   __ cmpl(ecx, Address(arg, count_offset));
1088*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &return_false);
1089*795d594fSAndroid Build Coastguard Worker   // Return true if strings are empty. Even with string compression `count == 0` means empty.
1090*795d594fSAndroid Build Coastguard Worker   static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1091*795d594fSAndroid Build Coastguard Worker                 "Expecting 0=compressed, 1=uncompressed");
1092*795d594fSAndroid Build Coastguard Worker   __ jecxz(&return_true);
1093*795d594fSAndroid Build Coastguard Worker 
1094*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1095*795d594fSAndroid Build Coastguard Worker     NearLabel string_uncompressed;
1096*795d594fSAndroid Build Coastguard Worker     // Extract length and differentiate between both compressed or both uncompressed.
1097*795d594fSAndroid Build Coastguard Worker     // Different compression style is cut above.
1098*795d594fSAndroid Build Coastguard Worker     __ shrl(ecx, Immediate(1));
1099*795d594fSAndroid Build Coastguard Worker     __ j(kCarrySet, &string_uncompressed);
1100*795d594fSAndroid Build Coastguard Worker     // Divide string length by 2, rounding up, and continue as if uncompressed.
1101*795d594fSAndroid Build Coastguard Worker     __ addl(ecx, Immediate(1));
1102*795d594fSAndroid Build Coastguard Worker     __ shrl(ecx, Immediate(1));
1103*795d594fSAndroid Build Coastguard Worker     __ Bind(&string_uncompressed);
1104*795d594fSAndroid Build Coastguard Worker   }
1105*795d594fSAndroid Build Coastguard Worker   // Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
1106*795d594fSAndroid Build Coastguard Worker   __ leal(esi, Address(str, value_offset));
1107*795d594fSAndroid Build Coastguard Worker   __ leal(edi, Address(arg, value_offset));
1108*795d594fSAndroid Build Coastguard Worker 
1109*795d594fSAndroid Build Coastguard Worker   // Divide string length by 2 to compare characters 2 at a time and adjust for lengths not
1110*795d594fSAndroid Build Coastguard Worker   // divisible by 2.
1111*795d594fSAndroid Build Coastguard Worker   __ addl(ecx, Immediate(1));
1112*795d594fSAndroid Build Coastguard Worker   __ shrl(ecx, Immediate(1));
1113*795d594fSAndroid Build Coastguard Worker 
1114*795d594fSAndroid Build Coastguard Worker   // Assertions that must hold in order to compare strings 2 characters (uncompressed)
1115*795d594fSAndroid Build Coastguard Worker   // or 4 characters (compressed) at a time.
1116*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(value_offset, 4);
1117*795d594fSAndroid Build Coastguard Worker   static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
1118*795d594fSAndroid Build Coastguard Worker 
1119*795d594fSAndroid Build Coastguard Worker   // Loop to compare strings two characters at a time starting at the beginning of the string.
1120*795d594fSAndroid Build Coastguard Worker   __ repe_cmpsl();
1121*795d594fSAndroid Build Coastguard Worker   // If strings are not equal, zero flag will be cleared.
1122*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &return_false);
1123*795d594fSAndroid Build Coastguard Worker 
1124*795d594fSAndroid Build Coastguard Worker   // Return true and exit the function.
1125*795d594fSAndroid Build Coastguard Worker   // If loop does not result in returning false, we return true.
1126*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_true);
1127*795d594fSAndroid Build Coastguard Worker   __ movl(esi, Immediate(1));
1128*795d594fSAndroid Build Coastguard Worker   __ jmp(&end);
1129*795d594fSAndroid Build Coastguard Worker 
1130*795d594fSAndroid Build Coastguard Worker   // Return false and exit the function.
1131*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_false);
1132*795d594fSAndroid Build Coastguard Worker   __ xorl(esi, esi);
1133*795d594fSAndroid Build Coastguard Worker   __ Bind(&end);
1134*795d594fSAndroid Build Coastguard Worker }
1135*795d594fSAndroid Build Coastguard Worker 
CreateStringIndexOfLocations(HInvoke * invoke,ArenaAllocator * allocator,bool start_at_zero)1136*795d594fSAndroid Build Coastguard Worker static void CreateStringIndexOfLocations(HInvoke* invoke,
1137*795d594fSAndroid Build Coastguard Worker                                          ArenaAllocator* allocator,
1138*795d594fSAndroid Build Coastguard Worker                                          bool start_at_zero) {
1139*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(invoke,
1140*795d594fSAndroid Build Coastguard Worker                                                                LocationSummary::kCallOnSlowPath,
1141*795d594fSAndroid Build Coastguard Worker                                                                kIntrinsified);
1142*795d594fSAndroid Build Coastguard Worker   // The data needs to be in EDI for scasw. So request that the string is there, anyways.
1143*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(EDI));
1144*795d594fSAndroid Build Coastguard Worker   // If we look for a constant char, we'll still have to copy it into EAX. So just request the
1145*795d594fSAndroid Build Coastguard Worker   // allocator to do that, anyways. We can still do the constant check by checking the parameter
1146*795d594fSAndroid Build Coastguard Worker   // of the instruction explicitly.
1147*795d594fSAndroid Build Coastguard Worker   // Note: This works as we don't clobber EAX anywhere.
1148*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterLocation(EAX));
1149*795d594fSAndroid Build Coastguard Worker   if (!start_at_zero) {
1150*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::RequiresRegister());          // The starting index.
1151*795d594fSAndroid Build Coastguard Worker   }
1152*795d594fSAndroid Build Coastguard Worker   // As we clobber EDI during execution anyways, also use it as the output.
1153*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
1154*795d594fSAndroid Build Coastguard Worker 
1155*795d594fSAndroid Build Coastguard Worker   // repne scasw uses ECX as the counter.
1156*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ECX));
1157*795d594fSAndroid Build Coastguard Worker   // Need another temporary to be able to compute the result.
1158*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
1159*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1160*795d594fSAndroid Build Coastguard Worker     // Need another temporary to be able to save unflagged string length.
1161*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
1162*795d594fSAndroid Build Coastguard Worker   }
1163*795d594fSAndroid Build Coastguard Worker }
1164*795d594fSAndroid Build Coastguard Worker 
GenerateStringIndexOf(HInvoke * invoke,X86Assembler * assembler,CodeGeneratorX86 * codegen,bool start_at_zero)1165*795d594fSAndroid Build Coastguard Worker static void GenerateStringIndexOf(HInvoke* invoke,
1166*795d594fSAndroid Build Coastguard Worker                                   X86Assembler* assembler,
1167*795d594fSAndroid Build Coastguard Worker                                   CodeGeneratorX86* codegen,
1168*795d594fSAndroid Build Coastguard Worker                                   bool start_at_zero) {
1169*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1170*795d594fSAndroid Build Coastguard Worker 
1171*795d594fSAndroid Build Coastguard Worker   // Note that the null check must have been done earlier.
1172*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1173*795d594fSAndroid Build Coastguard Worker 
1174*795d594fSAndroid Build Coastguard Worker   Register string_obj = locations->InAt(0).AsRegister<Register>();
1175*795d594fSAndroid Build Coastguard Worker   Register search_value = locations->InAt(1).AsRegister<Register>();
1176*795d594fSAndroid Build Coastguard Worker   Register counter = locations->GetTemp(0).AsRegister<Register>();
1177*795d594fSAndroid Build Coastguard Worker   Register string_length = locations->GetTemp(1).AsRegister<Register>();
1178*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
1179*795d594fSAndroid Build Coastguard Worker   // Only used when string compression feature is on.
1180*795d594fSAndroid Build Coastguard Worker   Register string_length_flagged;
1181*795d594fSAndroid Build Coastguard Worker 
1182*795d594fSAndroid Build Coastguard Worker   // Check our assumptions for registers.
1183*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(string_obj, EDI);
1184*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(search_value, EAX);
1185*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(counter, ECX);
1186*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(out, EDI);
1187*795d594fSAndroid Build Coastguard Worker 
1188*795d594fSAndroid Build Coastguard Worker   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
1189*795d594fSAndroid Build Coastguard Worker   // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
1190*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = nullptr;
1191*795d594fSAndroid Build Coastguard Worker   HInstruction* code_point = invoke->InputAt(1);
1192*795d594fSAndroid Build Coastguard Worker   if (code_point->IsIntConstant()) {
1193*795d594fSAndroid Build Coastguard Worker     if (static_cast<uint32_t>(code_point->AsIntConstant()->GetValue()) >
1194*795d594fSAndroid Build Coastguard Worker         std::numeric_limits<uint16_t>::max()) {
1195*795d594fSAndroid Build Coastguard Worker       // Always needs the slow-path. We could directly dispatch to it, but this case should be
1196*795d594fSAndroid Build Coastguard Worker       // rare, so for simplicity just put the full slow-path down and branch unconditionally.
1197*795d594fSAndroid Build Coastguard Worker       slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
1198*795d594fSAndroid Build Coastguard Worker       codegen->AddSlowPath(slow_path);
1199*795d594fSAndroid Build Coastguard Worker       __ jmp(slow_path->GetEntryLabel());
1200*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetExitLabel());
1201*795d594fSAndroid Build Coastguard Worker       return;
1202*795d594fSAndroid Build Coastguard Worker     }
1203*795d594fSAndroid Build Coastguard Worker   } else if (code_point->GetType() != DataType::Type::kUint16) {
1204*795d594fSAndroid Build Coastguard Worker     __ cmpl(search_value, Immediate(std::numeric_limits<uint16_t>::max()));
1205*795d594fSAndroid Build Coastguard Worker     slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
1206*795d594fSAndroid Build Coastguard Worker     codegen->AddSlowPath(slow_path);
1207*795d594fSAndroid Build Coastguard Worker     __ j(kAbove, slow_path->GetEntryLabel());
1208*795d594fSAndroid Build Coastguard Worker   }
1209*795d594fSAndroid Build Coastguard Worker 
1210*795d594fSAndroid Build Coastguard Worker   // From here down, we know that we are looking for a char that fits in 16 bits.
1211*795d594fSAndroid Build Coastguard Worker   // Location of reference to data array within the String object.
1212*795d594fSAndroid Build Coastguard Worker   int32_t value_offset = mirror::String::ValueOffset().Int32Value();
1213*795d594fSAndroid Build Coastguard Worker   // Location of count within the String object.
1214*795d594fSAndroid Build Coastguard Worker   int32_t count_offset = mirror::String::CountOffset().Int32Value();
1215*795d594fSAndroid Build Coastguard Worker 
1216*795d594fSAndroid Build Coastguard Worker   // Load the count field of the string containing the length and compression flag.
1217*795d594fSAndroid Build Coastguard Worker   __ movl(string_length, Address(string_obj, count_offset));
1218*795d594fSAndroid Build Coastguard Worker 
1219*795d594fSAndroid Build Coastguard Worker   // Do a zero-length check. Even with string compression `count == 0` means empty.
1220*795d594fSAndroid Build Coastguard Worker   static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1221*795d594fSAndroid Build Coastguard Worker                 "Expecting 0=compressed, 1=uncompressed");
1222*795d594fSAndroid Build Coastguard Worker   // TODO: Support jecxz.
1223*795d594fSAndroid Build Coastguard Worker   NearLabel not_found_label;
1224*795d594fSAndroid Build Coastguard Worker   __ testl(string_length, string_length);
1225*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &not_found_label);
1226*795d594fSAndroid Build Coastguard Worker 
1227*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1228*795d594fSAndroid Build Coastguard Worker     string_length_flagged = locations->GetTemp(2).AsRegister<Register>();
1229*795d594fSAndroid Build Coastguard Worker     __ movl(string_length_flagged, string_length);
1230*795d594fSAndroid Build Coastguard Worker     // Extract the length and shift out the least significant bit used as compression flag.
1231*795d594fSAndroid Build Coastguard Worker     __ shrl(string_length, Immediate(1));
1232*795d594fSAndroid Build Coastguard Worker   }
1233*795d594fSAndroid Build Coastguard Worker 
1234*795d594fSAndroid Build Coastguard Worker   if (start_at_zero) {
1235*795d594fSAndroid Build Coastguard Worker     // Number of chars to scan is the same as the string length.
1236*795d594fSAndroid Build Coastguard Worker     __ movl(counter, string_length);
1237*795d594fSAndroid Build Coastguard Worker 
1238*795d594fSAndroid Build Coastguard Worker     // Move to the start of the string.
1239*795d594fSAndroid Build Coastguard Worker     __ addl(string_obj, Immediate(value_offset));
1240*795d594fSAndroid Build Coastguard Worker   } else {
1241*795d594fSAndroid Build Coastguard Worker     Register start_index = locations->InAt(2).AsRegister<Register>();
1242*795d594fSAndroid Build Coastguard Worker 
1243*795d594fSAndroid Build Coastguard Worker     // Do a start_index check.
1244*795d594fSAndroid Build Coastguard Worker     __ cmpl(start_index, string_length);
1245*795d594fSAndroid Build Coastguard Worker     __ j(kGreaterEqual, &not_found_label);
1246*795d594fSAndroid Build Coastguard Worker 
1247*795d594fSAndroid Build Coastguard Worker     // Ensure we have a start index >= 0;
1248*795d594fSAndroid Build Coastguard Worker     __ xorl(counter, counter);
1249*795d594fSAndroid Build Coastguard Worker     __ cmpl(start_index, Immediate(0));
1250*795d594fSAndroid Build Coastguard Worker     __ cmovl(kGreater, counter, start_index);
1251*795d594fSAndroid Build Coastguard Worker 
1252*795d594fSAndroid Build Coastguard Worker     if (mirror::kUseStringCompression) {
1253*795d594fSAndroid Build Coastguard Worker       NearLabel modify_counter, offset_uncompressed_label;
1254*795d594fSAndroid Build Coastguard Worker       __ testl(string_length_flagged, Immediate(1));
1255*795d594fSAndroid Build Coastguard Worker       __ j(kNotZero, &offset_uncompressed_label);
1256*795d594fSAndroid Build Coastguard Worker       // Move to the start of the string: string_obj + value_offset + start_index.
1257*795d594fSAndroid Build Coastguard Worker       __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
1258*795d594fSAndroid Build Coastguard Worker       __ jmp(&modify_counter);
1259*795d594fSAndroid Build Coastguard Worker 
1260*795d594fSAndroid Build Coastguard Worker       // Move to the start of the string: string_obj + value_offset + 2 * start_index.
1261*795d594fSAndroid Build Coastguard Worker       __ Bind(&offset_uncompressed_label);
1262*795d594fSAndroid Build Coastguard Worker       __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
1263*795d594fSAndroid Build Coastguard Worker 
1264*795d594fSAndroid Build Coastguard Worker       // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
1265*795d594fSAndroid Build Coastguard Worker       // compare.
1266*795d594fSAndroid Build Coastguard Worker       __ Bind(&modify_counter);
1267*795d594fSAndroid Build Coastguard Worker     } else {
1268*795d594fSAndroid Build Coastguard Worker       __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
1269*795d594fSAndroid Build Coastguard Worker     }
1270*795d594fSAndroid Build Coastguard Worker     __ negl(counter);
1271*795d594fSAndroid Build Coastguard Worker     __ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
1272*795d594fSAndroid Build Coastguard Worker   }
1273*795d594fSAndroid Build Coastguard Worker 
1274*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1275*795d594fSAndroid Build Coastguard Worker     NearLabel uncompressed_string_comparison;
1276*795d594fSAndroid Build Coastguard Worker     NearLabel comparison_done;
1277*795d594fSAndroid Build Coastguard Worker     __ testl(string_length_flagged, Immediate(1));
1278*795d594fSAndroid Build Coastguard Worker     __ j(kNotZero, &uncompressed_string_comparison);
1279*795d594fSAndroid Build Coastguard Worker 
1280*795d594fSAndroid Build Coastguard Worker     // Check if EAX (search_value) is ASCII.
1281*795d594fSAndroid Build Coastguard Worker     __ cmpl(search_value, Immediate(127));
1282*795d594fSAndroid Build Coastguard Worker     __ j(kGreater, &not_found_label);
1283*795d594fSAndroid Build Coastguard Worker     // Comparing byte-per-byte.
1284*795d594fSAndroid Build Coastguard Worker     __ repne_scasb();
1285*795d594fSAndroid Build Coastguard Worker     __ jmp(&comparison_done);
1286*795d594fSAndroid Build Coastguard Worker 
1287*795d594fSAndroid Build Coastguard Worker     // Everything is set up for repne scasw:
1288*795d594fSAndroid Build Coastguard Worker     //   * Comparison address in EDI.
1289*795d594fSAndroid Build Coastguard Worker     //   * Counter in ECX.
1290*795d594fSAndroid Build Coastguard Worker     __ Bind(&uncompressed_string_comparison);
1291*795d594fSAndroid Build Coastguard Worker     __ repne_scasw();
1292*795d594fSAndroid Build Coastguard Worker     __ Bind(&comparison_done);
1293*795d594fSAndroid Build Coastguard Worker   } else {
1294*795d594fSAndroid Build Coastguard Worker     __ repne_scasw();
1295*795d594fSAndroid Build Coastguard Worker   }
1296*795d594fSAndroid Build Coastguard Worker   // Did we find a match?
1297*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &not_found_label);
1298*795d594fSAndroid Build Coastguard Worker 
1299*795d594fSAndroid Build Coastguard Worker   // Yes, we matched.  Compute the index of the result.
1300*795d594fSAndroid Build Coastguard Worker   __ subl(string_length, counter);
1301*795d594fSAndroid Build Coastguard Worker   __ leal(out, Address(string_length, -1));
1302*795d594fSAndroid Build Coastguard Worker 
1303*795d594fSAndroid Build Coastguard Worker   NearLabel done;
1304*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
1305*795d594fSAndroid Build Coastguard Worker 
1306*795d594fSAndroid Build Coastguard Worker   // Failed to match; return -1.
1307*795d594fSAndroid Build Coastguard Worker   __ Bind(&not_found_label);
1308*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(-1));
1309*795d594fSAndroid Build Coastguard Worker 
1310*795d594fSAndroid Build Coastguard Worker   // And join up at the end.
1311*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
1312*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
1313*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
1314*795d594fSAndroid Build Coastguard Worker   }
1315*795d594fSAndroid Build Coastguard Worker }
1316*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOf(HInvoke * invoke)1317*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringIndexOf(HInvoke* invoke) {
1318*795d594fSAndroid Build Coastguard Worker   CreateStringIndexOfLocations(invoke, allocator_, /* start_at_zero= */ true);
1319*795d594fSAndroid Build Coastguard Worker }
1320*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOf(HInvoke * invoke)1321*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringIndexOf(HInvoke* invoke) {
1322*795d594fSAndroid Build Coastguard Worker   GenerateStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero= */ true);
1323*795d594fSAndroid Build Coastguard Worker }
1324*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOfAfter(HInvoke * invoke)1325*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringIndexOfAfter(HInvoke* invoke) {
1326*795d594fSAndroid Build Coastguard Worker   CreateStringIndexOfLocations(invoke, allocator_, /* start_at_zero= */ false);
1327*795d594fSAndroid Build Coastguard Worker }
1328*795d594fSAndroid Build Coastguard Worker 
VisitStringIndexOfAfter(HInvoke * invoke)1329*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringIndexOfAfter(HInvoke* invoke) {
1330*795d594fSAndroid Build Coastguard Worker   GenerateStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero= */ false);
1331*795d594fSAndroid Build Coastguard Worker }
1332*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromBytes(HInvoke * invoke)1333*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1334*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
1335*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
1336*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
1337*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1338*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1339*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1340*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1341*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
1342*795d594fSAndroid Build Coastguard Worker }
1343*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromBytes(HInvoke * invoke)1344*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1345*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
1346*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1347*795d594fSAndroid Build Coastguard Worker 
1348*795d594fSAndroid Build Coastguard Worker   Register byte_array = locations->InAt(0).AsRegister<Register>();
1349*795d594fSAndroid Build Coastguard Worker   __ testl(byte_array, byte_array);
1350*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
1351*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
1352*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
1353*795d594fSAndroid Build Coastguard Worker 
1354*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc());
1355*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
1356*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
1357*795d594fSAndroid Build Coastguard Worker }
1358*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromChars(HInvoke * invoke)1359*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1360*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1361*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
1362*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
1363*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1364*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1365*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1366*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
1367*795d594fSAndroid Build Coastguard Worker }
1368*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromChars(HInvoke * invoke)1369*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1370*795d594fSAndroid Build Coastguard Worker   // No need to emit code checking whether `locations->InAt(2)` is a null
1371*795d594fSAndroid Build Coastguard Worker   // pointer, as callers of the native method
1372*795d594fSAndroid Build Coastguard Worker   //
1373*795d594fSAndroid Build Coastguard Worker   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1374*795d594fSAndroid Build Coastguard Worker   //
1375*795d594fSAndroid Build Coastguard Worker   // all include a null check on `data` before calling that method.
1376*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
1377*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
1378*795d594fSAndroid Build Coastguard Worker }
1379*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromString(HInvoke * invoke)1380*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringNewStringFromString(HInvoke* invoke) {
1381*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(
1382*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
1383*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
1384*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1385*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
1386*795d594fSAndroid Build Coastguard Worker }
1387*795d594fSAndroid Build Coastguard Worker 
VisitStringNewStringFromString(HInvoke * invoke)1388*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringNewStringFromString(HInvoke* invoke) {
1389*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
1390*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1391*795d594fSAndroid Build Coastguard Worker 
1392*795d594fSAndroid Build Coastguard Worker   Register string_to_copy = locations->InAt(0).AsRegister<Register>();
1393*795d594fSAndroid Build Coastguard Worker   __ testl(string_to_copy, string_to_copy);
1394*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
1395*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
1396*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
1397*795d594fSAndroid Build Coastguard Worker 
1398*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc());
1399*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
1400*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
1401*795d594fSAndroid Build Coastguard Worker }
1402*795d594fSAndroid Build Coastguard Worker 
VisitStringGetCharsNoCheck(HInvoke * invoke)1403*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1404*795d594fSAndroid Build Coastguard Worker   // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1405*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1406*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1407*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
1408*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
1409*795d594fSAndroid Build Coastguard Worker   // Place srcEnd in ECX to save a move below.
1410*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RegisterLocation(ECX));
1411*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(3, Location::RequiresRegister());
1412*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(4, Location::RequiresRegister());
1413*795d594fSAndroid Build Coastguard Worker 
1414*795d594fSAndroid Build Coastguard Worker   // And we need some temporaries.  We will use REP MOVSW, so we need fixed registers.
1415*795d594fSAndroid Build Coastguard Worker   // We don't have enough registers to also grab ECX, so handle below.
1416*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ESI));
1417*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDI));
1418*795d594fSAndroid Build Coastguard Worker }
1419*795d594fSAndroid Build Coastguard Worker 
VisitStringGetCharsNoCheck(HInvoke * invoke)1420*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1421*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
1422*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1423*795d594fSAndroid Build Coastguard Worker 
1424*795d594fSAndroid Build Coastguard Worker   size_t char_component_size = DataType::Size(DataType::Type::kUint16);
1425*795d594fSAndroid Build Coastguard Worker   // Location of data in char array buffer.
1426*795d594fSAndroid Build Coastguard Worker   const uint32_t data_offset = mirror::Array::DataOffset(char_component_size).Uint32Value();
1427*795d594fSAndroid Build Coastguard Worker   // Location of char array data in string.
1428*795d594fSAndroid Build Coastguard Worker   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1429*795d594fSAndroid Build Coastguard Worker 
1430*795d594fSAndroid Build Coastguard Worker   // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1431*795d594fSAndroid Build Coastguard Worker   Register obj = locations->InAt(0).AsRegister<Register>();
1432*795d594fSAndroid Build Coastguard Worker   Location srcBegin = locations->InAt(1);
1433*795d594fSAndroid Build Coastguard Worker   int srcBegin_value =
1434*795d594fSAndroid Build Coastguard Worker       srcBegin.IsConstant() ? srcBegin.GetConstant()->AsIntConstant()->GetValue() : 0;
1435*795d594fSAndroid Build Coastguard Worker   Register srcEnd = locations->InAt(2).AsRegister<Register>();
1436*795d594fSAndroid Build Coastguard Worker   Register dst = locations->InAt(3).AsRegister<Register>();
1437*795d594fSAndroid Build Coastguard Worker   Register dstBegin = locations->InAt(4).AsRegister<Register>();
1438*795d594fSAndroid Build Coastguard Worker 
1439*795d594fSAndroid Build Coastguard Worker   // Check assumption that sizeof(Char) is 2 (used in scaling below).
1440*795d594fSAndroid Build Coastguard Worker   const size_t char_size = DataType::Size(DataType::Type::kUint16);
1441*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(char_size, 2u);
1442*795d594fSAndroid Build Coastguard Worker 
1443*795d594fSAndroid Build Coastguard Worker   // Compute the number of chars (words) to move.
1444*795d594fSAndroid Build Coastguard Worker   // Save ECX, since we don't know if it will be used later.
1445*795d594fSAndroid Build Coastguard Worker   __ pushl(ECX);
1446*795d594fSAndroid Build Coastguard Worker   int stack_adjust = kX86WordSize;
1447*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(stack_adjust);
1448*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(srcEnd, ECX);
1449*795d594fSAndroid Build Coastguard Worker   if (srcBegin.IsConstant()) {
1450*795d594fSAndroid Build Coastguard Worker     __ subl(ECX, Immediate(srcBegin_value));
1451*795d594fSAndroid Build Coastguard Worker   } else {
1452*795d594fSAndroid Build Coastguard Worker     DCHECK(srcBegin.IsRegister());
1453*795d594fSAndroid Build Coastguard Worker     __ subl(ECX, srcBegin.AsRegister<Register>());
1454*795d594fSAndroid Build Coastguard Worker   }
1455*795d594fSAndroid Build Coastguard Worker 
1456*795d594fSAndroid Build Coastguard Worker   NearLabel done;
1457*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1458*795d594fSAndroid Build Coastguard Worker     // Location of count in string
1459*795d594fSAndroid Build Coastguard Worker     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1460*795d594fSAndroid Build Coastguard Worker     const size_t c_char_size = DataType::Size(DataType::Type::kInt8);
1461*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(c_char_size, 1u);
1462*795d594fSAndroid Build Coastguard Worker     __ pushl(EAX);
1463*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(stack_adjust);
1464*795d594fSAndroid Build Coastguard Worker 
1465*795d594fSAndroid Build Coastguard Worker     NearLabel copy_loop, copy_uncompressed;
1466*795d594fSAndroid Build Coastguard Worker     __ testl(Address(obj, count_offset), Immediate(1));
1467*795d594fSAndroid Build Coastguard Worker     static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1468*795d594fSAndroid Build Coastguard Worker                   "Expecting 0=compressed, 1=uncompressed");
1469*795d594fSAndroid Build Coastguard Worker     __ j(kNotZero, &copy_uncompressed);
1470*795d594fSAndroid Build Coastguard Worker     // Compute the address of the source string by adding the number of chars from
1471*795d594fSAndroid Build Coastguard Worker     // the source beginning to the value offset of a string.
1472*795d594fSAndroid Build Coastguard Worker     __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
1473*795d594fSAndroid Build Coastguard Worker 
1474*795d594fSAndroid Build Coastguard Worker     // Start the loop to copy String's value to Array of Char.
1475*795d594fSAndroid Build Coastguard Worker     __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
1476*795d594fSAndroid Build Coastguard Worker     __ Bind(&copy_loop);
1477*795d594fSAndroid Build Coastguard Worker     __ jecxz(&done);
1478*795d594fSAndroid Build Coastguard Worker     // Use EAX temporary (convert byte from ESI to word).
1479*795d594fSAndroid Build Coastguard Worker     // TODO: Use LODSB/STOSW (not supported by X86Assembler) with AH initialized to 0.
1480*795d594fSAndroid Build Coastguard Worker     __ movzxb(EAX, Address(ESI, 0));
1481*795d594fSAndroid Build Coastguard Worker     __ movw(Address(EDI, 0), EAX);
1482*795d594fSAndroid Build Coastguard Worker     __ leal(EDI, Address(EDI, char_size));
1483*795d594fSAndroid Build Coastguard Worker     __ leal(ESI, Address(ESI, c_char_size));
1484*795d594fSAndroid Build Coastguard Worker     // TODO: Add support for LOOP to X86Assembler.
1485*795d594fSAndroid Build Coastguard Worker     __ subl(ECX, Immediate(1));
1486*795d594fSAndroid Build Coastguard Worker     __ jmp(&copy_loop);
1487*795d594fSAndroid Build Coastguard Worker     __ Bind(&copy_uncompressed);
1488*795d594fSAndroid Build Coastguard Worker   }
1489*795d594fSAndroid Build Coastguard Worker 
1490*795d594fSAndroid Build Coastguard Worker   // Do the copy for uncompressed string.
1491*795d594fSAndroid Build Coastguard Worker   // Compute the address of the destination buffer.
1492*795d594fSAndroid Build Coastguard Worker   __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
1493*795d594fSAndroid Build Coastguard Worker   __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
1494*795d594fSAndroid Build Coastguard Worker   __ rep_movsw();
1495*795d594fSAndroid Build Coastguard Worker 
1496*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
1497*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression) {
1498*795d594fSAndroid Build Coastguard Worker     // Restore EAX.
1499*795d594fSAndroid Build Coastguard Worker     __ popl(EAX);
1500*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(-stack_adjust);
1501*795d594fSAndroid Build Coastguard Worker   }
1502*795d594fSAndroid Build Coastguard Worker   // Restore ECX.
1503*795d594fSAndroid Build Coastguard Worker   __ popl(ECX);
1504*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(-stack_adjust);
1505*795d594fSAndroid Build Coastguard Worker }
1506*795d594fSAndroid Build Coastguard Worker 
GenPeek(LocationSummary * locations,DataType::Type size,X86Assembler * assembler)1507*795d594fSAndroid Build Coastguard Worker static void GenPeek(LocationSummary* locations, DataType::Type size, X86Assembler* assembler) {
1508*795d594fSAndroid Build Coastguard Worker   Register address = locations->InAt(0).AsRegisterPairLow<Register>();
1509*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
1510*795d594fSAndroid Build Coastguard Worker   // x86 allows unaligned access. We do not have to check the input or use specific instructions
1511*795d594fSAndroid Build Coastguard Worker   // to avoid a SIGBUS.
1512*795d594fSAndroid Build Coastguard Worker   switch (size) {
1513*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1514*795d594fSAndroid Build Coastguard Worker       __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
1515*795d594fSAndroid Build Coastguard Worker       break;
1516*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1517*795d594fSAndroid Build Coastguard Worker       __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
1518*795d594fSAndroid Build Coastguard Worker       break;
1519*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1520*795d594fSAndroid Build Coastguard Worker       __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
1521*795d594fSAndroid Build Coastguard Worker       break;
1522*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1523*795d594fSAndroid Build Coastguard Worker       __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
1524*795d594fSAndroid Build Coastguard Worker       __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
1525*795d594fSAndroid Build Coastguard Worker       break;
1526*795d594fSAndroid Build Coastguard Worker     default:
1527*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Type not recognized for peek: " << size;
1528*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1529*795d594fSAndroid Build Coastguard Worker   }
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekByte(HInvoke * invoke)1532*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPeekByte(HInvoke* invoke) {
1533*795d594fSAndroid Build Coastguard Worker   CreateLongToIntLocations(allocator_, invoke);
1534*795d594fSAndroid Build Coastguard Worker }
1535*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekByte(HInvoke * invoke)1536*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
1537*795d594fSAndroid Build Coastguard Worker   GenPeek(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
1538*795d594fSAndroid Build Coastguard Worker }
1539*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekIntNative(HInvoke * invoke)1540*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
1541*795d594fSAndroid Build Coastguard Worker   CreateLongToIntLocations(allocator_, invoke);
1542*795d594fSAndroid Build Coastguard Worker }
1543*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekIntNative(HInvoke * invoke)1544*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
1545*795d594fSAndroid Build Coastguard Worker   GenPeek(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
1546*795d594fSAndroid Build Coastguard Worker }
1547*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekLongNative(HInvoke * invoke)1548*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
1549*795d594fSAndroid Build Coastguard Worker   CreateLongToLongLocations(allocator_, invoke);
1550*795d594fSAndroid Build Coastguard Worker }
1551*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekLongNative(HInvoke * invoke)1552*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
1553*795d594fSAndroid Build Coastguard Worker   GenPeek(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
1554*795d594fSAndroid Build Coastguard Worker }
1555*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekShortNative(HInvoke * invoke)1556*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
1557*795d594fSAndroid Build Coastguard Worker   CreateLongToIntLocations(allocator_, invoke);
1558*795d594fSAndroid Build Coastguard Worker }
1559*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPeekShortNative(HInvoke * invoke)1560*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
1561*795d594fSAndroid Build Coastguard Worker   GenPeek(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
1562*795d594fSAndroid Build Coastguard Worker }
1563*795d594fSAndroid Build Coastguard Worker 
CreateLongIntToVoidLocations(ArenaAllocator * allocator,DataType::Type size,HInvoke * invoke)1564*795d594fSAndroid Build Coastguard Worker static void CreateLongIntToVoidLocations(ArenaAllocator* allocator,
1565*795d594fSAndroid Build Coastguard Worker                                          DataType::Type size,
1566*795d594fSAndroid Build Coastguard Worker                                          HInvoke* invoke) {
1567*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1568*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1569*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
1570*795d594fSAndroid Build Coastguard Worker   HInstruction* value = invoke->InputAt(1);
1571*795d594fSAndroid Build Coastguard Worker   if (size == DataType::Type::kInt8) {
1572*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
1573*795d594fSAndroid Build Coastguard Worker   } else {
1574*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RegisterOrConstant(value));
1575*795d594fSAndroid Build Coastguard Worker   }
1576*795d594fSAndroid Build Coastguard Worker }
1577*795d594fSAndroid Build Coastguard Worker 
GenPoke(LocationSummary * locations,DataType::Type size,X86Assembler * assembler)1578*795d594fSAndroid Build Coastguard Worker static void GenPoke(LocationSummary* locations, DataType::Type size, X86Assembler* assembler) {
1579*795d594fSAndroid Build Coastguard Worker   Register address = locations->InAt(0).AsRegisterPairLow<Register>();
1580*795d594fSAndroid Build Coastguard Worker   Location value_loc = locations->InAt(1);
1581*795d594fSAndroid Build Coastguard Worker   // x86 allows unaligned access. We do not have to check the input or use specific instructions
1582*795d594fSAndroid Build Coastguard Worker   // to avoid a SIGBUS.
1583*795d594fSAndroid Build Coastguard Worker   switch (size) {
1584*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1585*795d594fSAndroid Build Coastguard Worker       if (value_loc.IsConstant()) {
1586*795d594fSAndroid Build Coastguard Worker         __ movb(Address(address, 0),
1587*795d594fSAndroid Build Coastguard Worker                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1588*795d594fSAndroid Build Coastguard Worker       } else {
1589*795d594fSAndroid Build Coastguard Worker         __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
1590*795d594fSAndroid Build Coastguard Worker       }
1591*795d594fSAndroid Build Coastguard Worker       break;
1592*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1593*795d594fSAndroid Build Coastguard Worker       if (value_loc.IsConstant()) {
1594*795d594fSAndroid Build Coastguard Worker         __ movw(Address(address, 0),
1595*795d594fSAndroid Build Coastguard Worker                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1596*795d594fSAndroid Build Coastguard Worker       } else {
1597*795d594fSAndroid Build Coastguard Worker         __ movw(Address(address, 0), value_loc.AsRegister<Register>());
1598*795d594fSAndroid Build Coastguard Worker       }
1599*795d594fSAndroid Build Coastguard Worker       break;
1600*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1601*795d594fSAndroid Build Coastguard Worker       if (value_loc.IsConstant()) {
1602*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 0),
1603*795d594fSAndroid Build Coastguard Worker                 Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
1604*795d594fSAndroid Build Coastguard Worker       } else {
1605*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 0), value_loc.AsRegister<Register>());
1606*795d594fSAndroid Build Coastguard Worker       }
1607*795d594fSAndroid Build Coastguard Worker       break;
1608*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1609*795d594fSAndroid Build Coastguard Worker       if (value_loc.IsConstant()) {
1610*795d594fSAndroid Build Coastguard Worker         int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
1611*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 0), Immediate(Low32Bits(value)));
1612*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 4), Immediate(High32Bits(value)));
1613*795d594fSAndroid Build Coastguard Worker       } else {
1614*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 0), value_loc.AsRegisterPairLow<Register>());
1615*795d594fSAndroid Build Coastguard Worker         __ movl(Address(address, 4), value_loc.AsRegisterPairHigh<Register>());
1616*795d594fSAndroid Build Coastguard Worker       }
1617*795d594fSAndroid Build Coastguard Worker       break;
1618*795d594fSAndroid Build Coastguard Worker     default:
1619*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Type not recognized for poke: " << size;
1620*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1621*795d594fSAndroid Build Coastguard Worker   }
1622*795d594fSAndroid Build Coastguard Worker }
1623*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeByte(HInvoke * invoke)1624*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
1625*795d594fSAndroid Build Coastguard Worker   CreateLongIntToVoidLocations(allocator_, DataType::Type::kInt8, invoke);
1626*795d594fSAndroid Build Coastguard Worker }
1627*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeByte(HInvoke * invoke)1628*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
1629*795d594fSAndroid Build Coastguard Worker   GenPoke(invoke->GetLocations(), DataType::Type::kInt8, GetAssembler());
1630*795d594fSAndroid Build Coastguard Worker }
1631*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeIntNative(HInvoke * invoke)1632*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
1633*795d594fSAndroid Build Coastguard Worker   CreateLongIntToVoidLocations(allocator_, DataType::Type::kInt32, invoke);
1634*795d594fSAndroid Build Coastguard Worker }
1635*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeIntNative(HInvoke * invoke)1636*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
1637*795d594fSAndroid Build Coastguard Worker   GenPoke(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
1638*795d594fSAndroid Build Coastguard Worker }
1639*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeLongNative(HInvoke * invoke)1640*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
1641*795d594fSAndroid Build Coastguard Worker   CreateLongIntToVoidLocations(allocator_, DataType::Type::kInt64, invoke);
1642*795d594fSAndroid Build Coastguard Worker }
1643*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeLongNative(HInvoke * invoke)1644*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
1645*795d594fSAndroid Build Coastguard Worker   GenPoke(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
1646*795d594fSAndroid Build Coastguard Worker }
1647*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeShortNative(HInvoke * invoke)1648*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
1649*795d594fSAndroid Build Coastguard Worker   CreateLongIntToVoidLocations(allocator_, DataType::Type::kInt16, invoke);
1650*795d594fSAndroid Build Coastguard Worker }
1651*795d594fSAndroid Build Coastguard Worker 
VisitMemoryPokeShortNative(HInvoke * invoke)1652*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
1653*795d594fSAndroid Build Coastguard Worker   GenPoke(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
1654*795d594fSAndroid Build Coastguard Worker }
1655*795d594fSAndroid Build Coastguard Worker 
VisitThreadCurrentThread(HInvoke * invoke)1656*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
1657*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1658*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1659*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
1660*795d594fSAndroid Build Coastguard Worker }
1661*795d594fSAndroid Build Coastguard Worker 
VisitThreadCurrentThread(HInvoke * invoke)1662*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitThreadCurrentThread(HInvoke* invoke) {
1663*795d594fSAndroid Build Coastguard Worker   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1664*795d594fSAndroid Build Coastguard Worker   GetAssembler()->fs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86PointerSize>()));
1665*795d594fSAndroid Build Coastguard Worker }
1666*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGet(HInvoke * invoke,DataType::Type type,bool is_volatile,CodeGeneratorX86 * codegen)1667*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGet(HInvoke* invoke,
1668*795d594fSAndroid Build Coastguard Worker                          DataType::Type type,
1669*795d594fSAndroid Build Coastguard Worker                          bool is_volatile,
1670*795d594fSAndroid Build Coastguard Worker                          CodeGeneratorX86* codegen) {
1671*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
1672*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1673*795d594fSAndroid Build Coastguard Worker   Location base_loc = locations->InAt(1);
1674*795d594fSAndroid Build Coastguard Worker   Register base = base_loc.AsRegister<Register>();
1675*795d594fSAndroid Build Coastguard Worker   Location offset_loc = locations->InAt(2);
1676*795d594fSAndroid Build Coastguard Worker   Register offset = offset_loc.AsRegisterPairLow<Register>();
1677*795d594fSAndroid Build Coastguard Worker   Location output_loc = locations->Out();
1678*795d594fSAndroid Build Coastguard Worker 
1679*795d594fSAndroid Build Coastguard Worker   switch (type) {
1680*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8: {
1681*795d594fSAndroid Build Coastguard Worker       Register output = output_loc.AsRegister<Register>();
1682*795d594fSAndroid Build Coastguard Worker       __ movsxb(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1683*795d594fSAndroid Build Coastguard Worker       break;
1684*795d594fSAndroid Build Coastguard Worker     }
1685*795d594fSAndroid Build Coastguard Worker 
1686*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
1687*795d594fSAndroid Build Coastguard Worker       Register output = output_loc.AsRegister<Register>();
1688*795d594fSAndroid Build Coastguard Worker       __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1689*795d594fSAndroid Build Coastguard Worker       break;
1690*795d594fSAndroid Build Coastguard Worker     }
1691*795d594fSAndroid Build Coastguard Worker 
1692*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference: {
1693*795d594fSAndroid Build Coastguard Worker       Register output = output_loc.AsRegister<Register>();
1694*795d594fSAndroid Build Coastguard Worker       if (codegen->EmitReadBarrier()) {
1695*795d594fSAndroid Build Coastguard Worker         if (kUseBakerReadBarrier) {
1696*795d594fSAndroid Build Coastguard Worker           Address src(base, offset, ScaleFactor::TIMES_1, 0);
1697*795d594fSAndroid Build Coastguard Worker           codegen->GenerateReferenceLoadWithBakerReadBarrier(
1698*795d594fSAndroid Build Coastguard Worker               invoke, output_loc, base, src, /* needs_null_check= */ false);
1699*795d594fSAndroid Build Coastguard Worker         } else {
1700*795d594fSAndroid Build Coastguard Worker           __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1701*795d594fSAndroid Build Coastguard Worker           codegen->GenerateReadBarrierSlow(
1702*795d594fSAndroid Build Coastguard Worker               invoke, output_loc, output_loc, base_loc, 0U, offset_loc);
1703*795d594fSAndroid Build Coastguard Worker         }
1704*795d594fSAndroid Build Coastguard Worker       } else {
1705*795d594fSAndroid Build Coastguard Worker         __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
1706*795d594fSAndroid Build Coastguard Worker         __ MaybeUnpoisonHeapReference(output);
1707*795d594fSAndroid Build Coastguard Worker       }
1708*795d594fSAndroid Build Coastguard Worker       break;
1709*795d594fSAndroid Build Coastguard Worker     }
1710*795d594fSAndroid Build Coastguard Worker 
1711*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
1712*795d594fSAndroid Build Coastguard Worker         Register output_lo = output_loc.AsRegisterPairLow<Register>();
1713*795d594fSAndroid Build Coastguard Worker         Register output_hi = output_loc.AsRegisterPairHigh<Register>();
1714*795d594fSAndroid Build Coastguard Worker         if (is_volatile) {
1715*795d594fSAndroid Build Coastguard Worker           // Need to use a XMM to read atomically.
1716*795d594fSAndroid Build Coastguard Worker           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1717*795d594fSAndroid Build Coastguard Worker           __ movsd(temp, Address(base, offset, ScaleFactor::TIMES_1, 0));
1718*795d594fSAndroid Build Coastguard Worker           __ movd(output_lo, temp);
1719*795d594fSAndroid Build Coastguard Worker           __ psrlq(temp, Immediate(32));
1720*795d594fSAndroid Build Coastguard Worker           __ movd(output_hi, temp);
1721*795d594fSAndroid Build Coastguard Worker         } else {
1722*795d594fSAndroid Build Coastguard Worker           __ movl(output_lo, Address(base, offset, ScaleFactor::TIMES_1, 0));
1723*795d594fSAndroid Build Coastguard Worker           __ movl(output_hi, Address(base, offset, ScaleFactor::TIMES_1, 4));
1724*795d594fSAndroid Build Coastguard Worker         }
1725*795d594fSAndroid Build Coastguard Worker       }
1726*795d594fSAndroid Build Coastguard Worker       break;
1727*795d594fSAndroid Build Coastguard Worker 
1728*795d594fSAndroid Build Coastguard Worker     default:
1729*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unsupported op size " << type;
1730*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1731*795d594fSAndroid Build Coastguard Worker   }
1732*795d594fSAndroid Build Coastguard Worker }
1733*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGetAbsolute(HInvoke * invoke,DataType::Type type,bool is_volatile,CodeGeneratorX86 * codegen)1734*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAbsolute(HInvoke* invoke,
1735*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type,
1736*795d594fSAndroid Build Coastguard Worker                                  bool is_volatile,
1737*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorX86* codegen) {
1738*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
1739*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
1740*795d594fSAndroid Build Coastguard Worker   Register address = locations->InAt(1).AsRegisterPairLow<Register>();
1741*795d594fSAndroid Build Coastguard Worker   Address address_offset(address, 0);
1742*795d594fSAndroid Build Coastguard Worker   Location output_loc = locations->Out();
1743*795d594fSAndroid Build Coastguard Worker 
1744*795d594fSAndroid Build Coastguard Worker   switch (type) {
1745*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8: {
1746*795d594fSAndroid Build Coastguard Worker       Register output = output_loc.AsRegister<Register>();
1747*795d594fSAndroid Build Coastguard Worker       __ movsxb(output, address_offset);
1748*795d594fSAndroid Build Coastguard Worker       break;
1749*795d594fSAndroid Build Coastguard Worker     }
1750*795d594fSAndroid Build Coastguard Worker 
1751*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
1752*795d594fSAndroid Build Coastguard Worker       Register output = output_loc.AsRegister<Register>();
1753*795d594fSAndroid Build Coastguard Worker       __ movl(output, address_offset);
1754*795d594fSAndroid Build Coastguard Worker       break;
1755*795d594fSAndroid Build Coastguard Worker     }
1756*795d594fSAndroid Build Coastguard Worker 
1757*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
1758*795d594fSAndroid Build Coastguard Worker         Register output_lo = output_loc.AsRegisterPairLow<Register>();
1759*795d594fSAndroid Build Coastguard Worker         Register output_hi = output_loc.AsRegisterPairHigh<Register>();
1760*795d594fSAndroid Build Coastguard Worker         if (is_volatile) {
1761*795d594fSAndroid Build Coastguard Worker           // Need to use a XMM to read atomically.
1762*795d594fSAndroid Build Coastguard Worker           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1763*795d594fSAndroid Build Coastguard Worker           __ movsd(temp, address_offset);
1764*795d594fSAndroid Build Coastguard Worker           __ movd(output_lo, temp);
1765*795d594fSAndroid Build Coastguard Worker           __ psrlq(temp, Immediate(32));
1766*795d594fSAndroid Build Coastguard Worker           __ movd(output_hi, temp);
1767*795d594fSAndroid Build Coastguard Worker         } else {
1768*795d594fSAndroid Build Coastguard Worker           Address address_hi(address, 4);
1769*795d594fSAndroid Build Coastguard Worker           __ movl(output_lo, address_offset);
1770*795d594fSAndroid Build Coastguard Worker           __ movl(output_hi, address_hi);
1771*795d594fSAndroid Build Coastguard Worker         }
1772*795d594fSAndroid Build Coastguard Worker       }
1773*795d594fSAndroid Build Coastguard Worker       break;
1774*795d594fSAndroid Build Coastguard Worker 
1775*795d594fSAndroid Build Coastguard Worker     default:
1776*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unsupported op size " << type;
1777*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1778*795d594fSAndroid Build Coastguard Worker   }
1779*795d594fSAndroid Build Coastguard Worker }
1780*795d594fSAndroid Build Coastguard Worker 
CreateIntIntToIntLocations(ArenaAllocator * allocator,HInvoke * invoke,DataType::Type type,bool is_volatile)1781*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToIntLocations(ArenaAllocator* allocator,
1782*795d594fSAndroid Build Coastguard Worker                                        HInvoke* invoke,
1783*795d594fSAndroid Build Coastguard Worker                                        DataType::Type type,
1784*795d594fSAndroid Build Coastguard Worker                                        bool is_volatile) {
1785*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1786*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1787*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1788*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1789*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
1790*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
1791*795d594fSAndroid Build Coastguard Worker       // Need to use XMM to read volatile.
1792*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
1793*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1794*795d594fSAndroid Build Coastguard Worker     } else {
1795*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1796*795d594fSAndroid Build Coastguard Worker     }
1797*795d594fSAndroid Build Coastguard Worker   } else {
1798*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1799*795d594fSAndroid Build Coastguard Worker   }
1800*795d594fSAndroid Build Coastguard Worker }
1801*795d594fSAndroid Build Coastguard Worker 
CreateIntIntIntToIntLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorX86 * codegen,DataType::Type type,bool is_volatile)1802*795d594fSAndroid Build Coastguard Worker static void CreateIntIntIntToIntLocations(ArenaAllocator* allocator,
1803*795d594fSAndroid Build Coastguard Worker                                           HInvoke* invoke,
1804*795d594fSAndroid Build Coastguard Worker                                           CodeGeneratorX86* codegen,
1805*795d594fSAndroid Build Coastguard Worker                                           DataType::Type type,
1806*795d594fSAndroid Build Coastguard Worker                                           bool is_volatile) {
1807*795d594fSAndroid Build Coastguard Worker   bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetReference(invoke);
1808*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1809*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
1810*795d594fSAndroid Build Coastguard Worker                                       can_call
1811*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
1812*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
1813*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
1814*795d594fSAndroid Build Coastguard Worker   if (can_call && kUseBakerReadBarrier) {
1815*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
1816*795d594fSAndroid Build Coastguard Worker   }
1817*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1818*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1819*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
1820*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
1821*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
1822*795d594fSAndroid Build Coastguard Worker       // Need to use XMM to read volatile.
1823*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
1824*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1825*795d594fSAndroid Build Coastguard Worker     } else {
1826*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1827*795d594fSAndroid Build Coastguard Worker     }
1828*795d594fSAndroid Build Coastguard Worker   } else {
1829*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister(),
1830*795d594fSAndroid Build Coastguard Worker                       (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
1831*795d594fSAndroid Build Coastguard Worker   }
1832*795d594fSAndroid Build Coastguard Worker }
1833*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGet(HInvoke * invoke)1834*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
1835*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGet(invoke);
1836*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAbsolute(HInvoke * invoke)1837*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAbsolute(HInvoke* invoke) {
1838*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAbsolute(invoke);
1839*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetVolatile(HInvoke * invoke)1840*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1841*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetVolatile(invoke);
1842*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLong(HInvoke * invoke)1843*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
1844*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLong(invoke);
1845*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLongVolatile(HInvoke * invoke)1846*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1847*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLongVolatile(invoke);
1848*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObject(HInvoke * invoke)1849*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
1850*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReference(invoke);
1851*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1852*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1853*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReferenceVolatile(invoke);
1854*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetByte(HInvoke * invoke)1855*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetByte(HInvoke* invoke) {
1856*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetByte(invoke);
1857*795d594fSAndroid Build Coastguard Worker }
1858*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGet(HInvoke * invoke)1859*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
1860*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGet(invoke);
1861*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetAbsolute(HInvoke * invoke)1862*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAbsolute(HInvoke* invoke) {
1863*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAbsolute(invoke);
1864*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetVolatile(HInvoke * invoke)1865*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1866*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetVolatile(invoke);
1867*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLong(HInvoke * invoke)1868*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
1869*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLong(invoke);
1870*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetLongVolatile(HInvoke * invoke)1871*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1872*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetLongVolatile(invoke);
1873*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObject(HInvoke * invoke)1874*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
1875*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReference(invoke);
1876*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1877*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1878*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetReferenceVolatile(invoke);
1879*795d594fSAndroid Build Coastguard Worker }
VisitUnsafeGetByte(HInvoke * invoke)1880*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetByte(HInvoke* invoke) {
1881*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetByte(invoke);
1882*795d594fSAndroid Build Coastguard Worker }
1883*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGet(HInvoke * invoke)1884*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGet(HInvoke* invoke) {
1885*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1886*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt32, /*is_volatile=*/ false);
1887*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)1888*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
1889*795d594fSAndroid Build Coastguard Worker   CreateIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32, /*is_volatile=*/false);
1890*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetVolatile(HInvoke * invoke)1891*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
1892*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1893*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt32, /*is_volatile=*/ true);
1894*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAcquire(HInvoke * invoke)1895*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
1896*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1897*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt32, /*is_volatile=*/ true);
1898*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLong(HInvoke * invoke)1899*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetLong(HInvoke* invoke) {
1900*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1901*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt64, /*is_volatile=*/ false);
1902*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)1903*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
1904*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1905*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt64, /*is_volatile=*/ true);
1906*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)1907*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
1908*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1909*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt64, /*is_volatile=*/ true);
1910*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReference(HInvoke * invoke)1911*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetReference(HInvoke* invoke) {
1912*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1913*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kReference, /*is_volatile=*/ false);
1914*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)1915*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
1916*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1917*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kReference, /*is_volatile=*/ true);
1918*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)1919*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
1920*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1921*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kReference, /*is_volatile=*/ true);
1922*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetByte(HInvoke * invoke)1923*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetByte(HInvoke* invoke) {
1924*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToIntLocations(
1925*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt8, /*is_volatile=*/ false);
1926*795d594fSAndroid Build Coastguard Worker }
1927*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGet(HInvoke * invoke)1928*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGet(HInvoke* invoke) {
1929*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
1930*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)1931*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
1932*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAbsolute(invoke, DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
1933*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetVolatile(HInvoke * invoke)1934*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
1935*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
1936*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetAcquire(HInvoke * invoke)1937*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
1938*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
1939*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLong(HInvoke * invoke)1940*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetLong(HInvoke* invoke) {
1941*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ false, codegen_);
1942*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)1943*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
1944*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
1945*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)1946*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
1947*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
1948*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReference(HInvoke * invoke)1949*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetReference(HInvoke* invoke) {
1950*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ false, codegen_);
1951*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)1952*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
1953*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
1954*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)1955*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
1956*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
1957*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafeGetByte(HInvoke * invoke)1958*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetByte(HInvoke* invoke) {
1959*795d594fSAndroid Build Coastguard Worker   GenUnsafeGet(invoke, DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
1960*795d594fSAndroid Build Coastguard Worker }
1961*795d594fSAndroid Build Coastguard Worker 
CreateIntIntIntToVoidPlusTempsLocations(ArenaAllocator * allocator,DataType::Type type,HInvoke * invoke,bool is_volatile)1962*795d594fSAndroid Build Coastguard Worker static void CreateIntIntIntToVoidPlusTempsLocations(ArenaAllocator* allocator,
1963*795d594fSAndroid Build Coastguard Worker                                                     DataType::Type type,
1964*795d594fSAndroid Build Coastguard Worker                                                     HInvoke* invoke,
1965*795d594fSAndroid Build Coastguard Worker                                                     bool is_volatile) {
1966*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1967*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1968*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1969*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1970*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt8 || type == DataType::Type::kUint8) {
1971*795d594fSAndroid Build Coastguard Worker     // Ensure the value is in a byte register
1972*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, invoke->InputAt(3)));
1973*795d594fSAndroid Build Coastguard Worker   } else {
1974*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::RequiresRegister());
1975*795d594fSAndroid Build Coastguard Worker   }
1976*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64 && is_volatile) {
1977*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
1978*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
1979*795d594fSAndroid Build Coastguard Worker   }
1980*795d594fSAndroid Build Coastguard Worker }
1981*795d594fSAndroid Build Coastguard Worker 
CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator * allocator,DataType::Type type,HInvoke * invoke,bool is_volatile)1982*795d594fSAndroid Build Coastguard Worker static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* allocator,
1983*795d594fSAndroid Build Coastguard Worker                                                        DataType::Type type,
1984*795d594fSAndroid Build Coastguard Worker                                                        HInvoke* invoke,
1985*795d594fSAndroid Build Coastguard Worker                                                        bool is_volatile) {
1986*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
1987*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1988*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1989*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
1990*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
1991*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt8 || type == DataType::Type::kUint8) {
1992*795d594fSAndroid Build Coastguard Worker     // Ensure the value is in a byte register
1993*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::ByteRegisterOrConstant(EAX, invoke->InputAt(3)));
1994*795d594fSAndroid Build Coastguard Worker   } else {
1995*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::RequiresRegister());
1996*795d594fSAndroid Build Coastguard Worker   }
1997*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1998*795d594fSAndroid Build Coastguard Worker     // Need temp registers for card-marking.
1999*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
2000*795d594fSAndroid Build Coastguard Worker     // Ensure the value is in a byte register.
2001*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(ECX));
2002*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kInt64 && is_volatile) {
2003*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
2004*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
2005*795d594fSAndroid Build Coastguard Worker   }
2006*795d594fSAndroid Build Coastguard Worker }
2007*795d594fSAndroid Build Coastguard Worker 
VisitUnsafePut(HInvoke * invoke)2008*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
2009*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePut(invoke);
2010*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutAbsolute(HInvoke * invoke)2011*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutAbsolute(HInvoke* invoke) {
2012*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutAbsolute(invoke);
2013*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutOrdered(HInvoke * invoke)2014*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
2015*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutOrdered(invoke);
2016*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutVolatile(HInvoke * invoke)2017*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
2018*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutVolatile(invoke);
2019*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObject(HInvoke * invoke)2020*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
2021*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReference(invoke);
2022*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectOrdered(HInvoke * invoke)2023*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2024*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutObjectOrdered(invoke);
2025*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectVolatile(HInvoke * invoke)2026*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2027*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReferenceVolatile(invoke);
2028*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLong(HInvoke * invoke)2029*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
2030*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLong(invoke);
2031*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongOrdered(HInvoke * invoke)2032*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2033*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongOrdered(invoke);
2034*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongVolatile(HInvoke * invoke)2035*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2036*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongVolatile(invoke);
2037*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutByte(HInvoke * invoke)2038*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafePutByte(HInvoke* invoke) {
2039*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutByte(invoke);
2040*795d594fSAndroid Build Coastguard Worker }
2041*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafePut(HInvoke * invoke)2042*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePut(HInvoke* invoke) {
2043*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2044*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt32, invoke, /*is_volatile=*/ false);
2045*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutAbsolute(HInvoke * invoke)2046*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
2047*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntToVoidPlusTempsLocations(
2048*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ false);
2049*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutOrdered(HInvoke * invoke)2050*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
2051*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2052*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt32, invoke, /*is_volatile=*/ false);
2053*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutVolatile(HInvoke * invoke)2054*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
2055*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2056*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt32, invoke, /*is_volatile=*/ true);
2057*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutRelease(HInvoke * invoke)2058*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutRelease(HInvoke* invoke) {
2059*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2060*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt32, invoke, /*is_volatile=*/ true);
2061*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReference(HInvoke * invoke)2062*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutReference(HInvoke* invoke) {
2063*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2064*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kReference, invoke, /*is_volatile=*/ false);
2065*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)2066*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
2067*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2068*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kReference, invoke, /*is_volatile=*/ false);
2069*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)2070*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
2071*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2072*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kReference, invoke, /*is_volatile=*/ true);
2073*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)2074*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
2075*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2076*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kReference, invoke, /*is_volatile=*/ true);
2077*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLong(HInvoke * invoke)2078*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutLong(HInvoke* invoke) {
2079*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2080*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ false);
2081*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)2082*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
2083*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2084*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ false);
2085*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)2086*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
2087*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2088*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ true);
2089*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongRelease(HInvoke * invoke)2090*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
2091*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2092*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt64, invoke, /*is_volatile=*/ true);
2093*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutByte(HInvoke * invoke)2094*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafePutByte(HInvoke* invoke) {
2095*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntToVoidPlusTempsLocations(
2096*795d594fSAndroid Build Coastguard Worker       allocator_, DataType::Type::kInt8, invoke, /*is_volatile=*/ false);
2097*795d594fSAndroid Build Coastguard Worker }
2098*795d594fSAndroid Build Coastguard Worker 
2099*795d594fSAndroid Build Coastguard Worker // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
2100*795d594fSAndroid Build Coastguard Worker // memory model.
GenUnsafePut(LocationSummary * locations,DataType::Type type,bool is_volatile,CodeGeneratorX86 * codegen)2101*795d594fSAndroid Build Coastguard Worker static void GenUnsafePut(LocationSummary* locations,
2102*795d594fSAndroid Build Coastguard Worker                          DataType::Type type,
2103*795d594fSAndroid Build Coastguard Worker                          bool is_volatile,
2104*795d594fSAndroid Build Coastguard Worker                          CodeGeneratorX86* codegen) {
2105*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2106*795d594fSAndroid Build Coastguard Worker   Register base = locations->InAt(1).AsRegister<Register>();
2107*795d594fSAndroid Build Coastguard Worker   Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
2108*795d594fSAndroid Build Coastguard Worker   Location value_loc = locations->InAt(3);
2109*795d594fSAndroid Build Coastguard Worker 
2110*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
2111*795d594fSAndroid Build Coastguard Worker     Register value_lo = value_loc.AsRegisterPairLow<Register>();
2112*795d594fSAndroid Build Coastguard Worker     Register value_hi = value_loc.AsRegisterPairHigh<Register>();
2113*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
2114*795d594fSAndroid Build Coastguard Worker       XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2115*795d594fSAndroid Build Coastguard Worker       XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
2116*795d594fSAndroid Build Coastguard Worker       __ movd(temp1, value_lo);
2117*795d594fSAndroid Build Coastguard Worker       __ movd(temp2, value_hi);
2118*795d594fSAndroid Build Coastguard Worker       __ punpckldq(temp1, temp2);
2119*795d594fSAndroid Build Coastguard Worker       __ movsd(Address(base, offset, ScaleFactor::TIMES_1, 0), temp1);
2120*795d594fSAndroid Build Coastguard Worker     } else {
2121*795d594fSAndroid Build Coastguard Worker       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
2122*795d594fSAndroid Build Coastguard Worker       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
2123*795d594fSAndroid Build Coastguard Worker     }
2124*795d594fSAndroid Build Coastguard Worker   } else if (kPoisonHeapReferences && type == DataType::Type::kReference) {
2125*795d594fSAndroid Build Coastguard Worker     Register temp = locations->GetTemp(0).AsRegister<Register>();
2126*795d594fSAndroid Build Coastguard Worker     __ movl(temp, value_loc.AsRegister<Register>());
2127*795d594fSAndroid Build Coastguard Worker     __ PoisonHeapReference(temp);
2128*795d594fSAndroid Build Coastguard Worker     __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), temp);
2129*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kInt32 || type == DataType::Type::kReference) {
2130*795d594fSAndroid Build Coastguard Worker     __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
2131*795d594fSAndroid Build Coastguard Worker   } else {
2132*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(type, DataType::Type::kInt8) << "Unimplemented GenUnsafePut data type";
2133*795d594fSAndroid Build Coastguard Worker     if (value_loc.IsRegister()) {
2134*795d594fSAndroid Build Coastguard Worker       __ movb(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<ByteRegister>());
2135*795d594fSAndroid Build Coastguard Worker     } else {
2136*795d594fSAndroid Build Coastguard Worker       __ movb(Address(base, offset, ScaleFactor::TIMES_1, 0),
2137*795d594fSAndroid Build Coastguard Worker               Immediate(CodeGenerator::GetInt8ValueOf(value_loc.GetConstant())));
2138*795d594fSAndroid Build Coastguard Worker     }
2139*795d594fSAndroid Build Coastguard Worker   }
2140*795d594fSAndroid Build Coastguard Worker 
2141*795d594fSAndroid Build Coastguard Worker   if (is_volatile) {
2142*795d594fSAndroid Build Coastguard Worker     codegen->MemoryFence();
2143*795d594fSAndroid Build Coastguard Worker   }
2144*795d594fSAndroid Build Coastguard Worker 
2145*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
2146*795d594fSAndroid Build Coastguard Worker     bool value_can_be_null = true;  // TODO: Worth finding out this information?
2147*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
2148*795d594fSAndroid Build Coastguard Worker                              locations->GetTemp(1).AsRegister<Register>(),
2149*795d594fSAndroid Build Coastguard Worker                              base,
2150*795d594fSAndroid Build Coastguard Worker                              value_loc.AsRegister<Register>(),
2151*795d594fSAndroid Build Coastguard Worker                              value_can_be_null);
2152*795d594fSAndroid Build Coastguard Worker   }
2153*795d594fSAndroid Build Coastguard Worker }
2154*795d594fSAndroid Build Coastguard Worker 
2155*795d594fSAndroid Build Coastguard Worker // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
2156*795d594fSAndroid Build Coastguard Worker // memory model.
GenUnsafePutAbsolute(LocationSummary * locations,DataType::Type type,bool is_volatile,CodeGeneratorX86 * codegen)2157*795d594fSAndroid Build Coastguard Worker static void GenUnsafePutAbsolute(LocationSummary* locations,
2158*795d594fSAndroid Build Coastguard Worker                                  DataType::Type type,
2159*795d594fSAndroid Build Coastguard Worker                                  bool is_volatile,
2160*795d594fSAndroid Build Coastguard Worker                                  CodeGeneratorX86* codegen) {
2161*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2162*795d594fSAndroid Build Coastguard Worker   Register address = locations->InAt(1).AsRegisterPairLow<Register>();
2163*795d594fSAndroid Build Coastguard Worker   Address address_offset(address, 0);
2164*795d594fSAndroid Build Coastguard Worker   Location value_loc = locations->InAt(2);
2165*795d594fSAndroid Build Coastguard Worker 
2166*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
2167*795d594fSAndroid Build Coastguard Worker     Register value_lo = value_loc.AsRegisterPairLow<Register>();
2168*795d594fSAndroid Build Coastguard Worker     Register value_hi = value_loc.AsRegisterPairHigh<Register>();
2169*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
2170*795d594fSAndroid Build Coastguard Worker       XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2171*795d594fSAndroid Build Coastguard Worker       XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
2172*795d594fSAndroid Build Coastguard Worker       __ movd(temp1, value_lo);
2173*795d594fSAndroid Build Coastguard Worker       __ movd(temp2, value_hi);
2174*795d594fSAndroid Build Coastguard Worker       __ punpckldq(temp1, temp2);
2175*795d594fSAndroid Build Coastguard Worker       __ movsd(address_offset, temp1);
2176*795d594fSAndroid Build Coastguard Worker     } else {
2177*795d594fSAndroid Build Coastguard Worker       __ movl(address_offset, value_lo);
2178*795d594fSAndroid Build Coastguard Worker       __ movl(Address(address, 4), value_hi);
2179*795d594fSAndroid Build Coastguard Worker     }
2180*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kInt32) {
2181*795d594fSAndroid Build Coastguard Worker     __ movl(address_offset, value_loc.AsRegister<Register>());
2182*795d594fSAndroid Build Coastguard Worker   } else {
2183*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(type, DataType::Type::kInt8) << "Unimplemented GenUnsafePut data type";
2184*795d594fSAndroid Build Coastguard Worker     if (value_loc.IsRegister()) {
2185*795d594fSAndroid Build Coastguard Worker       __ movb(address_offset, value_loc.AsRegister<ByteRegister>());
2186*795d594fSAndroid Build Coastguard Worker     } else {
2187*795d594fSAndroid Build Coastguard Worker       __ movb(address_offset,
2188*795d594fSAndroid Build Coastguard Worker               Immediate(CodeGenerator::GetInt8ValueOf(value_loc.GetConstant())));
2189*795d594fSAndroid Build Coastguard Worker     }
2190*795d594fSAndroid Build Coastguard Worker   }
2191*795d594fSAndroid Build Coastguard Worker 
2192*795d594fSAndroid Build Coastguard Worker   if (is_volatile) {
2193*795d594fSAndroid Build Coastguard Worker     codegen->MemoryFence();
2194*795d594fSAndroid Build Coastguard Worker   }
2195*795d594fSAndroid Build Coastguard Worker }
2196*795d594fSAndroid Build Coastguard Worker 
VisitUnsafePut(HInvoke * invoke)2197*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
2198*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePut(invoke);
2199*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutAbsolute(HInvoke * invoke)2200*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutAbsolute(HInvoke* invoke) {
2201*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutAbsolute(invoke);
2202*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutOrdered(HInvoke * invoke)2203*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
2204*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutOrdered(invoke);
2205*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutVolatile(HInvoke * invoke)2206*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
2207*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutVolatile(invoke);
2208*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObject(HInvoke * invoke)2209*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
2210*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReference(invoke);
2211*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectOrdered(HInvoke * invoke)2212*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2213*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutObjectOrdered(invoke);
2214*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutObjectVolatile(HInvoke * invoke)2215*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2216*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutReferenceVolatile(invoke);
2217*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLong(HInvoke * invoke)2218*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
2219*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLong(invoke);
2220*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongOrdered(HInvoke * invoke)2221*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2222*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongOrdered(invoke);
2223*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutLongVolatile(HInvoke * invoke)2224*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2225*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutLongVolatile(invoke);
2226*795d594fSAndroid Build Coastguard Worker }
VisitUnsafePutByte(HInvoke * invoke)2227*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafePutByte(HInvoke* invoke) {
2228*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafePutByte(invoke);
2229*795d594fSAndroid Build Coastguard Worker }
2230*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafePut(HInvoke * invoke)2231*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePut(HInvoke* invoke) {
2232*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
2233*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutAbsolute(HInvoke * invoke)2234*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
2235*795d594fSAndroid Build Coastguard Worker   GenUnsafePutAbsolute(
2236*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/false, codegen_);
2237*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutOrdered(HInvoke * invoke)2238*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
2239*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ false, codegen_);
2240*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutVolatile(HInvoke * invoke)2241*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
2242*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
2243*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutRelease(HInvoke * invoke)2244*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutRelease(HInvoke* invoke) {
2245*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt32, /*is_volatile=*/ true, codegen_);
2246*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReference(HInvoke * invoke)2247*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutReference(HInvoke* invoke) {
2248*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(
2249*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations(), DataType::Type::kReference, /*is_volatile=*/ false, codegen_);
2250*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)2251*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
2252*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(
2253*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations(), DataType::Type::kReference, /*is_volatile=*/ false, codegen_);
2254*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)2255*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
2256*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(
2257*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations(), DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
2258*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)2259*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
2260*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(
2261*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations(), DataType::Type::kReference, /*is_volatile=*/ true, codegen_);
2262*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLong(HInvoke * invoke)2263*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutLong(HInvoke* invoke) {
2264*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ false, codegen_);
2265*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)2266*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
2267*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ false, codegen_);
2268*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)2269*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
2270*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
2271*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutLongRelease(HInvoke * invoke)2272*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
2273*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt64, /*is_volatile=*/ true, codegen_);
2274*795d594fSAndroid Build Coastguard Worker }
VisitJdkUnsafePutByte(HInvoke * invoke)2275*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafePutByte(HInvoke* invoke) {
2276*795d594fSAndroid Build Coastguard Worker   GenUnsafePut(invoke->GetLocations(), DataType::Type::kInt8, /*is_volatile=*/ false, codegen_);
2277*795d594fSAndroid Build Coastguard Worker }
2278*795d594fSAndroid Build Coastguard Worker 
CreateIntIntIntIntIntToInt(ArenaAllocator * allocator,CodeGeneratorX86 * codegen,DataType::Type type,HInvoke * invoke)2279*795d594fSAndroid Build Coastguard Worker static void CreateIntIntIntIntIntToInt(ArenaAllocator* allocator,
2280*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorX86* codegen,
2281*795d594fSAndroid Build Coastguard Worker                                        DataType::Type type,
2282*795d594fSAndroid Build Coastguard Worker                                        HInvoke* invoke) {
2283*795d594fSAndroid Build Coastguard Worker   const bool can_call = codegen->EmitBakerReadBarrier() && IsUnsafeCASReference(invoke);
2284*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2285*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
2286*795d594fSAndroid Build Coastguard Worker                                       can_call
2287*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
2288*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
2289*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
2290*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
2291*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
2292*795d594fSAndroid Build Coastguard Worker   // Offset is a long, but in 32 bit mode, we only need the low word.
2293*795d594fSAndroid Build Coastguard Worker   // Can we update the invoke here to remove a TypeConvert to Long?
2294*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(2, Location::RequiresRegister());
2295*795d594fSAndroid Build Coastguard Worker   // Expected value must be in EAX or EDX:EAX.
2296*795d594fSAndroid Build Coastguard Worker   // For long, new value must be in ECX:EBX.
2297*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
2298*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::RegisterPairLocation(EAX, EDX));
2299*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(4, Location::RegisterPairLocation(EBX, ECX));
2300*795d594fSAndroid Build Coastguard Worker   } else {
2301*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::RegisterLocation(EAX));
2302*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(4, Location::RequiresRegister());
2303*795d594fSAndroid Build Coastguard Worker   }
2304*795d594fSAndroid Build Coastguard Worker 
2305*795d594fSAndroid Build Coastguard Worker   // Force a byte register for the output.
2306*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
2307*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
2308*795d594fSAndroid Build Coastguard Worker     // Need temporary registers for card-marking, and possibly for
2309*795d594fSAndroid Build Coastguard Worker     // (Baker) read barrier.
2310*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
2311*795d594fSAndroid Build Coastguard Worker     // Need a byte register for marking.
2312*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(ECX));
2313*795d594fSAndroid Build Coastguard Worker   }
2314*795d594fSAndroid Build Coastguard Worker }
2315*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASInt(HInvoke * invoke)2316*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeCASInt(HInvoke* invoke) {
2317*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASInt(invoke);
2318*795d594fSAndroid Build Coastguard Worker }
2319*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASLong(HInvoke * invoke)2320*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeCASLong(HInvoke* invoke) {
2321*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASLong(invoke);
2322*795d594fSAndroid Build Coastguard Worker }
2323*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASObject(HInvoke * invoke)2324*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
2325*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASObject(invoke);
2326*795d594fSAndroid Build Coastguard Worker }
2327*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASInt(HInvoke * invoke)2328*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCASInt(HInvoke* invoke) {
2329*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
2330*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetInt(invoke);
2331*795d594fSAndroid Build Coastguard Worker }
2332*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASLong(HInvoke * invoke)2333*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCASLong(HInvoke* invoke) {
2334*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
2335*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetLong(invoke);
2336*795d594fSAndroid Build Coastguard Worker }
2337*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASObject(HInvoke * invoke)2338*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCASObject(HInvoke* invoke) {
2339*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
2340*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetReference(invoke);
2341*795d594fSAndroid Build Coastguard Worker }
2342*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)2343*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
2344*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntIntToInt(allocator_, codegen_, DataType::Type::kInt32, invoke);
2345*795d594fSAndroid Build Coastguard Worker }
2346*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)2347*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
2348*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntIntToInt(allocator_, codegen_, DataType::Type::kInt64, invoke);
2349*795d594fSAndroid Build Coastguard Worker }
2350*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)2351*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
2352*795d594fSAndroid Build Coastguard Worker   // The only supported read barrier implementation is the Baker-style read barriers.
2353*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitNonBakerReadBarrier()) {
2354*795d594fSAndroid Build Coastguard Worker     return;
2355*795d594fSAndroid Build Coastguard Worker   }
2356*795d594fSAndroid Build Coastguard Worker 
2357*795d594fSAndroid Build Coastguard Worker   CreateIntIntIntIntIntToInt(allocator_, codegen_, DataType::Type::kReference, invoke);
2358*795d594fSAndroid Build Coastguard Worker }
2359*795d594fSAndroid Build Coastguard Worker 
GenPrimitiveLockedCmpxchg(DataType::Type type,CodeGeneratorX86 * codegen,Location expected_value,Location new_value,Register base,Register offset,Register temp=Register::kNoRegister)2360*795d594fSAndroid Build Coastguard Worker static void GenPrimitiveLockedCmpxchg(DataType::Type type,
2361*795d594fSAndroid Build Coastguard Worker                                       CodeGeneratorX86* codegen,
2362*795d594fSAndroid Build Coastguard Worker                                       Location expected_value,
2363*795d594fSAndroid Build Coastguard Worker                                       Location new_value,
2364*795d594fSAndroid Build Coastguard Worker                                       Register base,
2365*795d594fSAndroid Build Coastguard Worker                                       Register offset,
2366*795d594fSAndroid Build Coastguard Worker                                       // Only necessary for floating point
2367*795d594fSAndroid Build Coastguard Worker                                       Register temp = Register::kNoRegister) {
2368*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2369*795d594fSAndroid Build Coastguard Worker 
2370*795d594fSAndroid Build Coastguard Worker   if (DataType::Kind(type) == DataType::Type::kInt32) {
2371*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(expected_value.AsRegister<Register>(), EAX);
2372*795d594fSAndroid Build Coastguard Worker   }
2373*795d594fSAndroid Build Coastguard Worker 
2374*795d594fSAndroid Build Coastguard Worker   // The address of the field within the holding object.
2375*795d594fSAndroid Build Coastguard Worker   Address field_addr(base, offset, TIMES_1, 0);
2376*795d594fSAndroid Build Coastguard Worker 
2377*795d594fSAndroid Build Coastguard Worker   switch (type) {
2378*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
2379*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
2380*795d594fSAndroid Build Coastguard Worker       __ LockCmpxchgb(field_addr, new_value.AsRegister<ByteRegister>());
2381*795d594fSAndroid Build Coastguard Worker       break;
2382*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
2383*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
2384*795d594fSAndroid Build Coastguard Worker       __ LockCmpxchgw(field_addr, new_value.AsRegister<Register>());
2385*795d594fSAndroid Build Coastguard Worker       break;
2386*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
2387*795d594fSAndroid Build Coastguard Worker       __ LockCmpxchgl(field_addr, new_value.AsRegister<Register>());
2388*795d594fSAndroid Build Coastguard Worker       break;
2389*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
2390*795d594fSAndroid Build Coastguard Worker       // cmpxchg requires the expected value to be in EAX so the new value must be elsewhere.
2391*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(temp, EAX);
2392*795d594fSAndroid Build Coastguard Worker       // EAX is both an input and an output for cmpxchg
2393*795d594fSAndroid Build Coastguard Worker       codegen->Move32(Location::RegisterLocation(EAX), expected_value);
2394*795d594fSAndroid Build Coastguard Worker       codegen->Move32(Location::RegisterLocation(temp), new_value);
2395*795d594fSAndroid Build Coastguard Worker       __ LockCmpxchgl(field_addr, temp);
2396*795d594fSAndroid Build Coastguard Worker       break;
2397*795d594fSAndroid Build Coastguard Worker     }
2398*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
2399*795d594fSAndroid Build Coastguard Worker       // Ensure the expected value is in EAX:EDX and that the new
2400*795d594fSAndroid Build Coastguard Worker       // value is in EBX:ECX (required by the CMPXCHG8B instruction).
2401*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(expected_value.AsRegisterPairLow<Register>(), EAX);
2402*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(expected_value.AsRegisterPairHigh<Register>(), EDX);
2403*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(new_value.AsRegisterPairLow<Register>(), EBX);
2404*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(new_value.AsRegisterPairHigh<Register>(), ECX);
2405*795d594fSAndroid Build Coastguard Worker       __ LockCmpxchg8b(field_addr);
2406*795d594fSAndroid Build Coastguard Worker       break;
2407*795d594fSAndroid Build Coastguard Worker     default:
2408*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected CAS type " << type;
2409*795d594fSAndroid Build Coastguard Worker   }
2410*795d594fSAndroid Build Coastguard Worker   // LOCK CMPXCHG/LOCK CMPXCHG8B have full barrier semantics, and we
2411*795d594fSAndroid Build Coastguard Worker   // don't need scheduling barriers at this time.
2412*795d594fSAndroid Build Coastguard Worker }
2413*795d594fSAndroid Build Coastguard Worker 
GenPrimitiveCAS(DataType::Type type,CodeGeneratorX86 * codegen,Location expected_value,Location new_value,Register base,Register offset,Location out,Register temp=Register::kNoRegister,bool is_cmpxchg=false)2414*795d594fSAndroid Build Coastguard Worker static void GenPrimitiveCAS(DataType::Type type,
2415*795d594fSAndroid Build Coastguard Worker                             CodeGeneratorX86* codegen,
2416*795d594fSAndroid Build Coastguard Worker                             Location expected_value,
2417*795d594fSAndroid Build Coastguard Worker                             Location new_value,
2418*795d594fSAndroid Build Coastguard Worker                             Register base,
2419*795d594fSAndroid Build Coastguard Worker                             Register offset,
2420*795d594fSAndroid Build Coastguard Worker                             Location out,
2421*795d594fSAndroid Build Coastguard Worker                             // Only necessary for floating point
2422*795d594fSAndroid Build Coastguard Worker                             Register temp = Register::kNoRegister,
2423*795d594fSAndroid Build Coastguard Worker                             bool is_cmpxchg = false) {
2424*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2425*795d594fSAndroid Build Coastguard Worker 
2426*795d594fSAndroid Build Coastguard Worker   if (!is_cmpxchg || DataType::Kind(type) == DataType::Type::kInt32) {
2427*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(out.AsRegister<Register>(), EAX);
2428*795d594fSAndroid Build Coastguard Worker   }
2429*795d594fSAndroid Build Coastguard Worker 
2430*795d594fSAndroid Build Coastguard Worker   GenPrimitiveLockedCmpxchg(type, codegen, expected_value, new_value, base, offset, temp);
2431*795d594fSAndroid Build Coastguard Worker 
2432*795d594fSAndroid Build Coastguard Worker   if (is_cmpxchg) {
2433*795d594fSAndroid Build Coastguard Worker     // Sign-extend, zero-extend or move the result if necessary
2434*795d594fSAndroid Build Coastguard Worker     switch (type) {
2435*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kBool:
2436*795d594fSAndroid Build Coastguard Worker         __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
2437*795d594fSAndroid Build Coastguard Worker         break;
2438*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt8:
2439*795d594fSAndroid Build Coastguard Worker         __ movsxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
2440*795d594fSAndroid Build Coastguard Worker         break;
2441*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt16:
2442*795d594fSAndroid Build Coastguard Worker         __ movsxw(out.AsRegister<Register>(), out.AsRegister<Register>());
2443*795d594fSAndroid Build Coastguard Worker         break;
2444*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kUint16:
2445*795d594fSAndroid Build Coastguard Worker         __ movzxw(out.AsRegister<Register>(), out.AsRegister<Register>());
2446*795d594fSAndroid Build Coastguard Worker         break;
2447*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kFloat32:
2448*795d594fSAndroid Build Coastguard Worker         __ movd(out.AsFpuRegister<XmmRegister>(), EAX);
2449*795d594fSAndroid Build Coastguard Worker         break;
2450*795d594fSAndroid Build Coastguard Worker       default:
2451*795d594fSAndroid Build Coastguard Worker         // Nothing to do
2452*795d594fSAndroid Build Coastguard Worker         break;
2453*795d594fSAndroid Build Coastguard Worker     }
2454*795d594fSAndroid Build Coastguard Worker   } else {
2455*795d594fSAndroid Build Coastguard Worker     // Convert ZF into the Boolean result.
2456*795d594fSAndroid Build Coastguard Worker     __ setb(kZero, out.AsRegister<Register>());
2457*795d594fSAndroid Build Coastguard Worker     __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
2458*795d594fSAndroid Build Coastguard Worker   }
2459*795d594fSAndroid Build Coastguard Worker }
2460*795d594fSAndroid Build Coastguard Worker 
GenReferenceCAS(HInvoke * invoke,CodeGeneratorX86 * codegen,Location expected_value,Location new_value,Register base,Register offset,Register temp,Register temp2,bool is_cmpxchg=false)2461*795d594fSAndroid Build Coastguard Worker static void GenReferenceCAS(HInvoke* invoke,
2462*795d594fSAndroid Build Coastguard Worker                             CodeGeneratorX86* codegen,
2463*795d594fSAndroid Build Coastguard Worker                             Location expected_value,
2464*795d594fSAndroid Build Coastguard Worker                             Location new_value,
2465*795d594fSAndroid Build Coastguard Worker                             Register base,
2466*795d594fSAndroid Build Coastguard Worker                             Register offset,
2467*795d594fSAndroid Build Coastguard Worker                             Register temp,
2468*795d594fSAndroid Build Coastguard Worker                             Register temp2,
2469*795d594fSAndroid Build Coastguard Worker                             bool is_cmpxchg = false) {
2470*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2471*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2472*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
2473*795d594fSAndroid Build Coastguard Worker 
2474*795d594fSAndroid Build Coastguard Worker   // The address of the field within the holding object.
2475*795d594fSAndroid Build Coastguard Worker   Address field_addr(base, offset, TIMES_1, 0);
2476*795d594fSAndroid Build Coastguard Worker 
2477*795d594fSAndroid Build Coastguard Worker   Register value = new_value.AsRegister<Register>();
2478*795d594fSAndroid Build Coastguard Worker   Register expected = expected_value.AsRegister<Register>();
2479*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(expected, EAX);
2480*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(temp, temp2);
2481*795d594fSAndroid Build Coastguard Worker 
2482*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitBakerReadBarrier()) {
2483*795d594fSAndroid Build Coastguard Worker     // Need to make sure the reference stored in the field is a to-space
2484*795d594fSAndroid Build Coastguard Worker     // one before attempting the CAS or the CAS could fail incorrectly.
2485*795d594fSAndroid Build Coastguard Worker     codegen->GenerateReferenceLoadWithBakerReadBarrier(
2486*795d594fSAndroid Build Coastguard Worker         invoke,
2487*795d594fSAndroid Build Coastguard Worker         // Unused, used only as a "temporary" within the read barrier.
2488*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(temp),
2489*795d594fSAndroid Build Coastguard Worker         base,
2490*795d594fSAndroid Build Coastguard Worker         field_addr,
2491*795d594fSAndroid Build Coastguard Worker         /* needs_null_check= */ false,
2492*795d594fSAndroid Build Coastguard Worker         /* always_update_field= */ true,
2493*795d594fSAndroid Build Coastguard Worker         &temp2);
2494*795d594fSAndroid Build Coastguard Worker   }
2495*795d594fSAndroid Build Coastguard Worker   bool base_equals_value = (base == value);
2496*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
2497*795d594fSAndroid Build Coastguard Worker     if (base_equals_value) {
2498*795d594fSAndroid Build Coastguard Worker       // If `base` and `value` are the same register location, move
2499*795d594fSAndroid Build Coastguard Worker       // `value` to a temporary register.  This way, poisoning
2500*795d594fSAndroid Build Coastguard Worker       // `value` won't invalidate `base`.
2501*795d594fSAndroid Build Coastguard Worker       value = temp;
2502*795d594fSAndroid Build Coastguard Worker       __ movl(value, base);
2503*795d594fSAndroid Build Coastguard Worker     }
2504*795d594fSAndroid Build Coastguard Worker 
2505*795d594fSAndroid Build Coastguard Worker     // Check that the register allocator did not assign the location
2506*795d594fSAndroid Build Coastguard Worker     // of `expected` (EAX) to `value` nor to `base`, so that heap
2507*795d594fSAndroid Build Coastguard Worker     // poisoning (when enabled) works as intended below.
2508*795d594fSAndroid Build Coastguard Worker     // - If `value` were equal to `expected`, both references would
2509*795d594fSAndroid Build Coastguard Worker     //   be poisoned twice, meaning they would not be poisoned at
2510*795d594fSAndroid Build Coastguard Worker     //   all, as heap poisoning uses address negation.
2511*795d594fSAndroid Build Coastguard Worker     // - If `base` were equal to `expected`, poisoning `expected`
2512*795d594fSAndroid Build Coastguard Worker     //   would invalidate `base`.
2513*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(value, expected);
2514*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(base, expected);
2515*795d594fSAndroid Build Coastguard Worker     __ PoisonHeapReference(expected);
2516*795d594fSAndroid Build Coastguard Worker     __ PoisonHeapReference(value);
2517*795d594fSAndroid Build Coastguard Worker   }
2518*795d594fSAndroid Build Coastguard Worker   __ LockCmpxchgl(field_addr, value);
2519*795d594fSAndroid Build Coastguard Worker 
2520*795d594fSAndroid Build Coastguard Worker   // LOCK CMPXCHG has full barrier semantics, and we don't need
2521*795d594fSAndroid Build Coastguard Worker   // scheduling barriers at this time.
2522*795d594fSAndroid Build Coastguard Worker 
2523*795d594fSAndroid Build Coastguard Worker   if (is_cmpxchg) {
2524*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(out.AsRegister<Register>(), EAX);
2525*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
2526*795d594fSAndroid Build Coastguard Worker   } else {
2527*795d594fSAndroid Build Coastguard Worker     // Convert ZF into the Boolean result.
2528*795d594fSAndroid Build Coastguard Worker     __ setb(kZero, out.AsRegister<Register>());
2529*795d594fSAndroid Build Coastguard Worker     __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
2530*795d594fSAndroid Build Coastguard Worker   }
2531*795d594fSAndroid Build Coastguard Worker 
2532*795d594fSAndroid Build Coastguard Worker   // Mark card for object if the new value is stored.
2533*795d594fSAndroid Build Coastguard Worker   bool value_can_be_null = true;  // TODO: Worth finding out this information?
2534*795d594fSAndroid Build Coastguard Worker   NearLabel skip_mark_gc_card;
2535*795d594fSAndroid Build Coastguard Worker   __ j(kNotZero, &skip_mark_gc_card);
2536*795d594fSAndroid Build Coastguard Worker   codegen->MaybeMarkGCCard(temp, temp2, base, value, value_can_be_null);
2537*795d594fSAndroid Build Coastguard Worker   __ Bind(&skip_mark_gc_card);
2538*795d594fSAndroid Build Coastguard Worker 
2539*795d594fSAndroid Build Coastguard Worker   // If heap poisoning is enabled, we need to unpoison the values
2540*795d594fSAndroid Build Coastguard Worker   // that were poisoned earlier.
2541*795d594fSAndroid Build Coastguard Worker   if (kPoisonHeapReferences) {
2542*795d594fSAndroid Build Coastguard Worker     if (base_equals_value) {
2543*795d594fSAndroid Build Coastguard Worker       // `value` has been moved to a temporary register, no need to
2544*795d594fSAndroid Build Coastguard Worker       // unpoison it.
2545*795d594fSAndroid Build Coastguard Worker     } else {
2546*795d594fSAndroid Build Coastguard Worker       // Ensure `value` is different from `out`, so that unpoisoning
2547*795d594fSAndroid Build Coastguard Worker       // the former does not invalidate the latter.
2548*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(value, out.AsRegister<Register>());
2549*795d594fSAndroid Build Coastguard Worker       __ UnpoisonHeapReference(value);
2550*795d594fSAndroid Build Coastguard Worker     }
2551*795d594fSAndroid Build Coastguard Worker   }
2552*795d594fSAndroid Build Coastguard Worker   // Do not unpoison the reference contained in register
2553*795d594fSAndroid Build Coastguard Worker   // `expected`, as it is the same as register `out` (EAX).
2554*795d594fSAndroid Build Coastguard Worker }
2555*795d594fSAndroid Build Coastguard Worker 
GenCAS(DataType::Type type,HInvoke * invoke,CodeGeneratorX86 * codegen)2556*795d594fSAndroid Build Coastguard Worker static void GenCAS(DataType::Type type, HInvoke* invoke, CodeGeneratorX86* codegen) {
2557*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2558*795d594fSAndroid Build Coastguard Worker 
2559*795d594fSAndroid Build Coastguard Worker   Register base = locations->InAt(1).AsRegister<Register>();
2560*795d594fSAndroid Build Coastguard Worker   Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
2561*795d594fSAndroid Build Coastguard Worker   Location expected_value = locations->InAt(3);
2562*795d594fSAndroid Build Coastguard Worker   Location new_value = locations->InAt(4);
2563*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
2564*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(out.AsRegister<Register>(), EAX);
2565*795d594fSAndroid Build Coastguard Worker 
2566*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
2567*795d594fSAndroid Build Coastguard Worker     // The only read barrier implementation supporting the
2568*795d594fSAndroid Build Coastguard Worker     // UnsafeCASObject intrinsic is the Baker-style read barriers.
2569*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
2570*795d594fSAndroid Build Coastguard Worker 
2571*795d594fSAndroid Build Coastguard Worker     Register temp = locations->GetTemp(0).AsRegister<Register>();
2572*795d594fSAndroid Build Coastguard Worker     Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2573*795d594fSAndroid Build Coastguard Worker     GenReferenceCAS(invoke, codegen, expected_value, new_value, base, offset, temp, temp2);
2574*795d594fSAndroid Build Coastguard Worker   } else {
2575*795d594fSAndroid Build Coastguard Worker     DCHECK(!DataType::IsFloatingPointType(type));
2576*795d594fSAndroid Build Coastguard Worker     GenPrimitiveCAS(type, codegen, expected_value, new_value, base, offset, out);
2577*795d594fSAndroid Build Coastguard Worker   }
2578*795d594fSAndroid Build Coastguard Worker }
2579*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASInt(HInvoke * invoke)2580*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeCASInt(HInvoke* invoke) {
2581*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASInt(invoke);
2582*795d594fSAndroid Build Coastguard Worker }
2583*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASLong(HInvoke * invoke)2584*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) {
2585*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCASLong(invoke);
2586*795d594fSAndroid Build Coastguard Worker }
2587*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeCASObject(HInvoke * invoke)2588*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) {
2589*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
2590*795d594fSAndroid Build Coastguard Worker   // UnsafeCASObject intrinsic is the Baker-style read barriers.
2591*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
2592*795d594fSAndroid Build Coastguard Worker 
2593*795d594fSAndroid Build Coastguard Worker   GenCAS(DataType::Type::kReference, invoke, codegen_);
2594*795d594fSAndroid Build Coastguard Worker }
2595*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASInt(HInvoke * invoke)2596*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCASInt(HInvoke* invoke) {
2597*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
2598*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetInt(invoke);
2599*795d594fSAndroid Build Coastguard Worker }
2600*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASLong(HInvoke * invoke)2601*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCASLong(HInvoke* invoke) {
2602*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
2603*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetLong(invoke);
2604*795d594fSAndroid Build Coastguard Worker }
2605*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCASObject(HInvoke * invoke)2606*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCASObject(HInvoke* invoke) {
2607*795d594fSAndroid Build Coastguard Worker   // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
2608*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeCompareAndSetReference(invoke);
2609*795d594fSAndroid Build Coastguard Worker }
2610*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)2611*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
2612*795d594fSAndroid Build Coastguard Worker   GenCAS(DataType::Type::kInt32, invoke, codegen_);
2613*795d594fSAndroid Build Coastguard Worker }
2614*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)2615*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
2616*795d594fSAndroid Build Coastguard Worker   GenCAS(DataType::Type::kInt64, invoke, codegen_);
2617*795d594fSAndroid Build Coastguard Worker }
2618*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)2619*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
2620*795d594fSAndroid Build Coastguard Worker   // The only supported read barrier implementation is the Baker-style read barriers.
2621*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
2622*795d594fSAndroid Build Coastguard Worker 
2623*795d594fSAndroid Build Coastguard Worker   GenCAS(DataType::Type::kReference, invoke, codegen_);
2624*795d594fSAndroid Build Coastguard Worker }
2625*795d594fSAndroid Build Coastguard Worker 
2626*795d594fSAndroid Build Coastguard Worker // Note: Unlike other architectures that use corresponding enums for the `VarHandle`
2627*795d594fSAndroid Build Coastguard Worker // implementation, x86 is currently using it only for `Unsafe`.
2628*795d594fSAndroid Build Coastguard Worker enum class GetAndUpdateOp {
2629*795d594fSAndroid Build Coastguard Worker   kSet,
2630*795d594fSAndroid Build Coastguard Worker   kAdd,
2631*795d594fSAndroid Build Coastguard Worker };
2632*795d594fSAndroid Build Coastguard Worker 
CreateUnsafeGetAndUpdateLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorX86 * codegen,DataType::Type type,GetAndUpdateOp get_and_unsafe_op)2633*795d594fSAndroid Build Coastguard Worker void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
2634*795d594fSAndroid Build Coastguard Worker                                        HInvoke* invoke,
2635*795d594fSAndroid Build Coastguard Worker                                        CodeGeneratorX86* codegen,
2636*795d594fSAndroid Build Coastguard Worker                                        DataType::Type type,
2637*795d594fSAndroid Build Coastguard Worker                                        GetAndUpdateOp get_and_unsafe_op) {
2638*795d594fSAndroid Build Coastguard Worker   const bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetAndSetReference(invoke);
2639*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2640*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke,
2641*795d594fSAndroid Build Coastguard Worker                                       can_call
2642*795d594fSAndroid Build Coastguard Worker                                           ? LocationSummary::kCallOnSlowPath
2643*795d594fSAndroid Build Coastguard Worker                                           : LocationSummary::kNoCall,
2644*795d594fSAndroid Build Coastguard Worker                                       kIntrinsified);
2645*795d594fSAndroid Build Coastguard Worker   if (can_call && kUseBakerReadBarrier) {
2646*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
2647*795d594fSAndroid Build Coastguard Worker   }
2648*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
2649*795d594fSAndroid Build Coastguard Worker   const bool is_void = invoke->GetType() == DataType::Type::kVoid;
2650*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
2651*795d594fSAndroid Build Coastguard Worker     // Explicitly allocate all registers.
2652*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RegisterLocation(EBP));
2653*795d594fSAndroid Build Coastguard Worker     if (get_and_unsafe_op == GetAndUpdateOp::kAdd) {
2654*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EBP));  // We shall clobber EBP.
2655*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(2, Location::Any());  // Offset shall be on the stack.
2656*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(3, Location::RegisterPairLocation(ESI, EDI));
2657*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EBX));
2658*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(ECX));
2659*795d594fSAndroid Build Coastguard Worker     } else {
2660*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(2, Location::RegisterPairLocation(ESI, EDI));
2661*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(3, Location::RegisterPairLocation(EBX, ECX));
2662*795d594fSAndroid Build Coastguard Worker     }
2663*795d594fSAndroid Build Coastguard Worker     if (is_void) {
2664*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
2665*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EDX));
2666*795d594fSAndroid Build Coastguard Worker     } else {
2667*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterPairLocation(EAX, EDX), Location::kOutputOverlap);
2668*795d594fSAndroid Build Coastguard Worker     }
2669*795d594fSAndroid Build Coastguard Worker   } else {
2670*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
2671*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::RequiresRegister());
2672*795d594fSAndroid Build Coastguard Worker     // Use the same register for both the output and the new value or addend
2673*795d594fSAndroid Build Coastguard Worker     // to take advantage of XCHG or XADD. Arbitrarily pick EAX.
2674*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::RegisterLocation(EAX));
2675*795d594fSAndroid Build Coastguard Worker     // Only set the `out` register if it's needed. In the void case we can still use EAX in the
2676*795d594fSAndroid Build Coastguard Worker     // same manner as it is marked as a temp register.
2677*795d594fSAndroid Build Coastguard Worker     if (is_void) {
2678*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
2679*795d594fSAndroid Build Coastguard Worker     } else {
2680*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterLocation(EAX));
2681*795d594fSAndroid Build Coastguard Worker     }
2682*795d594fSAndroid Build Coastguard Worker   }
2683*795d594fSAndroid Build Coastguard Worker }
2684*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddInt(HInvoke * invoke)2685*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
2686*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddInt(invoke);
2687*795d594fSAndroid Build Coastguard Worker }
2688*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddLong(HInvoke * invoke)2689*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
2690*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddLong(invoke);
2691*795d594fSAndroid Build Coastguard Worker }
2692*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetInt(HInvoke * invoke)2693*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
2694*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetInt(invoke);
2695*795d594fSAndroid Build Coastguard Worker }
2696*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetLong(HInvoke * invoke)2697*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
2698*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetLong(invoke);
2699*795d594fSAndroid Build Coastguard Worker }
2700*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetObject(HInvoke * invoke)2701*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
2702*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetReference(invoke);
2703*795d594fSAndroid Build Coastguard Worker }
2704*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)2705*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
2706*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(
2707*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt32, GetAndUpdateOp::kAdd);
2708*795d594fSAndroid Build Coastguard Worker }
2709*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)2710*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
2711*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(
2712*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt64, GetAndUpdateOp::kAdd);
2713*795d594fSAndroid Build Coastguard Worker }
2714*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)2715*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
2716*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(
2717*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt32, GetAndUpdateOp::kSet);
2718*795d594fSAndroid Build Coastguard Worker }
2719*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)2720*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
2721*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(
2722*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kInt64, GetAndUpdateOp::kSet);
2723*795d594fSAndroid Build Coastguard Worker }
2724*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)2725*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
2726*795d594fSAndroid Build Coastguard Worker   // The only supported read barrier implementation is the Baker-style read barriers.
2727*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitNonBakerReadBarrier()) {
2728*795d594fSAndroid Build Coastguard Worker     return;
2729*795d594fSAndroid Build Coastguard Worker   }
2730*795d594fSAndroid Build Coastguard Worker 
2731*795d594fSAndroid Build Coastguard Worker   CreateUnsafeGetAndUpdateLocations(
2732*795d594fSAndroid Build Coastguard Worker       allocator_, invoke, codegen_, DataType::Type::kReference, GetAndUpdateOp::kSet);
2733*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2734*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
2735*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(ECX));  // Byte register for `MarkGCCard()`.
2736*795d594fSAndroid Build Coastguard Worker }
2737*795d594fSAndroid Build Coastguard Worker 
GenUnsafeGetAndUpdate(HInvoke * invoke,DataType::Type type,CodeGeneratorX86 * codegen,GetAndUpdateOp get_and_update_op)2738*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAndUpdate(HInvoke* invoke,
2739*795d594fSAndroid Build Coastguard Worker                                   DataType::Type type,
2740*795d594fSAndroid Build Coastguard Worker                                   CodeGeneratorX86* codegen,
2741*795d594fSAndroid Build Coastguard Worker                                   GetAndUpdateOp get_and_update_op) {
2742*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
2743*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2744*795d594fSAndroid Build Coastguard Worker 
2745*795d594fSAndroid Build Coastguard Worker   const bool is_void = invoke->GetType() == DataType::Type::kVoid;
2746*795d594fSAndroid Build Coastguard Worker   // We use requested specific registers to use as temps for void methods, as we don't return the
2747*795d594fSAndroid Build Coastguard Worker   // value.
2748*795d594fSAndroid Build Coastguard Worker   Location out_or_temp =
2749*795d594fSAndroid Build Coastguard Worker       is_void ? (type == DataType::Type::kInt64 ? Location::RegisterPairLocation(EAX, EDX) :
2750*795d594fSAndroid Build Coastguard Worker                                                   Location::RegisterLocation(EAX)) :
2751*795d594fSAndroid Build Coastguard Worker                 locations->Out();
2752*795d594fSAndroid Build Coastguard Worker   Register base = locations->InAt(1).AsRegister<Register>();  // Object pointer.
2753*795d594fSAndroid Build Coastguard Worker   Location offset = locations->InAt(2);                       // Long offset.
2754*795d594fSAndroid Build Coastguard Worker   Location arg = locations->InAt(3);                          // New value or addend.
2755*795d594fSAndroid Build Coastguard Worker 
2756*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt32) {
2757*795d594fSAndroid Build Coastguard Worker     DCHECK(out_or_temp.Equals(arg));
2758*795d594fSAndroid Build Coastguard Worker     Register out_reg = out_or_temp.AsRegister<Register>();
2759*795d594fSAndroid Build Coastguard Worker     Address field_address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 0);
2760*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAdd) {
2761*795d594fSAndroid Build Coastguard Worker       __ LockXaddl(field_address, out_reg);
2762*795d594fSAndroid Build Coastguard Worker     } else {
2763*795d594fSAndroid Build Coastguard Worker       DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
2764*795d594fSAndroid Build Coastguard Worker       __ xchgl(out_reg, field_address);
2765*795d594fSAndroid Build Coastguard Worker     }
2766*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kInt64) {
2767*795d594fSAndroid Build Coastguard Worker     // Prepare the field address. Ignore the high 32 bits of the `offset`.
2768*795d594fSAndroid Build Coastguard Worker     Address field_address_low(kNoRegister, 0), field_address_high(kNoRegister, 0);
2769*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAdd) {
2770*795d594fSAndroid Build Coastguard Worker       DCHECK(offset.IsDoubleStackSlot());
2771*795d594fSAndroid Build Coastguard Worker       __ addl(base, Address(ESP, offset.GetStackIndex()));  // Clobbers `base`.
2772*795d594fSAndroid Build Coastguard Worker       DCHECK(Location::RegisterLocation(base).Equals(locations->GetTemp(0)));
2773*795d594fSAndroid Build Coastguard Worker       field_address_low = Address(base, 0);
2774*795d594fSAndroid Build Coastguard Worker       field_address_high = Address(base, 4);
2775*795d594fSAndroid Build Coastguard Worker     } else {
2776*795d594fSAndroid Build Coastguard Worker       field_address_low = Address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 0);
2777*795d594fSAndroid Build Coastguard Worker       field_address_high = Address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 4);
2778*795d594fSAndroid Build Coastguard Worker     }
2779*795d594fSAndroid Build Coastguard Worker     // Load the old value to EDX:EAX and use LOCK CMPXCHG8B to set the new value.
2780*795d594fSAndroid Build Coastguard Worker     NearLabel loop;
2781*795d594fSAndroid Build Coastguard Worker     __ Bind(&loop);
2782*795d594fSAndroid Build Coastguard Worker     __ movl(EAX, field_address_low);
2783*795d594fSAndroid Build Coastguard Worker     __ movl(EDX, field_address_high);
2784*795d594fSAndroid Build Coastguard Worker     if (get_and_update_op == GetAndUpdateOp::kAdd) {
2785*795d594fSAndroid Build Coastguard Worker       DCHECK(Location::RegisterPairLocation(ESI, EDI).Equals(arg));
2786*795d594fSAndroid Build Coastguard Worker       __ movl(EBX, EAX);
2787*795d594fSAndroid Build Coastguard Worker       __ movl(ECX, EDX);
2788*795d594fSAndroid Build Coastguard Worker       __ addl(EBX, ESI);
2789*795d594fSAndroid Build Coastguard Worker       __ adcl(ECX, EDI);
2790*795d594fSAndroid Build Coastguard Worker     } else {
2791*795d594fSAndroid Build Coastguard Worker       DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
2792*795d594fSAndroid Build Coastguard Worker       DCHECK(Location::RegisterPairLocation(EBX, ECX).Equals(arg));
2793*795d594fSAndroid Build Coastguard Worker     }
2794*795d594fSAndroid Build Coastguard Worker     __ LockCmpxchg8b(field_address_low);
2795*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, &loop);  // Repeat on failure.
2796*795d594fSAndroid Build Coastguard Worker   } else {
2797*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kReference);
2798*795d594fSAndroid Build Coastguard Worker     DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
2799*795d594fSAndroid Build Coastguard Worker     Register out_reg = out_or_temp.AsRegister<Register>();
2800*795d594fSAndroid Build Coastguard Worker     Address field_address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 0);
2801*795d594fSAndroid Build Coastguard Worker     Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2802*795d594fSAndroid Build Coastguard Worker     Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2803*795d594fSAndroid Build Coastguard Worker 
2804*795d594fSAndroid Build Coastguard Worker     if (codegen->EmitReadBarrier()) {
2805*795d594fSAndroid Build Coastguard Worker       DCHECK(kUseBakerReadBarrier);
2806*795d594fSAndroid Build Coastguard Worker       // Ensure that the field contains a to-space reference.
2807*795d594fSAndroid Build Coastguard Worker       codegen->GenerateReferenceLoadWithBakerReadBarrier(
2808*795d594fSAndroid Build Coastguard Worker           invoke,
2809*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(temp2),
2810*795d594fSAndroid Build Coastguard Worker           base,
2811*795d594fSAndroid Build Coastguard Worker           field_address,
2812*795d594fSAndroid Build Coastguard Worker           /*needs_null_check=*/ false,
2813*795d594fSAndroid Build Coastguard Worker           /*always_update_field=*/ true,
2814*795d594fSAndroid Build Coastguard Worker           &temp1);
2815*795d594fSAndroid Build Coastguard Worker     }
2816*795d594fSAndroid Build Coastguard Worker 
2817*795d594fSAndroid Build Coastguard Worker     // Mark card for object as a new value shall be stored.
2818*795d594fSAndroid Build Coastguard Worker     bool new_value_can_be_null = true;  // TODO: Worth finding out this information?
2819*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(temp2, ECX);  // Byte register for `MarkGCCard()`.
2820*795d594fSAndroid Build Coastguard Worker     codegen->MaybeMarkGCCard(temp1, temp2, base, /*value=*/out_reg, new_value_can_be_null);
2821*795d594fSAndroid Build Coastguard Worker 
2822*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences) {
2823*795d594fSAndroid Build Coastguard Worker       // Use a temp to avoid poisoning base of the field address, which might happen if `out`
2824*795d594fSAndroid Build Coastguard Worker       // is the same as `base` (for code like `unsafe.getAndSet(obj, offset, obj)`).
2825*795d594fSAndroid Build Coastguard Worker       __ movl(temp1, out_reg);
2826*795d594fSAndroid Build Coastguard Worker       __ PoisonHeapReference(temp1);
2827*795d594fSAndroid Build Coastguard Worker       __ xchgl(temp1, field_address);
2828*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
2829*795d594fSAndroid Build Coastguard Worker         __ UnpoisonHeapReference(temp1);
2830*795d594fSAndroid Build Coastguard Worker         __ movl(out_reg, temp1);
2831*795d594fSAndroid Build Coastguard Worker       }
2832*795d594fSAndroid Build Coastguard Worker     } else {
2833*795d594fSAndroid Build Coastguard Worker       __ xchgl(out_reg, field_address);
2834*795d594fSAndroid Build Coastguard Worker     }
2835*795d594fSAndroid Build Coastguard Worker   }
2836*795d594fSAndroid Build Coastguard Worker }
2837*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddInt(HInvoke * invoke)2838*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
2839*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddInt(invoke);
2840*795d594fSAndroid Build Coastguard Worker }
2841*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndAddLong(HInvoke * invoke)2842*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
2843*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndAddLong(invoke);
2844*795d594fSAndroid Build Coastguard Worker }
2845*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetInt(HInvoke * invoke)2846*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
2847*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetInt(invoke);
2848*795d594fSAndroid Build Coastguard Worker }
2849*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetLong(HInvoke * invoke)2850*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
2851*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetLong(invoke);
2852*795d594fSAndroid Build Coastguard Worker }
2853*795d594fSAndroid Build Coastguard Worker 
VisitUnsafeGetAndSetObject(HInvoke * invoke)2854*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
2855*795d594fSAndroid Build Coastguard Worker   VisitJdkUnsafeGetAndSetReference(invoke);
2856*795d594fSAndroid Build Coastguard Worker }
2857*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)2858*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
2859*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kAdd);
2860*795d594fSAndroid Build Coastguard Worker }
2861*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)2862*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
2863*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kAdd);
2864*795d594fSAndroid Build Coastguard Worker }
2865*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)2866*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
2867*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kSet);
2868*795d594fSAndroid Build Coastguard Worker }
2869*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)2870*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
2871*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kSet);
2872*795d594fSAndroid Build Coastguard Worker }
2873*795d594fSAndroid Build Coastguard Worker 
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)2874*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
2875*795d594fSAndroid Build Coastguard Worker   GenUnsafeGetAndUpdate(invoke, DataType::Type::kReference, codegen_, GetAndUpdateOp::kSet);
2876*795d594fSAndroid Build Coastguard Worker }
2877*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverse(HInvoke * invoke)2878*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerReverse(HInvoke* invoke) {
2879*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2880*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2881*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2882*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
2883*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
2884*795d594fSAndroid Build Coastguard Worker }
2885*795d594fSAndroid Build Coastguard Worker 
SwapBits(Register reg,Register temp,int32_t shift,int32_t mask,X86Assembler * assembler)2886*795d594fSAndroid Build Coastguard Worker static void SwapBits(Register reg, Register temp, int32_t shift, int32_t mask,
2887*795d594fSAndroid Build Coastguard Worker                      X86Assembler* assembler) {
2888*795d594fSAndroid Build Coastguard Worker   Immediate imm_shift(shift);
2889*795d594fSAndroid Build Coastguard Worker   Immediate imm_mask(mask);
2890*795d594fSAndroid Build Coastguard Worker   __ movl(temp, reg);
2891*795d594fSAndroid Build Coastguard Worker   __ shrl(reg, imm_shift);
2892*795d594fSAndroid Build Coastguard Worker   __ andl(temp, imm_mask);
2893*795d594fSAndroid Build Coastguard Worker   __ andl(reg, imm_mask);
2894*795d594fSAndroid Build Coastguard Worker   __ shll(temp, imm_shift);
2895*795d594fSAndroid Build Coastguard Worker   __ orl(reg, temp);
2896*795d594fSAndroid Build Coastguard Worker }
2897*795d594fSAndroid Build Coastguard Worker 
VisitIntegerReverse(HInvoke * invoke)2898*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerReverse(HInvoke* invoke) {
2899*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
2900*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2901*795d594fSAndroid Build Coastguard Worker 
2902*795d594fSAndroid Build Coastguard Worker   Register reg = locations->InAt(0).AsRegister<Register>();
2903*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
2904*795d594fSAndroid Build Coastguard Worker 
2905*795d594fSAndroid Build Coastguard Worker   /*
2906*795d594fSAndroid Build Coastguard Worker    * Use one bswap instruction to reverse byte order first and then use 3 rounds of
2907*795d594fSAndroid Build Coastguard Worker    * swapping bits to reverse bits in a number x. Using bswap to save instructions
2908*795d594fSAndroid Build Coastguard Worker    * compared to generic luni implementation which has 5 rounds of swapping bits.
2909*795d594fSAndroid Build Coastguard Worker    * x = bswap x
2910*795d594fSAndroid Build Coastguard Worker    * x = (x & 0x55555555) << 1 | (x >> 1) & 0x55555555;
2911*795d594fSAndroid Build Coastguard Worker    * x = (x & 0x33333333) << 2 | (x >> 2) & 0x33333333;
2912*795d594fSAndroid Build Coastguard Worker    * x = (x & 0x0F0F0F0F) << 4 | (x >> 4) & 0x0F0F0F0F;
2913*795d594fSAndroid Build Coastguard Worker    */
2914*795d594fSAndroid Build Coastguard Worker   __ bswapl(reg);
2915*795d594fSAndroid Build Coastguard Worker   SwapBits(reg, temp, 1, 0x55555555, assembler);
2916*795d594fSAndroid Build Coastguard Worker   SwapBits(reg, temp, 2, 0x33333333, assembler);
2917*795d594fSAndroid Build Coastguard Worker   SwapBits(reg, temp, 4, 0x0f0f0f0f, assembler);
2918*795d594fSAndroid Build Coastguard Worker }
2919*795d594fSAndroid Build Coastguard Worker 
VisitLongReverse(HInvoke * invoke)2920*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongReverse(HInvoke* invoke) {
2921*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2922*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2923*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
2924*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
2925*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
2926*795d594fSAndroid Build Coastguard Worker }
2927*795d594fSAndroid Build Coastguard Worker 
VisitLongReverse(HInvoke * invoke)2928*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongReverse(HInvoke* invoke) {
2929*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
2930*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2931*795d594fSAndroid Build Coastguard Worker 
2932*795d594fSAndroid Build Coastguard Worker   Register reg_low = locations->InAt(0).AsRegisterPairLow<Register>();
2933*795d594fSAndroid Build Coastguard Worker   Register reg_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2934*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
2935*795d594fSAndroid Build Coastguard Worker 
2936*795d594fSAndroid Build Coastguard Worker   // We want to swap high/low, then bswap each one, and then do the same
2937*795d594fSAndroid Build Coastguard Worker   // as a 32 bit reverse.
2938*795d594fSAndroid Build Coastguard Worker   // Exchange high and low.
2939*795d594fSAndroid Build Coastguard Worker   __ movl(temp, reg_low);
2940*795d594fSAndroid Build Coastguard Worker   __ movl(reg_low, reg_high);
2941*795d594fSAndroid Build Coastguard Worker   __ movl(reg_high, temp);
2942*795d594fSAndroid Build Coastguard Worker 
2943*795d594fSAndroid Build Coastguard Worker   // bit-reverse low
2944*795d594fSAndroid Build Coastguard Worker   __ bswapl(reg_low);
2945*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_low, temp, 1, 0x55555555, assembler);
2946*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_low, temp, 2, 0x33333333, assembler);
2947*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_low, temp, 4, 0x0f0f0f0f, assembler);
2948*795d594fSAndroid Build Coastguard Worker 
2949*795d594fSAndroid Build Coastguard Worker   // bit-reverse high
2950*795d594fSAndroid Build Coastguard Worker   __ bswapl(reg_high);
2951*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_high, temp, 1, 0x55555555, assembler);
2952*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_high, temp, 2, 0x33333333, assembler);
2953*795d594fSAndroid Build Coastguard Worker   SwapBits(reg_high, temp, 4, 0x0f0f0f0f, assembler);
2954*795d594fSAndroid Build Coastguard Worker }
2955*795d594fSAndroid Build Coastguard Worker 
CreateBitCountLocations(ArenaAllocator * allocator,CodeGeneratorX86 * codegen,HInvoke * invoke,bool is_long)2956*795d594fSAndroid Build Coastguard Worker static void CreateBitCountLocations(
2957*795d594fSAndroid Build Coastguard Worker     ArenaAllocator* allocator, CodeGeneratorX86* codegen, HInvoke* invoke, bool is_long) {
2958*795d594fSAndroid Build Coastguard Worker   if (!codegen->GetInstructionSetFeatures().HasPopCnt()) {
2959*795d594fSAndroid Build Coastguard Worker     // Do nothing if there is no popcnt support. This results in generating
2960*795d594fSAndroid Build Coastguard Worker     // a call for the intrinsic rather than direct code.
2961*795d594fSAndroid Build Coastguard Worker     return;
2962*795d594fSAndroid Build Coastguard Worker   }
2963*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2964*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2965*795d594fSAndroid Build Coastguard Worker   if (is_long) {
2966*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
2967*795d594fSAndroid Build Coastguard Worker   }
2968*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::Any());
2969*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
2970*795d594fSAndroid Build Coastguard Worker }
2971*795d594fSAndroid Build Coastguard Worker 
GenBitCount(X86Assembler * assembler,CodeGeneratorX86 * codegen,HInvoke * invoke,bool is_long)2972*795d594fSAndroid Build Coastguard Worker static void GenBitCount(X86Assembler* assembler,
2973*795d594fSAndroid Build Coastguard Worker                         CodeGeneratorX86* codegen,
2974*795d594fSAndroid Build Coastguard Worker                         HInvoke* invoke, bool is_long) {
2975*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2976*795d594fSAndroid Build Coastguard Worker   Location src = locations->InAt(0);
2977*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
2978*795d594fSAndroid Build Coastguard Worker 
2979*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsConstant()) {
2980*795d594fSAndroid Build Coastguard Worker     // Evaluate this at compile time.
2981*795d594fSAndroid Build Coastguard Worker     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
2982*795d594fSAndroid Build Coastguard Worker     int32_t result = is_long
2983*795d594fSAndroid Build Coastguard Worker         ? POPCOUNT(static_cast<uint64_t>(value))
2984*795d594fSAndroid Build Coastguard Worker         : POPCOUNT(static_cast<uint32_t>(value));
2985*795d594fSAndroid Build Coastguard Worker     codegen->Load32BitValue(out, result);
2986*795d594fSAndroid Build Coastguard Worker     return;
2987*795d594fSAndroid Build Coastguard Worker   }
2988*795d594fSAndroid Build Coastguard Worker 
2989*795d594fSAndroid Build Coastguard Worker   // Handle the non-constant cases.
2990*795d594fSAndroid Build Coastguard Worker   if (!is_long) {
2991*795d594fSAndroid Build Coastguard Worker     if (src.IsRegister()) {
2992*795d594fSAndroid Build Coastguard Worker       __ popcntl(out, src.AsRegister<Register>());
2993*795d594fSAndroid Build Coastguard Worker     } else {
2994*795d594fSAndroid Build Coastguard Worker       DCHECK(src.IsStackSlot());
2995*795d594fSAndroid Build Coastguard Worker       __ popcntl(out, Address(ESP, src.GetStackIndex()));
2996*795d594fSAndroid Build Coastguard Worker     }
2997*795d594fSAndroid Build Coastguard Worker   } else {
2998*795d594fSAndroid Build Coastguard Worker     // The 64-bit case needs to worry about two parts.
2999*795d594fSAndroid Build Coastguard Worker     Register temp = locations->GetTemp(0).AsRegister<Register>();
3000*795d594fSAndroid Build Coastguard Worker     if (src.IsRegisterPair()) {
3001*795d594fSAndroid Build Coastguard Worker       __ popcntl(temp, src.AsRegisterPairLow<Register>());
3002*795d594fSAndroid Build Coastguard Worker       __ popcntl(out, src.AsRegisterPairHigh<Register>());
3003*795d594fSAndroid Build Coastguard Worker     } else {
3004*795d594fSAndroid Build Coastguard Worker       DCHECK(src.IsDoubleStackSlot());
3005*795d594fSAndroid Build Coastguard Worker       __ popcntl(temp, Address(ESP, src.GetStackIndex()));
3006*795d594fSAndroid Build Coastguard Worker       __ popcntl(out, Address(ESP, src.GetHighStackIndex(kX86WordSize)));
3007*795d594fSAndroid Build Coastguard Worker     }
3008*795d594fSAndroid Build Coastguard Worker     __ addl(out, temp);
3009*795d594fSAndroid Build Coastguard Worker   }
3010*795d594fSAndroid Build Coastguard Worker }
3011*795d594fSAndroid Build Coastguard Worker 
VisitIntegerBitCount(HInvoke * invoke)3012*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerBitCount(HInvoke* invoke) {
3013*795d594fSAndroid Build Coastguard Worker   CreateBitCountLocations(allocator_, codegen_, invoke, /* is_long= */ false);
3014*795d594fSAndroid Build Coastguard Worker }
3015*795d594fSAndroid Build Coastguard Worker 
VisitIntegerBitCount(HInvoke * invoke)3016*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerBitCount(HInvoke* invoke) {
3017*795d594fSAndroid Build Coastguard Worker   GenBitCount(GetAssembler(), codegen_, invoke, /* is_long= */ false);
3018*795d594fSAndroid Build Coastguard Worker }
3019*795d594fSAndroid Build Coastguard Worker 
VisitLongBitCount(HInvoke * invoke)3020*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongBitCount(HInvoke* invoke) {
3021*795d594fSAndroid Build Coastguard Worker   CreateBitCountLocations(allocator_, codegen_, invoke, /* is_long= */ true);
3022*795d594fSAndroid Build Coastguard Worker }
3023*795d594fSAndroid Build Coastguard Worker 
VisitLongBitCount(HInvoke * invoke)3024*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongBitCount(HInvoke* invoke) {
3025*795d594fSAndroid Build Coastguard Worker   GenBitCount(GetAssembler(), codegen_, invoke, /* is_long= */ true);
3026*795d594fSAndroid Build Coastguard Worker }
3027*795d594fSAndroid Build Coastguard Worker 
CreateLeadingZeroLocations(ArenaAllocator * allocator,HInvoke * invoke,bool is_long)3028*795d594fSAndroid Build Coastguard Worker static void CreateLeadingZeroLocations(ArenaAllocator* allocator, HInvoke* invoke, bool is_long) {
3029*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3030*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3031*795d594fSAndroid Build Coastguard Worker   if (is_long) {
3032*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
3033*795d594fSAndroid Build Coastguard Worker   } else {
3034*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::Any());
3035*795d594fSAndroid Build Coastguard Worker   }
3036*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
3037*795d594fSAndroid Build Coastguard Worker }
3038*795d594fSAndroid Build Coastguard Worker 
GenLeadingZeros(X86Assembler * assembler,CodeGeneratorX86 * codegen,HInvoke * invoke,bool is_long)3039*795d594fSAndroid Build Coastguard Worker static void GenLeadingZeros(X86Assembler* assembler,
3040*795d594fSAndroid Build Coastguard Worker                             CodeGeneratorX86* codegen,
3041*795d594fSAndroid Build Coastguard Worker                             HInvoke* invoke, bool is_long) {
3042*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3043*795d594fSAndroid Build Coastguard Worker   Location src = locations->InAt(0);
3044*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
3045*795d594fSAndroid Build Coastguard Worker 
3046*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsConstant()) {
3047*795d594fSAndroid Build Coastguard Worker     // Evaluate this at compile time.
3048*795d594fSAndroid Build Coastguard Worker     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
3049*795d594fSAndroid Build Coastguard Worker     if (value == 0) {
3050*795d594fSAndroid Build Coastguard Worker       value = is_long ? 64 : 32;
3051*795d594fSAndroid Build Coastguard Worker     } else {
3052*795d594fSAndroid Build Coastguard Worker       value = is_long ? CLZ(static_cast<uint64_t>(value)) : CLZ(static_cast<uint32_t>(value));
3053*795d594fSAndroid Build Coastguard Worker     }
3054*795d594fSAndroid Build Coastguard Worker     codegen->Load32BitValue(out, value);
3055*795d594fSAndroid Build Coastguard Worker     return;
3056*795d594fSAndroid Build Coastguard Worker   }
3057*795d594fSAndroid Build Coastguard Worker 
3058*795d594fSAndroid Build Coastguard Worker   // Handle the non-constant cases.
3059*795d594fSAndroid Build Coastguard Worker   if (!is_long) {
3060*795d594fSAndroid Build Coastguard Worker     if (src.IsRegister()) {
3061*795d594fSAndroid Build Coastguard Worker       __ bsrl(out, src.AsRegister<Register>());
3062*795d594fSAndroid Build Coastguard Worker     } else {
3063*795d594fSAndroid Build Coastguard Worker       DCHECK(src.IsStackSlot());
3064*795d594fSAndroid Build Coastguard Worker       __ bsrl(out, Address(ESP, src.GetStackIndex()));
3065*795d594fSAndroid Build Coastguard Worker     }
3066*795d594fSAndroid Build Coastguard Worker 
3067*795d594fSAndroid Build Coastguard Worker     // BSR sets ZF if the input was zero, and the output is undefined.
3068*795d594fSAndroid Build Coastguard Worker     NearLabel all_zeroes, done;
3069*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &all_zeroes);
3070*795d594fSAndroid Build Coastguard Worker 
3071*795d594fSAndroid Build Coastguard Worker     // Correct the result from BSR to get the final CLZ result.
3072*795d594fSAndroid Build Coastguard Worker     __ xorl(out, Immediate(31));
3073*795d594fSAndroid Build Coastguard Worker     __ jmp(&done);
3074*795d594fSAndroid Build Coastguard Worker 
3075*795d594fSAndroid Build Coastguard Worker     // Fix the zero case with the expected result.
3076*795d594fSAndroid Build Coastguard Worker     __ Bind(&all_zeroes);
3077*795d594fSAndroid Build Coastguard Worker     __ movl(out, Immediate(32));
3078*795d594fSAndroid Build Coastguard Worker 
3079*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
3080*795d594fSAndroid Build Coastguard Worker     return;
3081*795d594fSAndroid Build Coastguard Worker   }
3082*795d594fSAndroid Build Coastguard Worker 
3083*795d594fSAndroid Build Coastguard Worker   // 64 bit case needs to worry about both parts of the register.
3084*795d594fSAndroid Build Coastguard Worker   DCHECK(src.IsRegisterPair());
3085*795d594fSAndroid Build Coastguard Worker   Register src_lo = src.AsRegisterPairLow<Register>();
3086*795d594fSAndroid Build Coastguard Worker   Register src_hi = src.AsRegisterPairHigh<Register>();
3087*795d594fSAndroid Build Coastguard Worker   NearLabel handle_low, done, all_zeroes;
3088*795d594fSAndroid Build Coastguard Worker 
3089*795d594fSAndroid Build Coastguard Worker   // Is the high word zero?
3090*795d594fSAndroid Build Coastguard Worker   __ testl(src_hi, src_hi);
3091*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &handle_low);
3092*795d594fSAndroid Build Coastguard Worker 
3093*795d594fSAndroid Build Coastguard Worker   // High word is not zero. We know that the BSR result is defined in this case.
3094*795d594fSAndroid Build Coastguard Worker   __ bsrl(out, src_hi);
3095*795d594fSAndroid Build Coastguard Worker 
3096*795d594fSAndroid Build Coastguard Worker   // Correct the result from BSR to get the final CLZ result.
3097*795d594fSAndroid Build Coastguard Worker   __ xorl(out, Immediate(31));
3098*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
3099*795d594fSAndroid Build Coastguard Worker 
3100*795d594fSAndroid Build Coastguard Worker   // High word was zero.  We have to compute the low word count and add 32.
3101*795d594fSAndroid Build Coastguard Worker   __ Bind(&handle_low);
3102*795d594fSAndroid Build Coastguard Worker   __ bsrl(out, src_lo);
3103*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &all_zeroes);
3104*795d594fSAndroid Build Coastguard Worker 
3105*795d594fSAndroid Build Coastguard Worker   // We had a valid result.  Use an XOR to both correct the result and add 32.
3106*795d594fSAndroid Build Coastguard Worker   __ xorl(out, Immediate(63));
3107*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
3108*795d594fSAndroid Build Coastguard Worker 
3109*795d594fSAndroid Build Coastguard Worker   // All zero case.
3110*795d594fSAndroid Build Coastguard Worker   __ Bind(&all_zeroes);
3111*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(64));
3112*795d594fSAndroid Build Coastguard Worker 
3113*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
3114*795d594fSAndroid Build Coastguard Worker }
3115*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)3116*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
3117*795d594fSAndroid Build Coastguard Worker   CreateLeadingZeroLocations(allocator_, invoke, /* is_long= */ false);
3118*795d594fSAndroid Build Coastguard Worker }
3119*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)3120*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
3121*795d594fSAndroid Build Coastguard Worker   GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long= */ false);
3122*795d594fSAndroid Build Coastguard Worker }
3123*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)3124*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
3125*795d594fSAndroid Build Coastguard Worker   CreateLeadingZeroLocations(allocator_, invoke, /* is_long= */ true);
3126*795d594fSAndroid Build Coastguard Worker }
3127*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)3128*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
3129*795d594fSAndroid Build Coastguard Worker   GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long= */ true);
3130*795d594fSAndroid Build Coastguard Worker }
3131*795d594fSAndroid Build Coastguard Worker 
CreateTrailingZeroLocations(ArenaAllocator * allocator,HInvoke * invoke,bool is_long)3132*795d594fSAndroid Build Coastguard Worker static void CreateTrailingZeroLocations(ArenaAllocator* allocator, HInvoke* invoke, bool is_long) {
3133*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3134*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3135*795d594fSAndroid Build Coastguard Worker   if (is_long) {
3136*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
3137*795d594fSAndroid Build Coastguard Worker   } else {
3138*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::Any());
3139*795d594fSAndroid Build Coastguard Worker   }
3140*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
3141*795d594fSAndroid Build Coastguard Worker }
3142*795d594fSAndroid Build Coastguard Worker 
GenTrailingZeros(X86Assembler * assembler,CodeGeneratorX86 * codegen,HInvoke * invoke,bool is_long)3143*795d594fSAndroid Build Coastguard Worker static void GenTrailingZeros(X86Assembler* assembler,
3144*795d594fSAndroid Build Coastguard Worker                              CodeGeneratorX86* codegen,
3145*795d594fSAndroid Build Coastguard Worker                              HInvoke* invoke, bool is_long) {
3146*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3147*795d594fSAndroid Build Coastguard Worker   Location src = locations->InAt(0);
3148*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
3149*795d594fSAndroid Build Coastguard Worker 
3150*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsConstant()) {
3151*795d594fSAndroid Build Coastguard Worker     // Evaluate this at compile time.
3152*795d594fSAndroid Build Coastguard Worker     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
3153*795d594fSAndroid Build Coastguard Worker     if (value == 0) {
3154*795d594fSAndroid Build Coastguard Worker       value = is_long ? 64 : 32;
3155*795d594fSAndroid Build Coastguard Worker     } else {
3156*795d594fSAndroid Build Coastguard Worker       value = is_long ? CTZ(static_cast<uint64_t>(value)) : CTZ(static_cast<uint32_t>(value));
3157*795d594fSAndroid Build Coastguard Worker     }
3158*795d594fSAndroid Build Coastguard Worker     codegen->Load32BitValue(out, value);
3159*795d594fSAndroid Build Coastguard Worker     return;
3160*795d594fSAndroid Build Coastguard Worker   }
3161*795d594fSAndroid Build Coastguard Worker 
3162*795d594fSAndroid Build Coastguard Worker   // Handle the non-constant cases.
3163*795d594fSAndroid Build Coastguard Worker   if (!is_long) {
3164*795d594fSAndroid Build Coastguard Worker     if (src.IsRegister()) {
3165*795d594fSAndroid Build Coastguard Worker       __ bsfl(out, src.AsRegister<Register>());
3166*795d594fSAndroid Build Coastguard Worker     } else {
3167*795d594fSAndroid Build Coastguard Worker       DCHECK(src.IsStackSlot());
3168*795d594fSAndroid Build Coastguard Worker       __ bsfl(out, Address(ESP, src.GetStackIndex()));
3169*795d594fSAndroid Build Coastguard Worker     }
3170*795d594fSAndroid Build Coastguard Worker 
3171*795d594fSAndroid Build Coastguard Worker     // BSF sets ZF if the input was zero, and the output is undefined.
3172*795d594fSAndroid Build Coastguard Worker     NearLabel done;
3173*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, &done);
3174*795d594fSAndroid Build Coastguard Worker 
3175*795d594fSAndroid Build Coastguard Worker     // Fix the zero case with the expected result.
3176*795d594fSAndroid Build Coastguard Worker     __ movl(out, Immediate(32));
3177*795d594fSAndroid Build Coastguard Worker 
3178*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
3179*795d594fSAndroid Build Coastguard Worker     return;
3180*795d594fSAndroid Build Coastguard Worker   }
3181*795d594fSAndroid Build Coastguard Worker 
3182*795d594fSAndroid Build Coastguard Worker   // 64 bit case needs to worry about both parts of the register.
3183*795d594fSAndroid Build Coastguard Worker   DCHECK(src.IsRegisterPair());
3184*795d594fSAndroid Build Coastguard Worker   Register src_lo = src.AsRegisterPairLow<Register>();
3185*795d594fSAndroid Build Coastguard Worker   Register src_hi = src.AsRegisterPairHigh<Register>();
3186*795d594fSAndroid Build Coastguard Worker   NearLabel done, all_zeroes;
3187*795d594fSAndroid Build Coastguard Worker 
3188*795d594fSAndroid Build Coastguard Worker   // If the low word is zero, then ZF will be set.  If not, we have the answer.
3189*795d594fSAndroid Build Coastguard Worker   __ bsfl(out, src_lo);
3190*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &done);
3191*795d594fSAndroid Build Coastguard Worker 
3192*795d594fSAndroid Build Coastguard Worker   // Low word was zero.  We have to compute the high word count and add 32.
3193*795d594fSAndroid Build Coastguard Worker   __ bsfl(out, src_hi);
3194*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &all_zeroes);
3195*795d594fSAndroid Build Coastguard Worker 
3196*795d594fSAndroid Build Coastguard Worker   // We had a valid result.  Add 32 to account for the low word being zero.
3197*795d594fSAndroid Build Coastguard Worker   __ addl(out, Immediate(32));
3198*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
3199*795d594fSAndroid Build Coastguard Worker 
3200*795d594fSAndroid Build Coastguard Worker   // All zero case.
3201*795d594fSAndroid Build Coastguard Worker   __ Bind(&all_zeroes);
3202*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(64));
3203*795d594fSAndroid Build Coastguard Worker 
3204*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
3205*795d594fSAndroid Build Coastguard Worker }
3206*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)3207*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
3208*795d594fSAndroid Build Coastguard Worker   CreateTrailingZeroLocations(allocator_, invoke, /* is_long= */ false);
3209*795d594fSAndroid Build Coastguard Worker }
3210*795d594fSAndroid Build Coastguard Worker 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)3211*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
3212*795d594fSAndroid Build Coastguard Worker   GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long= */ false);
3213*795d594fSAndroid Build Coastguard Worker }
3214*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)3215*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
3216*795d594fSAndroid Build Coastguard Worker   CreateTrailingZeroLocations(allocator_, invoke, /* is_long= */ true);
3217*795d594fSAndroid Build Coastguard Worker }
3218*795d594fSAndroid Build Coastguard Worker 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)3219*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
3220*795d594fSAndroid Build Coastguard Worker   GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long= */ true);
3221*795d594fSAndroid Build Coastguard Worker }
3222*795d594fSAndroid Build Coastguard Worker 
IsSameInput(HInstruction * instruction,size_t input0,size_t input1)3223*795d594fSAndroid Build Coastguard Worker static bool IsSameInput(HInstruction* instruction, size_t input0, size_t input1) {
3224*795d594fSAndroid Build Coastguard Worker   return instruction->InputAt(input0) == instruction->InputAt(input1);
3225*795d594fSAndroid Build Coastguard Worker }
3226*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopy(HInvoke * invoke)3227*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitSystemArrayCopy(HInvoke* invoke) {
3228*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
3229*795d594fSAndroid Build Coastguard Worker   // SystemArrayCopy intrinsic is the Baker-style read barriers.
3230*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitNonBakerReadBarrier()) {
3231*795d594fSAndroid Build Coastguard Worker     return;
3232*795d594fSAndroid Build Coastguard Worker   }
3233*795d594fSAndroid Build Coastguard Worker 
3234*795d594fSAndroid Build Coastguard Worker   constexpr int32_t kLengthThreshold = -1;  // No cut-off - handle large arrays in intrinsic code.
3235*795d594fSAndroid Build Coastguard Worker   constexpr size_t kInitialNumTemps = 0u;  // We shall allocate temps explicitly.
3236*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = CodeGenerator::CreateSystemArrayCopyLocationSummary(
3237*795d594fSAndroid Build Coastguard Worker       invoke, kLengthThreshold, kInitialNumTemps);
3238*795d594fSAndroid Build Coastguard Worker   if (locations != nullptr) {
3239*795d594fSAndroid Build Coastguard Worker     // Add temporaries.  We will use REP MOVSL, so we need fixed registers.
3240*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(locations->GetTempCount(), kInitialNumTemps);
3241*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(ESI));
3242*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(EDI));
3243*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(ECX));  // Byte reg also used for write barrier.
3244*795d594fSAndroid Build Coastguard Worker 
3245*795d594fSAndroid Build Coastguard Worker     static constexpr size_t kSrc = 0;
3246*795d594fSAndroid Build Coastguard Worker     static constexpr size_t kSrcPos = 1;
3247*795d594fSAndroid Build Coastguard Worker     static constexpr size_t kDest = 2;
3248*795d594fSAndroid Build Coastguard Worker     static constexpr size_t kDestPos = 3;
3249*795d594fSAndroid Build Coastguard Worker     static constexpr size_t kLength = 4;
3250*795d594fSAndroid Build Coastguard Worker 
3251*795d594fSAndroid Build Coastguard Worker     if (!locations->InAt(kLength).IsConstant()) {
3252*795d594fSAndroid Build Coastguard Worker       // We may not have enough registers for all inputs and temps, so put the
3253*795d594fSAndroid Build Coastguard Worker       // non-const length explicitly to the same register as one of the temps.
3254*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(kLength, Location::RegisterLocation(ECX));
3255*795d594fSAndroid Build Coastguard Worker     }
3256*795d594fSAndroid Build Coastguard Worker 
3257*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
3258*795d594fSAndroid Build Coastguard Worker       // We need an additional temp in the slow path for holding the reference.
3259*795d594fSAndroid Build Coastguard Worker       if (locations->InAt(kSrcPos).IsConstant() ||
3260*795d594fSAndroid Build Coastguard Worker           locations->InAt(kDestPos).IsConstant() ||
3261*795d594fSAndroid Build Coastguard Worker           IsSameInput(invoke, kSrc, kDest) ||
3262*795d594fSAndroid Build Coastguard Worker           IsSameInput(invoke, kSrcPos, kDestPos)) {
3263*795d594fSAndroid Build Coastguard Worker         // We can allocate another temp register.
3264*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresRegister());
3265*795d594fSAndroid Build Coastguard Worker       } else {
3266*795d594fSAndroid Build Coastguard Worker         // Use the same fixed register for the non-const `src_pos` and the additional temp.
3267*795d594fSAndroid Build Coastguard Worker         // The `src_pos` is no longer needed when we reach the slow path.
3268*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(kSrcPos, Location::RegisterLocation(EDX));
3269*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RegisterLocation(EDX));
3270*795d594fSAndroid Build Coastguard Worker       }
3271*795d594fSAndroid Build Coastguard Worker     }
3272*795d594fSAndroid Build Coastguard Worker   }
3273*795d594fSAndroid Build Coastguard Worker }
3274*795d594fSAndroid Build Coastguard Worker 
VisitSystemArrayCopy(HInvoke * invoke)3275*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitSystemArrayCopy(HInvoke* invoke) {
3276*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
3277*795d594fSAndroid Build Coastguard Worker   // SystemArrayCopy intrinsic is the Baker-style read barriers.
3278*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
3279*795d594fSAndroid Build Coastguard Worker 
3280*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3281*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3282*795d594fSAndroid Build Coastguard Worker 
3283*795d594fSAndroid Build Coastguard Worker   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3284*795d594fSAndroid Build Coastguard Worker   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3285*795d594fSAndroid Build Coastguard Worker   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3286*795d594fSAndroid Build Coastguard Worker   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
3287*795d594fSAndroid Build Coastguard Worker   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
3288*795d594fSAndroid Build Coastguard Worker 
3289*795d594fSAndroid Build Coastguard Worker   Register src = locations->InAt(0).AsRegister<Register>();
3290*795d594fSAndroid Build Coastguard Worker   Location src_pos = locations->InAt(1);
3291*795d594fSAndroid Build Coastguard Worker   Register dest = locations->InAt(2).AsRegister<Register>();
3292*795d594fSAndroid Build Coastguard Worker   Location dest_pos = locations->InAt(3);
3293*795d594fSAndroid Build Coastguard Worker   Location length = locations->InAt(4);
3294*795d594fSAndroid Build Coastguard Worker   Location temp1_loc = locations->GetTemp(0);
3295*795d594fSAndroid Build Coastguard Worker   Register temp1 = temp1_loc.AsRegister<Register>();
3296*795d594fSAndroid Build Coastguard Worker   Location temp2_loc = locations->GetTemp(1);
3297*795d594fSAndroid Build Coastguard Worker   Register temp2 = temp2_loc.AsRegister<Register>();
3298*795d594fSAndroid Build Coastguard Worker 
3299*795d594fSAndroid Build Coastguard Worker   SlowPathCode* intrinsic_slow_path =
3300*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
3301*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(intrinsic_slow_path);
3302*795d594fSAndroid Build Coastguard Worker 
3303*795d594fSAndroid Build Coastguard Worker   NearLabel conditions_on_positions_validated;
3304*795d594fSAndroid Build Coastguard Worker   SystemArrayCopyOptimizations optimizations(invoke);
3305*795d594fSAndroid Build Coastguard Worker 
3306*795d594fSAndroid Build Coastguard Worker   // If source and destination are the same, we go to slow path if we need to do forward copying.
3307*795d594fSAndroid Build Coastguard Worker   // We do not need to do this check if the source and destination positions are the same.
3308*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSourcePositionIsDestinationPosition()) {
3309*795d594fSAndroid Build Coastguard Worker     if (src_pos.IsConstant()) {
3310*795d594fSAndroid Build Coastguard Worker       int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
3311*795d594fSAndroid Build Coastguard Worker       if (dest_pos.IsConstant()) {
3312*795d594fSAndroid Build Coastguard Worker         int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
3313*795d594fSAndroid Build Coastguard Worker         if (optimizations.GetDestinationIsSource()) {
3314*795d594fSAndroid Build Coastguard Worker           // Checked when building locations.
3315*795d594fSAndroid Build Coastguard Worker           DCHECK_GE(src_pos_constant, dest_pos_constant);
3316*795d594fSAndroid Build Coastguard Worker         } else if (src_pos_constant < dest_pos_constant) {
3317*795d594fSAndroid Build Coastguard Worker           __ cmpl(src, dest);
3318*795d594fSAndroid Build Coastguard Worker           __ j(kEqual, intrinsic_slow_path->GetEntryLabel());
3319*795d594fSAndroid Build Coastguard Worker         }
3320*795d594fSAndroid Build Coastguard Worker       } else {
3321*795d594fSAndroid Build Coastguard Worker         if (!optimizations.GetDestinationIsSource()) {
3322*795d594fSAndroid Build Coastguard Worker           __ cmpl(src, dest);
3323*795d594fSAndroid Build Coastguard Worker           __ j(kNotEqual, &conditions_on_positions_validated);
3324*795d594fSAndroid Build Coastguard Worker         }
3325*795d594fSAndroid Build Coastguard Worker         __ cmpl(dest_pos.AsRegister<Register>(), Immediate(src_pos_constant));
3326*795d594fSAndroid Build Coastguard Worker         __ j(kGreater, intrinsic_slow_path->GetEntryLabel());
3327*795d594fSAndroid Build Coastguard Worker       }
3328*795d594fSAndroid Build Coastguard Worker     } else {
3329*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetDestinationIsSource()) {
3330*795d594fSAndroid Build Coastguard Worker         __ cmpl(src, dest);
3331*795d594fSAndroid Build Coastguard Worker         __ j(kNotEqual, &conditions_on_positions_validated);
3332*795d594fSAndroid Build Coastguard Worker       }
3333*795d594fSAndroid Build Coastguard Worker       Register src_pos_reg = src_pos.AsRegister<Register>();
3334*795d594fSAndroid Build Coastguard Worker       EmitCmplJLess(assembler, src_pos_reg, dest_pos, intrinsic_slow_path->GetEntryLabel());
3335*795d594fSAndroid Build Coastguard Worker     }
3336*795d594fSAndroid Build Coastguard Worker   }
3337*795d594fSAndroid Build Coastguard Worker 
3338*795d594fSAndroid Build Coastguard Worker   __ Bind(&conditions_on_positions_validated);
3339*795d594fSAndroid Build Coastguard Worker 
3340*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSourceIsNotNull()) {
3341*795d594fSAndroid Build Coastguard Worker     // Bail out if the source is null.
3342*795d594fSAndroid Build Coastguard Worker     __ testl(src, src);
3343*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, intrinsic_slow_path->GetEntryLabel());
3344*795d594fSAndroid Build Coastguard Worker   }
3345*795d594fSAndroid Build Coastguard Worker 
3346*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
3347*795d594fSAndroid Build Coastguard Worker     // Bail out if the destination is null.
3348*795d594fSAndroid Build Coastguard Worker     __ testl(dest, dest);
3349*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, intrinsic_slow_path->GetEntryLabel());
3350*795d594fSAndroid Build Coastguard Worker   }
3351*795d594fSAndroid Build Coastguard Worker 
3352*795d594fSAndroid Build Coastguard Worker   // If the length is negative, bail out.
3353*795d594fSAndroid Build Coastguard Worker   // We have already checked in the LocationsBuilder for the constant case.
3354*795d594fSAndroid Build Coastguard Worker   if (!length.IsConstant() &&
3355*795d594fSAndroid Build Coastguard Worker       !optimizations.GetCountIsSourceLength() &&
3356*795d594fSAndroid Build Coastguard Worker       !optimizations.GetCountIsDestinationLength()) {
3357*795d594fSAndroid Build Coastguard Worker     __ testl(length.AsRegister<Register>(), length.AsRegister<Register>());
3358*795d594fSAndroid Build Coastguard Worker     __ j(kLess, intrinsic_slow_path->GetEntryLabel());
3359*795d594fSAndroid Build Coastguard Worker   }
3360*795d594fSAndroid Build Coastguard Worker 
3361*795d594fSAndroid Build Coastguard Worker   // Validity checks: source.
3362*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(assembler,
3363*795d594fSAndroid Build Coastguard Worker                                src,
3364*795d594fSAndroid Build Coastguard Worker                                src_pos,
3365*795d594fSAndroid Build Coastguard Worker                                length,
3366*795d594fSAndroid Build Coastguard Worker                                intrinsic_slow_path,
3367*795d594fSAndroid Build Coastguard Worker                                temp1,
3368*795d594fSAndroid Build Coastguard Worker                                optimizations.GetCountIsSourceLength(),
3369*795d594fSAndroid Build Coastguard Worker                                /*position_sign_checked=*/ false);
3370*795d594fSAndroid Build Coastguard Worker 
3371*795d594fSAndroid Build Coastguard Worker   // Validity checks: dest.
3372*795d594fSAndroid Build Coastguard Worker   bool dest_position_sign_checked = optimizations.GetSourcePositionIsDestinationPosition();
3373*795d594fSAndroid Build Coastguard Worker   CheckSystemArrayCopyPosition(assembler,
3374*795d594fSAndroid Build Coastguard Worker                                dest,
3375*795d594fSAndroid Build Coastguard Worker                                dest_pos,
3376*795d594fSAndroid Build Coastguard Worker                                length,
3377*795d594fSAndroid Build Coastguard Worker                                intrinsic_slow_path,
3378*795d594fSAndroid Build Coastguard Worker                                temp1,
3379*795d594fSAndroid Build Coastguard Worker                                optimizations.GetCountIsDestinationLength(),
3380*795d594fSAndroid Build Coastguard Worker                                dest_position_sign_checked);
3381*795d594fSAndroid Build Coastguard Worker 
3382*795d594fSAndroid Build Coastguard Worker   auto check_non_primitive_array_class = [&](Register klass, Register temp) {
3383*795d594fSAndroid Build Coastguard Worker     // No read barrier is needed for reading a chain of constant references for comparing
3384*795d594fSAndroid Build Coastguard Worker     // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
3385*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp = klass->component_type_
3386*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(klass, component_offset));
3387*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(temp);
3388*795d594fSAndroid Build Coastguard Worker     // Check that the component type is not null.
3389*795d594fSAndroid Build Coastguard Worker     __ testl(temp, temp);
3390*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, intrinsic_slow_path->GetEntryLabel());
3391*795d594fSAndroid Build Coastguard Worker     // Check that the component type is not a primitive.
3392*795d594fSAndroid Build Coastguard Worker     __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
3393*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, intrinsic_slow_path->GetEntryLabel());
3394*795d594fSAndroid Build Coastguard Worker   };
3395*795d594fSAndroid Build Coastguard Worker 
3396*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetDoesNotNeedTypeCheck()) {
3397*795d594fSAndroid Build Coastguard Worker     // Check whether all elements of the source array are assignable to the component
3398*795d594fSAndroid Build Coastguard Worker     // type of the destination array. We do two checks: the classes are the same,
3399*795d594fSAndroid Build Coastguard Worker     // or the destination is Object[]. If none of these checks succeed, we go to the
3400*795d594fSAndroid Build Coastguard Worker     // slow path.
3401*795d594fSAndroid Build Coastguard Worker 
3402*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
3403*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = dest->klass_
3404*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(
3405*795d594fSAndroid Build Coastguard Worker           invoke, temp1_loc, dest, class_offset, /* needs_null_check= */ false);
3406*795d594fSAndroid Build Coastguard Worker       // Register `temp1` is not trashed by the read barrier emitted
3407*795d594fSAndroid Build Coastguard Worker       // by GenerateFieldLoadWithBakerReadBarrier below, as that
3408*795d594fSAndroid Build Coastguard Worker       // method produces a call to a ReadBarrierMarkRegX entry point,
3409*795d594fSAndroid Build Coastguard Worker       // which saves all potentially live registers, including
3410*795d594fSAndroid Build Coastguard Worker       // temporaries such a `temp1`.
3411*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp2 = src->klass_
3412*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(
3413*795d594fSAndroid Build Coastguard Worker           invoke, temp2_loc, src, class_offset, /* needs_null_check= */ false);
3414*795d594fSAndroid Build Coastguard Worker     } else {
3415*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = dest->klass_
3416*795d594fSAndroid Build Coastguard Worker       __ movl(temp1, Address(dest, class_offset));
3417*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(temp1);
3418*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp2 = src->klass_
3419*795d594fSAndroid Build Coastguard Worker       __ movl(temp2, Address(src, class_offset));
3420*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(temp2);
3421*795d594fSAndroid Build Coastguard Worker     }
3422*795d594fSAndroid Build Coastguard Worker 
3423*795d594fSAndroid Build Coastguard Worker     __ cmpl(temp1, temp2);
3424*795d594fSAndroid Build Coastguard Worker     if (optimizations.GetDestinationIsTypedObjectArray()) {
3425*795d594fSAndroid Build Coastguard Worker       DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
3426*795d594fSAndroid Build Coastguard Worker       NearLabel do_copy;
3427*795d594fSAndroid Build Coastguard Worker       // For class match, we can skip the source type check regardless of the optimization flag.
3428*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &do_copy);
3429*795d594fSAndroid Build Coastguard Worker       // No read barrier is needed for reading a chain of constant references
3430*795d594fSAndroid Build Coastguard Worker       // for comparing with null, see `ReadBarrierOption`.
3431*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp1 = temp1->component_type_
3432*795d594fSAndroid Build Coastguard Worker       __ movl(temp1, Address(temp1, component_offset));
3433*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(temp1);
3434*795d594fSAndroid Build Coastguard Worker       // No need to unpoison the following heap reference load, as
3435*795d594fSAndroid Build Coastguard Worker       // we're comparing against null.
3436*795d594fSAndroid Build Coastguard Worker       __ cmpl(Address(temp1, super_offset), Immediate(0));
3437*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, intrinsic_slow_path->GetEntryLabel());
3438*795d594fSAndroid Build Coastguard Worker       // Bail out if the source is not a non primitive array.
3439*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetSourceIsNonPrimitiveArray()) {
3440*795d594fSAndroid Build Coastguard Worker         check_non_primitive_array_class(temp2, temp2);
3441*795d594fSAndroid Build Coastguard Worker       }
3442*795d594fSAndroid Build Coastguard Worker       __ Bind(&do_copy);
3443*795d594fSAndroid Build Coastguard Worker     } else {
3444*795d594fSAndroid Build Coastguard Worker       DCHECK(!optimizations.GetDestinationIsTypedObjectArray());
3445*795d594fSAndroid Build Coastguard Worker       // For class match, we can skip the array type check completely if at least one of source
3446*795d594fSAndroid Build Coastguard Worker       // and destination is known to be a non primitive array, otherwise one check is enough.
3447*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, intrinsic_slow_path->GetEntryLabel());
3448*795d594fSAndroid Build Coastguard Worker       if (!optimizations.GetDestinationIsNonPrimitiveArray() &&
3449*795d594fSAndroid Build Coastguard Worker           !optimizations.GetSourceIsNonPrimitiveArray()) {
3450*795d594fSAndroid Build Coastguard Worker         check_non_primitive_array_class(temp2, temp2);
3451*795d594fSAndroid Build Coastguard Worker       }
3452*795d594fSAndroid Build Coastguard Worker     }
3453*795d594fSAndroid Build Coastguard Worker   } else if (!optimizations.GetSourceIsNonPrimitiveArray()) {
3454*795d594fSAndroid Build Coastguard Worker     DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
3455*795d594fSAndroid Build Coastguard Worker     // Bail out if the source is not a non primitive array.
3456*795d594fSAndroid Build Coastguard Worker     // No read barrier is needed for reading a chain of constant references for comparing
3457*795d594fSAndroid Build Coastguard Worker     // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
3458*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp1 = src->klass_
3459*795d594fSAndroid Build Coastguard Worker     __ movl(temp1, Address(src, class_offset));
3460*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(temp1);
3461*795d594fSAndroid Build Coastguard Worker     check_non_primitive_array_class(temp1, temp1);
3462*795d594fSAndroid Build Coastguard Worker   }
3463*795d594fSAndroid Build Coastguard Worker 
3464*795d594fSAndroid Build Coastguard Worker   if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) {
3465*795d594fSAndroid Build Coastguard Worker     // Null constant length: not need to emit the loop code at all.
3466*795d594fSAndroid Build Coastguard Worker   } else {
3467*795d594fSAndroid Build Coastguard Worker     const DataType::Type type = DataType::Type::kReference;
3468*795d594fSAndroid Build Coastguard Worker     const size_t data_size = DataType::Size(type);
3469*795d594fSAndroid Build Coastguard Worker     const uint32_t data_offset = mirror::Array::DataOffset(data_size).Uint32Value();
3470*795d594fSAndroid Build Coastguard Worker 
3471*795d594fSAndroid Build Coastguard Worker     // Don't enter copy loop if `length == 0`.
3472*795d594fSAndroid Build Coastguard Worker     NearLabel skip_copy_and_write_barrier;
3473*795d594fSAndroid Build Coastguard Worker     if (!length.IsConstant()) {
3474*795d594fSAndroid Build Coastguard Worker       __ testl(length.AsRegister<Register>(), length.AsRegister<Register>());
3475*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &skip_copy_and_write_barrier);
3476*795d594fSAndroid Build Coastguard Worker     }
3477*795d594fSAndroid Build Coastguard Worker 
3478*795d594fSAndroid Build Coastguard Worker     // Compute the base source address in `temp1`.
3479*795d594fSAndroid Build Coastguard Worker     GenArrayAddress(assembler, temp1, src, src_pos, type, data_offset);
3480*795d594fSAndroid Build Coastguard Worker     // Compute the base destination address in `temp2`.
3481*795d594fSAndroid Build Coastguard Worker     GenArrayAddress(assembler, temp2, dest, dest_pos, type, data_offset);
3482*795d594fSAndroid Build Coastguard Worker 
3483*795d594fSAndroid Build Coastguard Worker     SlowPathCode* read_barrier_slow_path = nullptr;
3484*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
3485*795d594fSAndroid Build Coastguard Worker       // SystemArrayCopy implementation for Baker read barriers (see
3486*795d594fSAndroid Build Coastguard Worker       // also CodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier):
3487*795d594fSAndroid Build Coastguard Worker       //
3488*795d594fSAndroid Build Coastguard Worker       //   if (src_ptr != end_ptr) {
3489*795d594fSAndroid Build Coastguard Worker       //     uint32_t rb_state = Lockword(src->monitor_).ReadBarrierState();
3490*795d594fSAndroid Build Coastguard Worker       //     lfence;  // Load fence or artificial data dependency to prevent load-load reordering
3491*795d594fSAndroid Build Coastguard Worker       //     bool is_gray = (rb_state == ReadBarrier::GrayState());
3492*795d594fSAndroid Build Coastguard Worker       //     if (is_gray) {
3493*795d594fSAndroid Build Coastguard Worker       //       // Slow-path copy.
3494*795d594fSAndroid Build Coastguard Worker       //       for (size_t i = 0; i != length; ++i) {
3495*795d594fSAndroid Build Coastguard Worker       //         dest_array[dest_pos + i] =
3496*795d594fSAndroid Build Coastguard Worker       //             MaybePoison(ReadBarrier::Mark(MaybeUnpoison(src_array[src_pos + i])));
3497*795d594fSAndroid Build Coastguard Worker       //       }
3498*795d594fSAndroid Build Coastguard Worker       //     } else {
3499*795d594fSAndroid Build Coastguard Worker       //       // Fast-path copy.
3500*795d594fSAndroid Build Coastguard Worker       //       do {
3501*795d594fSAndroid Build Coastguard Worker       //         *dest_ptr++ = *src_ptr++;
3502*795d594fSAndroid Build Coastguard Worker       //       } while (src_ptr != end_ptr)
3503*795d594fSAndroid Build Coastguard Worker       //     }
3504*795d594fSAndroid Build Coastguard Worker       //   }
3505*795d594fSAndroid Build Coastguard Worker 
3506*795d594fSAndroid Build Coastguard Worker       // Given the numeric representation, it's enough to check the low bit of the rb_state.
3507*795d594fSAndroid Build Coastguard Worker       static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
3508*795d594fSAndroid Build Coastguard Worker       static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
3509*795d594fSAndroid Build Coastguard Worker       constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
3510*795d594fSAndroid Build Coastguard Worker       constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
3511*795d594fSAndroid Build Coastguard Worker       constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
3512*795d594fSAndroid Build Coastguard Worker 
3513*795d594fSAndroid Build Coastguard Worker       // if (rb_state == ReadBarrier::GrayState())
3514*795d594fSAndroid Build Coastguard Worker       //   goto slow_path;
3515*795d594fSAndroid Build Coastguard Worker       // At this point, just do the "if" and make sure that flags are preserved until the branch.
3516*795d594fSAndroid Build Coastguard Worker       __ testb(Address(src, monitor_offset + gray_byte_position), Immediate(test_value));
3517*795d594fSAndroid Build Coastguard Worker 
3518*795d594fSAndroid Build Coastguard Worker       // Load fence to prevent load-load reordering.
3519*795d594fSAndroid Build Coastguard Worker       // Note that this is a no-op, thanks to the x86 memory model.
3520*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3521*795d594fSAndroid Build Coastguard Worker 
3522*795d594fSAndroid Build Coastguard Worker       // Slow path used to copy array when `src` is gray.
3523*795d594fSAndroid Build Coastguard Worker       read_barrier_slow_path =
3524*795d594fSAndroid Build Coastguard Worker           new (codegen_->GetScopedAllocator()) ReadBarrierSystemArrayCopySlowPathX86(invoke);
3525*795d594fSAndroid Build Coastguard Worker       codegen_->AddSlowPath(read_barrier_slow_path);
3526*795d594fSAndroid Build Coastguard Worker 
3527*795d594fSAndroid Build Coastguard Worker       // We have done the "if" of the gray bit check above, now branch based on the flags.
3528*795d594fSAndroid Build Coastguard Worker       __ j(kNotZero, read_barrier_slow_path->GetEntryLabel());
3529*795d594fSAndroid Build Coastguard Worker     }
3530*795d594fSAndroid Build Coastguard Worker 
3531*795d594fSAndroid Build Coastguard Worker     Register temp3 = locations->GetTemp(2).AsRegister<Register>();
3532*795d594fSAndroid Build Coastguard Worker     if (length.IsConstant()) {
3533*795d594fSAndroid Build Coastguard Worker       __ movl(temp3, Immediate(length.GetConstant()->AsIntConstant()->GetValue()));
3534*795d594fSAndroid Build Coastguard Worker     } else {
3535*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(temp3, length.AsRegister<Register>());
3536*795d594fSAndroid Build Coastguard Worker     }
3537*795d594fSAndroid Build Coastguard Worker 
3538*795d594fSAndroid Build Coastguard Worker     // Iterate over the arrays and do a raw copy of the objects. We don't need to poison/unpoison.
3539*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(temp1, ESI);
3540*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(temp2, EDI);
3541*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(temp3, ECX);
3542*795d594fSAndroid Build Coastguard Worker     __ rep_movsl();
3543*795d594fSAndroid Build Coastguard Worker 
3544*795d594fSAndroid Build Coastguard Worker     if (read_barrier_slow_path != nullptr) {
3545*795d594fSAndroid Build Coastguard Worker       DCHECK(codegen_->EmitBakerReadBarrier());
3546*795d594fSAndroid Build Coastguard Worker       __ Bind(read_barrier_slow_path->GetExitLabel());
3547*795d594fSAndroid Build Coastguard Worker     }
3548*795d594fSAndroid Build Coastguard Worker 
3549*795d594fSAndroid Build Coastguard Worker     // We only need one card marking on the destination array.
3550*795d594fSAndroid Build Coastguard Worker     codegen_->MarkGCCard(temp1, temp3, dest);
3551*795d594fSAndroid Build Coastguard Worker 
3552*795d594fSAndroid Build Coastguard Worker     __ Bind(&skip_copy_and_write_barrier);
3553*795d594fSAndroid Build Coastguard Worker   }
3554*795d594fSAndroid Build Coastguard Worker 
3555*795d594fSAndroid Build Coastguard Worker   __ Bind(intrinsic_slow_path->GetExitLabel());
3556*795d594fSAndroid Build Coastguard Worker }
3557*795d594fSAndroid Build Coastguard Worker 
RequestBaseMethodAddressInRegister(HInvoke * invoke)3558*795d594fSAndroid Build Coastguard Worker static void RequestBaseMethodAddressInRegister(HInvoke* invoke) {
3559*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3560*795d594fSAndroid Build Coastguard Worker   if (locations != nullptr) {
3561*795d594fSAndroid Build Coastguard Worker     HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
3562*795d594fSAndroid Build Coastguard Worker     // Note: The base method address is not present yet when this is called from the
3563*795d594fSAndroid Build Coastguard Worker     // PCRelativeHandlerVisitor via IsCallFreeIntrinsic() to determine whether to insert it.
3564*795d594fSAndroid Build Coastguard Worker     if (invoke_static_or_direct->HasSpecialInput()) {
3565*795d594fSAndroid Build Coastguard Worker       DCHECK(invoke_static_or_direct->InputAt(invoke_static_or_direct->GetSpecialInputIndex())
3566*795d594fSAndroid Build Coastguard Worker                  ->IsX86ComputeBaseMethodAddress());
3567*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(invoke_static_or_direct->GetSpecialInputIndex(),
3568*795d594fSAndroid Build Coastguard Worker                          Location::RequiresRegister());
3569*795d594fSAndroid Build Coastguard Worker     }
3570*795d594fSAndroid Build Coastguard Worker   }
3571*795d594fSAndroid Build Coastguard Worker }
3572*795d594fSAndroid Build Coastguard Worker 
3573*795d594fSAndroid Build Coastguard Worker #define VISIT_INTRINSIC(name, low, high, type, start_index)                              \
3574*795d594fSAndroid Build Coastguard Worker   void IntrinsicLocationsBuilderX86::Visit##name##ValueOf(HInvoke* invoke) {             \
3575*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;                                   \
3576*795d594fSAndroid Build Coastguard Worker     IntrinsicVisitor::ComputeValueOfLocations(                                           \
3577*795d594fSAndroid Build Coastguard Worker         invoke,                                                                          \
3578*795d594fSAndroid Build Coastguard Worker         codegen_,                                                                        \
3579*795d594fSAndroid Build Coastguard Worker         low,                                                                             \
3580*795d594fSAndroid Build Coastguard Worker         (high) - (low) + 1,                                                              \
3581*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(EAX),                                                 \
3582*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(0)));                \
3583*795d594fSAndroid Build Coastguard Worker     RequestBaseMethodAddressInRegister(invoke);                                          \
3584*795d594fSAndroid Build Coastguard Worker   }                                                                                      \
3585*795d594fSAndroid Build Coastguard Worker   void IntrinsicCodeGeneratorX86::Visit##name##ValueOf(HInvoke* invoke) {                \
3586*795d594fSAndroid Build Coastguard Worker     IntrinsicVisitor::ValueOfInfo info =                                                 \
3587*795d594fSAndroid Build Coastguard Worker         IntrinsicVisitor::ComputeValueOfInfo(invoke,                                     \
3588*795d594fSAndroid Build Coastguard Worker                                              codegen_->GetCompilerOptions(),             \
3589*795d594fSAndroid Build Coastguard Worker                                              WellKnownClasses::java_lang_##name##_value, \
3590*795d594fSAndroid Build Coastguard Worker                                              low,                                        \
3591*795d594fSAndroid Build Coastguard Worker                                              (high) - (low) + 1,                         \
3592*795d594fSAndroid Build Coastguard Worker                                              start_index);                               \
3593*795d594fSAndroid Build Coastguard Worker     HandleValueOf(invoke, info, type);                                                   \
3594*795d594fSAndroid Build Coastguard Worker   }
BOXED_TYPES(VISIT_INTRINSIC)3595*795d594fSAndroid Build Coastguard Worker   BOXED_TYPES(VISIT_INTRINSIC)
3596*795d594fSAndroid Build Coastguard Worker #undef VISIT_INTRINSIC
3597*795d594fSAndroid Build Coastguard Worker 
3598*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::HandleValueOf(HInvoke* invoke,
3599*795d594fSAndroid Build Coastguard Worker                                               const IntrinsicVisitor::ValueOfInfo& info,
3600*795d594fSAndroid Build Coastguard Worker                                               DataType::Type type) {
3601*795d594fSAndroid Build Coastguard Worker   DCHECK(invoke->IsInvokeStaticOrDirect());
3602*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3603*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3604*795d594fSAndroid Build Coastguard Worker 
3605*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
3606*795d594fSAndroid Build Coastguard Worker   auto allocate_instance = [&]() {
3607*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(out, InvokeRuntimeCallingConvention().GetRegisterAt(0));
3608*795d594fSAndroid Build Coastguard Worker     codegen_->LoadIntrinsicDeclaringClass(out, invoke->AsInvokeStaticOrDirect());
3609*795d594fSAndroid Build Coastguard Worker     codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
3610*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
3611*795d594fSAndroid Build Coastguard Worker   };
3612*795d594fSAndroid Build Coastguard Worker   if (invoke->InputAt(0)->IsIntConstant()) {
3613*795d594fSAndroid Build Coastguard Worker     int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
3614*795d594fSAndroid Build Coastguard Worker     if (static_cast<uint32_t>(value - info.low) < info.length) {
3615*795d594fSAndroid Build Coastguard Worker       // Just embed the object in the code.
3616*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(info.value_boot_image_reference, ValueOfInfo::kInvalidReference);
3617*795d594fSAndroid Build Coastguard Worker       codegen_->LoadBootImageAddress(
3618*795d594fSAndroid Build Coastguard Worker           out, info.value_boot_image_reference, invoke->AsInvokeStaticOrDirect());
3619*795d594fSAndroid Build Coastguard Worker     } else {
3620*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->CanCall());
3621*795d594fSAndroid Build Coastguard Worker       // Allocate and initialize a new j.l.Integer.
3622*795d594fSAndroid Build Coastguard Worker       // TODO: If we JIT, we could allocate the object now, and store it in the
3623*795d594fSAndroid Build Coastguard Worker       // JIT object table.
3624*795d594fSAndroid Build Coastguard Worker       allocate_instance();
3625*795d594fSAndroid Build Coastguard Worker       codegen_->MoveToMemory(type,
3626*795d594fSAndroid Build Coastguard Worker                              Location::ConstantLocation(invoke->InputAt(0)->AsIntConstant()),
3627*795d594fSAndroid Build Coastguard Worker                              out,
3628*795d594fSAndroid Build Coastguard Worker                              /* dst_index= */ Register::kNoRegister,
3629*795d594fSAndroid Build Coastguard Worker                              /* dst_scale= */ TIMES_1,
3630*795d594fSAndroid Build Coastguard Worker                              /* dst_disp= */ info.value_offset);
3631*795d594fSAndroid Build Coastguard Worker     }
3632*795d594fSAndroid Build Coastguard Worker   } else {
3633*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
3634*795d594fSAndroid Build Coastguard Worker     Register in = locations->InAt(0).AsRegister<Register>();
3635*795d594fSAndroid Build Coastguard Worker     // Check bounds of our cache.
3636*795d594fSAndroid Build Coastguard Worker     __ leal(out, Address(in, -info.low));
3637*795d594fSAndroid Build Coastguard Worker     __ cmpl(out, Immediate(info.length));
3638*795d594fSAndroid Build Coastguard Worker     NearLabel allocate, done;
3639*795d594fSAndroid Build Coastguard Worker     __ j(kAboveEqual, &allocate);
3640*795d594fSAndroid Build Coastguard Worker     // If the value is within the bounds, load the object directly from the array.
3641*795d594fSAndroid Build Coastguard Worker     constexpr size_t kElementSize = sizeof(mirror::HeapReference<mirror::Object>);
3642*795d594fSAndroid Build Coastguard Worker     static_assert((1u << TIMES_4) == sizeof(mirror::HeapReference<mirror::Object>),
3643*795d594fSAndroid Build Coastguard Worker                   "Check heap reference size.");
3644*795d594fSAndroid Build Coastguard Worker     if (codegen_->GetCompilerOptions().IsBootImage()) {
3645*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
3646*795d594fSAndroid Build Coastguard Worker       size_t method_address_index = invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
3647*795d594fSAndroid Build Coastguard Worker       HX86ComputeBaseMethodAddress* method_address =
3648*795d594fSAndroid Build Coastguard Worker           invoke->InputAt(method_address_index)->AsX86ComputeBaseMethodAddress();
3649*795d594fSAndroid Build Coastguard Worker       DCHECK(method_address != nullptr);
3650*795d594fSAndroid Build Coastguard Worker       Register method_address_reg =
3651*795d594fSAndroid Build Coastguard Worker           invoke->GetLocations()->InAt(method_address_index).AsRegister<Register>();
3652*795d594fSAndroid Build Coastguard Worker       __ movl(out,
3653*795d594fSAndroid Build Coastguard Worker               Address(method_address_reg, out, TIMES_4, CodeGeneratorX86::kPlaceholder32BitOffset));
3654*795d594fSAndroid Build Coastguard Worker       codegen_->RecordBootImageIntrinsicPatch(method_address, info.array_data_boot_image_reference);
3655*795d594fSAndroid Build Coastguard Worker     } else {
3656*795d594fSAndroid Build Coastguard Worker       // Note: We're about to clobber the index in `out`, so we need to use `in` and
3657*795d594fSAndroid Build Coastguard Worker       // adjust the offset accordingly.
3658*795d594fSAndroid Build Coastguard Worker       uint32_t mid_array_boot_image_offset =
3659*795d594fSAndroid Build Coastguard Worker               info.array_data_boot_image_reference - info.low * kElementSize;
3660*795d594fSAndroid Build Coastguard Worker       codegen_->LoadBootImageAddress(
3661*795d594fSAndroid Build Coastguard Worker           out, mid_array_boot_image_offset, invoke->AsInvokeStaticOrDirect());
3662*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(out, in);
3663*795d594fSAndroid Build Coastguard Worker       __ movl(out, Address(out, in, TIMES_4, 0));
3664*795d594fSAndroid Build Coastguard Worker     }
3665*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(out);
3666*795d594fSAndroid Build Coastguard Worker     __ jmp(&done);
3667*795d594fSAndroid Build Coastguard Worker     __ Bind(&allocate);
3668*795d594fSAndroid Build Coastguard Worker     // Otherwise allocate and initialize a new object.
3669*795d594fSAndroid Build Coastguard Worker     allocate_instance();
3670*795d594fSAndroid Build Coastguard Worker     codegen_->MoveToMemory(type,
3671*795d594fSAndroid Build Coastguard Worker                            Location::RegisterLocation(in),
3672*795d594fSAndroid Build Coastguard Worker                            out,
3673*795d594fSAndroid Build Coastguard Worker                            /* dst_index= */ Register::kNoRegister,
3674*795d594fSAndroid Build Coastguard Worker                            /* dst_scale= */ TIMES_1,
3675*795d594fSAndroid Build Coastguard Worker                            /* dst_disp= */ info.value_offset);
3676*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
3677*795d594fSAndroid Build Coastguard Worker   }
3678*795d594fSAndroid Build Coastguard Worker }
3679*795d594fSAndroid Build Coastguard Worker 
VisitReferenceGetReferent(HInvoke * invoke)3680*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitReferenceGetReferent(HInvoke* invoke) {
3681*795d594fSAndroid Build Coastguard Worker   IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_);
3682*795d594fSAndroid Build Coastguard Worker   RequestBaseMethodAddressInRegister(invoke);
3683*795d594fSAndroid Build Coastguard Worker }
3684*795d594fSAndroid Build Coastguard Worker 
VisitReferenceGetReferent(HInvoke * invoke)3685*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitReferenceGetReferent(HInvoke* invoke) {
3686*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3687*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3688*795d594fSAndroid Build Coastguard Worker 
3689*795d594fSAndroid Build Coastguard Worker   Location obj = locations->InAt(0);
3690*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3691*795d594fSAndroid Build Coastguard Worker 
3692*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
3693*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
3694*795d594fSAndroid Build Coastguard Worker 
3695*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitReadBarrier()) {
3696*795d594fSAndroid Build Coastguard Worker     // Check self->GetWeakRefAccessEnabled().
3697*795d594fSAndroid Build Coastguard Worker     ThreadOffset32 offset = Thread::WeakRefAccessEnabledOffset<kX86PointerSize>();
3698*795d594fSAndroid Build Coastguard Worker     __ fs()->cmpl(Address::Absolute(offset),
3699*795d594fSAndroid Build Coastguard Worker                   Immediate(enum_cast<int32_t>(WeakRefAccessState::kVisiblyEnabled)));
3700*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, slow_path->GetEntryLabel());
3701*795d594fSAndroid Build Coastguard Worker   }
3702*795d594fSAndroid Build Coastguard Worker 
3703*795d594fSAndroid Build Coastguard Worker   // Load the java.lang.ref.Reference class, use the output register as a temporary.
3704*795d594fSAndroid Build Coastguard Worker   codegen_->LoadIntrinsicDeclaringClass(out.AsRegister<Register>(),
3705*795d594fSAndroid Build Coastguard Worker                                         invoke->AsInvokeStaticOrDirect());
3706*795d594fSAndroid Build Coastguard Worker 
3707*795d594fSAndroid Build Coastguard Worker   // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together.
3708*795d594fSAndroid Build Coastguard Worker   MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset();
3709*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u);
3710*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u,
3711*795d594fSAndroid Build Coastguard Worker             IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value());
3712*795d594fSAndroid Build Coastguard Worker   __ cmpw(Address(out.AsRegister<Register>(), disable_intrinsic_offset.Uint32Value()),
3713*795d594fSAndroid Build Coastguard Worker           Immediate(0));
3714*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, slow_path->GetEntryLabel());
3715*795d594fSAndroid Build Coastguard Worker 
3716*795d594fSAndroid Build Coastguard Worker   // Load the value from the field.
3717*795d594fSAndroid Build Coastguard Worker   uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
3718*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitBakerReadBarrier()) {
3719*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
3720*795d594fSAndroid Build Coastguard Worker                                                     out,
3721*795d594fSAndroid Build Coastguard Worker                                                     obj.AsRegister<Register>(),
3722*795d594fSAndroid Build Coastguard Worker                                                     referent_offset,
3723*795d594fSAndroid Build Coastguard Worker                                                     /*needs_null_check=*/ true);
3724*795d594fSAndroid Build Coastguard Worker     // Note that the fence is a no-op, thanks to the x86 memory model.
3725*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);  // `referent` is volatile.
3726*795d594fSAndroid Build Coastguard Worker   } else {
3727*795d594fSAndroid Build Coastguard Worker     __ movl(out.AsRegister<Register>(), Address(obj.AsRegister<Register>(), referent_offset));
3728*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeRecordImplicitNullCheck(invoke);
3729*795d594fSAndroid Build Coastguard Worker     // Note that the fence is a no-op, thanks to the x86 memory model.
3730*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);  // `referent` is volatile.
3731*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset);
3732*795d594fSAndroid Build Coastguard Worker   }
3733*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
3734*795d594fSAndroid Build Coastguard Worker }
3735*795d594fSAndroid Build Coastguard Worker 
VisitReferenceRefersTo(HInvoke * invoke)3736*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitReferenceRefersTo(HInvoke* invoke) {
3737*795d594fSAndroid Build Coastguard Worker   IntrinsicVisitor::CreateReferenceRefersToLocations(invoke, codegen_);
3738*795d594fSAndroid Build Coastguard Worker }
3739*795d594fSAndroid Build Coastguard Worker 
VisitReferenceRefersTo(HInvoke * invoke)3740*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitReferenceRefersTo(HInvoke* invoke) {
3741*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3742*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3743*795d594fSAndroid Build Coastguard Worker 
3744*795d594fSAndroid Build Coastguard Worker   Register obj = locations->InAt(0).AsRegister<Register>();
3745*795d594fSAndroid Build Coastguard Worker   Register other = locations->InAt(1).AsRegister<Register>();
3746*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
3747*795d594fSAndroid Build Coastguard Worker 
3748*795d594fSAndroid Build Coastguard Worker   uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
3749*795d594fSAndroid Build Coastguard Worker   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
3750*795d594fSAndroid Build Coastguard Worker 
3751*795d594fSAndroid Build Coastguard Worker   __ movl(out, Address(obj, referent_offset));
3752*795d594fSAndroid Build Coastguard Worker   codegen_->MaybeRecordImplicitNullCheck(invoke);
3753*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(out);
3754*795d594fSAndroid Build Coastguard Worker   // Note that the fence is a no-op, thanks to the x86 memory model.
3755*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);  // `referent` is volatile.
3756*795d594fSAndroid Build Coastguard Worker 
3757*795d594fSAndroid Build Coastguard Worker   NearLabel end, return_true, return_false;
3758*795d594fSAndroid Build Coastguard Worker   __ cmpl(out, other);
3759*795d594fSAndroid Build Coastguard Worker 
3760*795d594fSAndroid Build Coastguard Worker   if (codegen_->EmitReadBarrier()) {
3761*795d594fSAndroid Build Coastguard Worker     DCHECK(kUseBakerReadBarrier);
3762*795d594fSAndroid Build Coastguard Worker 
3763*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &return_true);
3764*795d594fSAndroid Build Coastguard Worker 
3765*795d594fSAndroid Build Coastguard Worker     // Check if the loaded reference is null.
3766*795d594fSAndroid Build Coastguard Worker     __ testl(out, out);
3767*795d594fSAndroid Build Coastguard Worker     __ j(kZero, &return_false);
3768*795d594fSAndroid Build Coastguard Worker 
3769*795d594fSAndroid Build Coastguard Worker     // For correct memory visibility, we need a barrier before loading the lock word
3770*795d594fSAndroid Build Coastguard Worker     // but we already have the barrier emitted for volatile load above which is sufficient.
3771*795d594fSAndroid Build Coastguard Worker 
3772*795d594fSAndroid Build Coastguard Worker     // Load the lockword and check if it is a forwarding address.
3773*795d594fSAndroid Build Coastguard Worker     static_assert(LockWord::kStateShift == 30u);
3774*795d594fSAndroid Build Coastguard Worker     static_assert(LockWord::kStateForwardingAddress == 3u);
3775*795d594fSAndroid Build Coastguard Worker     __ movl(out, Address(out, monitor_offset));
3776*795d594fSAndroid Build Coastguard Worker     __ cmpl(out, Immediate(static_cast<int32_t>(0xc0000000)));
3777*795d594fSAndroid Build Coastguard Worker     __ j(kBelow, &return_false);
3778*795d594fSAndroid Build Coastguard Worker 
3779*795d594fSAndroid Build Coastguard Worker     // Extract the forwarding address and compare with `other`.
3780*795d594fSAndroid Build Coastguard Worker     __ shll(out, Immediate(LockWord::kForwardingAddressShift));
3781*795d594fSAndroid Build Coastguard Worker     __ cmpl(out, other);
3782*795d594fSAndroid Build Coastguard Worker   }
3783*795d594fSAndroid Build Coastguard Worker 
3784*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &return_false);
3785*795d594fSAndroid Build Coastguard Worker 
3786*795d594fSAndroid Build Coastguard Worker   // Return true and exit the function.
3787*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_true);
3788*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(1));
3789*795d594fSAndroid Build Coastguard Worker   __ jmp(&end);
3790*795d594fSAndroid Build Coastguard Worker 
3791*795d594fSAndroid Build Coastguard Worker   // Return false and exit the function.
3792*795d594fSAndroid Build Coastguard Worker   __ Bind(&return_false);
3793*795d594fSAndroid Build Coastguard Worker   __ xorl(out, out);
3794*795d594fSAndroid Build Coastguard Worker   __ Bind(&end);
3795*795d594fSAndroid Build Coastguard Worker }
3796*795d594fSAndroid Build Coastguard Worker 
VisitThreadInterrupted(HInvoke * invoke)3797*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitThreadInterrupted(HInvoke* invoke) {
3798*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3799*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3800*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
3801*795d594fSAndroid Build Coastguard Worker }
3802*795d594fSAndroid Build Coastguard Worker 
VisitThreadInterrupted(HInvoke * invoke)3803*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitThreadInterrupted(HInvoke* invoke) {
3804*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3805*795d594fSAndroid Build Coastguard Worker   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
3806*795d594fSAndroid Build Coastguard Worker   Address address = Address::Absolute(Thread::InterruptedOffset<kX86PointerSize>().Int32Value());
3807*795d594fSAndroid Build Coastguard Worker   NearLabel done;
3808*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(out, address);
3809*795d594fSAndroid Build Coastguard Worker   __ testl(out, out);
3810*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
3811*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(address, Immediate(0));
3812*795d594fSAndroid Build Coastguard Worker   codegen_->MemoryFence();
3813*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
3814*795d594fSAndroid Build Coastguard Worker }
3815*795d594fSAndroid Build Coastguard Worker 
VisitReachabilityFence(HInvoke * invoke)3816*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitReachabilityFence(HInvoke* invoke) {
3817*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3818*795d594fSAndroid Build Coastguard Worker       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
3819*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::Any());
3820*795d594fSAndroid Build Coastguard Worker }
3821*795d594fSAndroid Build Coastguard Worker 
VisitReachabilityFence(HInvoke * invoke)3822*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitReachabilityFence([[maybe_unused]] HInvoke* invoke) {}
3823*795d594fSAndroid Build Coastguard Worker 
VisitIntegerDivideUnsigned(HInvoke * invoke)3824*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitIntegerDivideUnsigned(HInvoke* invoke) {
3825*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator_) LocationSummary(invoke,
3826*795d594fSAndroid Build Coastguard Worker                                                                 LocationSummary::kCallOnSlowPath,
3827*795d594fSAndroid Build Coastguard Worker                                                                 kIntrinsified);
3828*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(EAX));
3829*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
3830*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
3831*795d594fSAndroid Build Coastguard Worker   // Intel uses edx:eax as the dividend.
3832*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDX));
3833*795d594fSAndroid Build Coastguard Worker }
3834*795d594fSAndroid Build Coastguard Worker 
VisitIntegerDivideUnsigned(HInvoke * invoke)3835*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitIntegerDivideUnsigned(HInvoke* invoke) {
3836*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
3837*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3838*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3839*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
3840*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
3841*795d594fSAndroid Build Coastguard Worker   Register edx = locations->GetTemp(0).AsRegister<Register>();
3842*795d594fSAndroid Build Coastguard Worker   Register second_reg = second.AsRegister<Register>();
3843*795d594fSAndroid Build Coastguard Worker 
3844*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EAX, first.AsRegister<Register>());
3845*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EAX, out.AsRegister<Register>());
3846*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EDX, edx);
3847*795d594fSAndroid Build Coastguard Worker 
3848*795d594fSAndroid Build Coastguard Worker   // Check if divisor is zero, bail to managed implementation to handle.
3849*795d594fSAndroid Build Coastguard Worker   __ testl(second_reg, second_reg);
3850*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
3851*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
3852*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
3853*795d594fSAndroid Build Coastguard Worker 
3854*795d594fSAndroid Build Coastguard Worker   __ xorl(edx, edx);
3855*795d594fSAndroid Build Coastguard Worker   __ divl(second_reg);
3856*795d594fSAndroid Build Coastguard Worker 
3857*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
3858*795d594fSAndroid Build Coastguard Worker }
3859*795d594fSAndroid Build Coastguard Worker 
HasVarHandleIntrinsicImplementation(HInvoke * invoke)3860*795d594fSAndroid Build Coastguard Worker static bool HasVarHandleIntrinsicImplementation(HInvoke* invoke) {
3861*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
3862*795d594fSAndroid Build Coastguard Worker   if (optimizations.GetDoNotIntrinsify()) {
3863*795d594fSAndroid Build Coastguard Worker     return false;
3864*795d594fSAndroid Build Coastguard Worker   }
3865*795d594fSAndroid Build Coastguard Worker 
3866*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3867*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(expected_coordinates_count, 2u);  // Filtered by the `DoNotIntrinsify` flag above.
3868*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count > 1u) {
3869*795d594fSAndroid Build Coastguard Worker     // Only static and instance fields VarHandle are supported now.
3870*795d594fSAndroid Build Coastguard Worker     // TODO: add support for arrays and views.
3871*795d594fSAndroid Build Coastguard Worker     return false;
3872*795d594fSAndroid Build Coastguard Worker   }
3873*795d594fSAndroid Build Coastguard Worker 
3874*795d594fSAndroid Build Coastguard Worker   return true;
3875*795d594fSAndroid Build Coastguard Worker }
3876*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleAccessModeCheck(Register varhandle_object,mirror::VarHandle::AccessMode access_mode,SlowPathCode * slow_path,X86Assembler * assembler)3877*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleAccessModeCheck(Register varhandle_object,
3878*795d594fSAndroid Build Coastguard Worker                                              mirror::VarHandle::AccessMode access_mode,
3879*795d594fSAndroid Build Coastguard Worker                                              SlowPathCode* slow_path,
3880*795d594fSAndroid Build Coastguard Worker                                              X86Assembler* assembler) {
3881*795d594fSAndroid Build Coastguard Worker   const uint32_t access_modes_bitmask_offset =
3882*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::AccessModesBitMaskOffset().Uint32Value();
3883*795d594fSAndroid Build Coastguard Worker   const uint32_t access_mode_bit = 1u << static_cast<uint32_t>(access_mode);
3884*795d594fSAndroid Build Coastguard Worker 
3885*795d594fSAndroid Build Coastguard Worker   // If the access mode is not supported, bail to runtime implementation to handle
3886*795d594fSAndroid Build Coastguard Worker   __ testl(Address(varhandle_object, access_modes_bitmask_offset), Immediate(access_mode_bit));
3887*795d594fSAndroid Build Coastguard Worker   __ j(kZero, slow_path->GetEntryLabel());
3888*795d594fSAndroid Build Coastguard Worker }
3889*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleStaticFieldCheck(Register varhandle_object,SlowPathCode * slow_path,X86Assembler * assembler)3890*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleStaticFieldCheck(Register varhandle_object,
3891*795d594fSAndroid Build Coastguard Worker                                               SlowPathCode* slow_path,
3892*795d594fSAndroid Build Coastguard Worker                                               X86Assembler* assembler) {
3893*795d594fSAndroid Build Coastguard Worker   const uint32_t coordtype0_offset = mirror::VarHandle::CoordinateType0Offset().Uint32Value();
3894*795d594fSAndroid Build Coastguard Worker 
3895*795d594fSAndroid Build Coastguard Worker   // Check that the VarHandle references a static field by checking that coordinateType0 == null.
3896*795d594fSAndroid Build Coastguard Worker   // Do not emit read barrier (or unpoison the reference) for comparing to null.
3897*795d594fSAndroid Build Coastguard Worker   __ cmpl(Address(varhandle_object, coordtype0_offset), Immediate(0));
3898*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, slow_path->GetEntryLabel());
3899*795d594fSAndroid Build Coastguard Worker }
3900*795d594fSAndroid Build Coastguard Worker 
GenerateSubTypeObjectCheck(Register object,Register temp,Address type_address,SlowPathCode * slow_path,X86Assembler * assembler,bool object_can_be_null=true)3901*795d594fSAndroid Build Coastguard Worker static void GenerateSubTypeObjectCheck(Register object,
3902*795d594fSAndroid Build Coastguard Worker                                        Register temp,
3903*795d594fSAndroid Build Coastguard Worker                                        Address type_address,
3904*795d594fSAndroid Build Coastguard Worker                                        SlowPathCode* slow_path,
3905*795d594fSAndroid Build Coastguard Worker                                        X86Assembler* assembler,
3906*795d594fSAndroid Build Coastguard Worker                                        bool object_can_be_null = true) {
3907*795d594fSAndroid Build Coastguard Worker   const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
3908*795d594fSAndroid Build Coastguard Worker   const uint32_t super_class_offset = mirror::Class::SuperClassOffset().Uint32Value();
3909*795d594fSAndroid Build Coastguard Worker   NearLabel check_type_compatibility, type_matched;
3910*795d594fSAndroid Build Coastguard Worker 
3911*795d594fSAndroid Build Coastguard Worker   // If the object is null, there is no need to check the type
3912*795d594fSAndroid Build Coastguard Worker   if (object_can_be_null) {
3913*795d594fSAndroid Build Coastguard Worker     __ testl(object, object);
3914*795d594fSAndroid Build Coastguard Worker     __ j(kZero, &type_matched);
3915*795d594fSAndroid Build Coastguard Worker   }
3916*795d594fSAndroid Build Coastguard Worker 
3917*795d594fSAndroid Build Coastguard Worker   // Do not unpoison for in-memory comparison.
3918*795d594fSAndroid Build Coastguard Worker   // We deliberately avoid the read barrier, letting the slow path handle the false negatives.
3919*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(object, class_offset));
3920*795d594fSAndroid Build Coastguard Worker   __ Bind(&check_type_compatibility);
3921*795d594fSAndroid Build Coastguard Worker   __ cmpl(temp, type_address);
3922*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &type_matched);
3923*795d594fSAndroid Build Coastguard Worker   // Load the super class.
3924*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(temp);
3925*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(temp, super_class_offset));
3926*795d594fSAndroid Build Coastguard Worker   // If the super class is null, we reached the root of the hierarchy without a match.
3927*795d594fSAndroid Build Coastguard Worker   // We let the slow path handle uncovered cases (e.g. interfaces).
3928*795d594fSAndroid Build Coastguard Worker   __ testl(temp, temp);
3929*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
3930*795d594fSAndroid Build Coastguard Worker   __ jmp(&check_type_compatibility);
3931*795d594fSAndroid Build Coastguard Worker   __ Bind(&type_matched);
3932*795d594fSAndroid Build Coastguard Worker }
3933*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleInstanceFieldChecks(HInvoke * invoke,Register temp,SlowPathCode * slow_path,X86Assembler * assembler)3934*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
3935*795d594fSAndroid Build Coastguard Worker                                                  Register temp,
3936*795d594fSAndroid Build Coastguard Worker                                                  SlowPathCode* slow_path,
3937*795d594fSAndroid Build Coastguard Worker                                                  X86Assembler* assembler) {
3938*795d594fSAndroid Build Coastguard Worker   VarHandleOptimizations optimizations(invoke);
3939*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3940*795d594fSAndroid Build Coastguard Worker   Register varhandle_object = locations->InAt(0).AsRegister<Register>();
3941*795d594fSAndroid Build Coastguard Worker   Register object = locations->InAt(1).AsRegister<Register>();
3942*795d594fSAndroid Build Coastguard Worker 
3943*795d594fSAndroid Build Coastguard Worker   const uint32_t coordtype0_offset = mirror::VarHandle::CoordinateType0Offset().Uint32Value();
3944*795d594fSAndroid Build Coastguard Worker   const uint32_t coordtype1_offset = mirror::VarHandle::CoordinateType1Offset().Uint32Value();
3945*795d594fSAndroid Build Coastguard Worker 
3946*795d594fSAndroid Build Coastguard Worker   // Check that the VarHandle references an instance field by checking that
3947*795d594fSAndroid Build Coastguard Worker   // coordinateType1 == null. coordinateType0 should be not null, but this is handled by the
3948*795d594fSAndroid Build Coastguard Worker   // type compatibility check with the source object's type, which will fail for null.
3949*795d594fSAndroid Build Coastguard Worker   __ cmpl(Address(varhandle_object, coordtype1_offset), Immediate(0));
3950*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, slow_path->GetEntryLabel());
3951*795d594fSAndroid Build Coastguard Worker 
3952*795d594fSAndroid Build Coastguard Worker   // Check if the object is null
3953*795d594fSAndroid Build Coastguard Worker   if (!optimizations.GetSkipObjectNullCheck()) {
3954*795d594fSAndroid Build Coastguard Worker     __ testl(object, object);
3955*795d594fSAndroid Build Coastguard Worker     __ j(kZero, slow_path->GetEntryLabel());
3956*795d594fSAndroid Build Coastguard Worker   }
3957*795d594fSAndroid Build Coastguard Worker 
3958*795d594fSAndroid Build Coastguard Worker   // Check the object's class against coordinateType0.
3959*795d594fSAndroid Build Coastguard Worker   GenerateSubTypeObjectCheck(object,
3960*795d594fSAndroid Build Coastguard Worker                              temp,
3961*795d594fSAndroid Build Coastguard Worker                              Address(varhandle_object, coordtype0_offset),
3962*795d594fSAndroid Build Coastguard Worker                              slow_path,
3963*795d594fSAndroid Build Coastguard Worker                              assembler,
3964*795d594fSAndroid Build Coastguard Worker                              /* object_can_be_null= */ false);
3965*795d594fSAndroid Build Coastguard Worker }
3966*795d594fSAndroid Build Coastguard Worker 
GenerateVarTypePrimitiveTypeCheck(Register varhandle_object,Register temp,DataType::Type type,SlowPathCode * slow_path,X86Assembler * assembler)3967*795d594fSAndroid Build Coastguard Worker static void GenerateVarTypePrimitiveTypeCheck(Register varhandle_object,
3968*795d594fSAndroid Build Coastguard Worker                                               Register temp,
3969*795d594fSAndroid Build Coastguard Worker                                               DataType::Type type,
3970*795d594fSAndroid Build Coastguard Worker                                               SlowPathCode* slow_path,
3971*795d594fSAndroid Build Coastguard Worker                                               X86Assembler* assembler) {
3972*795d594fSAndroid Build Coastguard Worker   const uint32_t var_type_offset = mirror::VarHandle::VarTypeOffset().Uint32Value();
3973*795d594fSAndroid Build Coastguard Worker   const uint32_t primitive_type_offset = mirror::Class::PrimitiveTypeOffset().Uint32Value();
3974*795d594fSAndroid Build Coastguard Worker   const uint32_t primitive_type = static_cast<uint32_t>(DataTypeToPrimitive(type));
3975*795d594fSAndroid Build Coastguard Worker 
3976*795d594fSAndroid Build Coastguard Worker   // We do not need a read barrier when loading a reference only for loading a constant field
3977*795d594fSAndroid Build Coastguard Worker   // through the reference.
3978*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(varhandle_object, var_type_offset));
3979*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(temp);
3980*795d594fSAndroid Build Coastguard Worker   __ cmpw(Address(temp, primitive_type_offset), Immediate(primitive_type));
3981*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, slow_path->GetEntryLabel());
3982*795d594fSAndroid Build Coastguard Worker }
3983*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleCommonChecks(HInvoke * invoke,Register temp,SlowPathCode * slow_path,X86Assembler * assembler)3984*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCommonChecks(HInvoke *invoke,
3985*795d594fSAndroid Build Coastguard Worker                                           Register temp,
3986*795d594fSAndroid Build Coastguard Worker                                           SlowPathCode* slow_path,
3987*795d594fSAndroid Build Coastguard Worker                                           X86Assembler* assembler) {
3988*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
3989*795d594fSAndroid Build Coastguard Worker   Register vh_object = locations->InAt(0).AsRegister<Register>();
3990*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessMode access_mode =
3991*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic());
3992*795d594fSAndroid Build Coastguard Worker 
3993*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleAccessModeCheck(vh_object,
3994*795d594fSAndroid Build Coastguard Worker                                    access_mode,
3995*795d594fSAndroid Build Coastguard Worker                                    slow_path,
3996*795d594fSAndroid Build Coastguard Worker                                    assembler);
3997*795d594fSAndroid Build Coastguard Worker 
3998*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3999*795d594fSAndroid Build Coastguard Worker   switch (expected_coordinates_count) {
4000*795d594fSAndroid Build Coastguard Worker     case 0u:
4001*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleStaticFieldCheck(vh_object, slow_path, assembler);
4002*795d594fSAndroid Build Coastguard Worker       break;
4003*795d594fSAndroid Build Coastguard Worker     case 1u: {
4004*795d594fSAndroid Build Coastguard Worker       GenerateVarHandleInstanceFieldChecks(invoke, temp, slow_path, assembler);
4005*795d594fSAndroid Build Coastguard Worker       break;
4006*795d594fSAndroid Build Coastguard Worker     }
4007*795d594fSAndroid Build Coastguard Worker     default:
4008*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected coordinates count: " << expected_coordinates_count;
4009*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
4010*795d594fSAndroid Build Coastguard Worker   }
4011*795d594fSAndroid Build Coastguard Worker 
4012*795d594fSAndroid Build Coastguard Worker   // Check the return type and varType parameters.
4013*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessModeTemplate access_mode_template =
4014*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::GetAccessModeTemplate(access_mode);
4015*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4016*795d594fSAndroid Build Coastguard Worker 
4017*795d594fSAndroid Build Coastguard Worker   switch (access_mode_template) {
4018*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kGet:
4019*795d594fSAndroid Build Coastguard Worker       // Check the varType.primitiveType against the type we're trying to retrieve. Reference types
4020*795d594fSAndroid Build Coastguard Worker       // are also checked later by a HCheckCast node as an additional check.
4021*795d594fSAndroid Build Coastguard Worker       GenerateVarTypePrimitiveTypeCheck(vh_object, temp, type, slow_path, assembler);
4022*795d594fSAndroid Build Coastguard Worker       break;
4023*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kSet:
4024*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
4025*795d594fSAndroid Build Coastguard Worker       uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4026*795d594fSAndroid Build Coastguard Worker       DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4027*795d594fSAndroid Build Coastguard Worker 
4028*795d594fSAndroid Build Coastguard Worker       // Check the varType.primitiveType against the type of the value we're trying to set.
4029*795d594fSAndroid Build Coastguard Worker       GenerateVarTypePrimitiveTypeCheck(vh_object, temp, value_type, slow_path, assembler);
4030*795d594fSAndroid Build Coastguard Worker       if (value_type == DataType::Type::kReference) {
4031*795d594fSAndroid Build Coastguard Worker         const uint32_t var_type_offset = mirror::VarHandle::VarTypeOffset().Uint32Value();
4032*795d594fSAndroid Build Coastguard Worker 
4033*795d594fSAndroid Build Coastguard Worker         // If the value type is a reference, check it against the varType.
4034*795d594fSAndroid Build Coastguard Worker         GenerateSubTypeObjectCheck(locations->InAt(value_index).AsRegister<Register>(),
4035*795d594fSAndroid Build Coastguard Worker                                    temp,
4036*795d594fSAndroid Build Coastguard Worker                                    Address(vh_object, var_type_offset),
4037*795d594fSAndroid Build Coastguard Worker                                    slow_path,
4038*795d594fSAndroid Build Coastguard Worker                                    assembler);
4039*795d594fSAndroid Build Coastguard Worker       }
4040*795d594fSAndroid Build Coastguard Worker       break;
4041*795d594fSAndroid Build Coastguard Worker     }
4042*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kCompareAndSet:
4043*795d594fSAndroid Build Coastguard Worker     case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
4044*795d594fSAndroid Build Coastguard Worker       uint32_t new_value_index = invoke->GetNumberOfArguments() - 1;
4045*795d594fSAndroid Build Coastguard Worker       uint32_t expected_value_index = invoke->GetNumberOfArguments() - 2;
4046*795d594fSAndroid Build Coastguard Worker       DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
4047*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, expected_value_index));
4048*795d594fSAndroid Build Coastguard Worker 
4049*795d594fSAndroid Build Coastguard Worker       // Check the varType.primitiveType against the type of the expected value.
4050*795d594fSAndroid Build Coastguard Worker       GenerateVarTypePrimitiveTypeCheck(vh_object, temp, value_type, slow_path, assembler);
4051*795d594fSAndroid Build Coastguard Worker       if (value_type == DataType::Type::kReference) {
4052*795d594fSAndroid Build Coastguard Worker         const uint32_t var_type_offset = mirror::VarHandle::VarTypeOffset().Uint32Value();
4053*795d594fSAndroid Build Coastguard Worker 
4054*795d594fSAndroid Build Coastguard Worker         // If the value type is a reference, check both the expected and the new value against
4055*795d594fSAndroid Build Coastguard Worker         // the varType.
4056*795d594fSAndroid Build Coastguard Worker         GenerateSubTypeObjectCheck(locations->InAt(new_value_index).AsRegister<Register>(),
4057*795d594fSAndroid Build Coastguard Worker                                    temp,
4058*795d594fSAndroid Build Coastguard Worker                                    Address(vh_object, var_type_offset),
4059*795d594fSAndroid Build Coastguard Worker                                    slow_path,
4060*795d594fSAndroid Build Coastguard Worker                                    assembler);
4061*795d594fSAndroid Build Coastguard Worker         GenerateSubTypeObjectCheck(locations->InAt(expected_value_index).AsRegister<Register>(),
4062*795d594fSAndroid Build Coastguard Worker                                    temp,
4063*795d594fSAndroid Build Coastguard Worker                                    Address(vh_object, var_type_offset),
4064*795d594fSAndroid Build Coastguard Worker                                    slow_path,
4065*795d594fSAndroid Build Coastguard Worker                                    assembler);
4066*795d594fSAndroid Build Coastguard Worker       }
4067*795d594fSAndroid Build Coastguard Worker       break;
4068*795d594fSAndroid Build Coastguard Worker     }
4069*795d594fSAndroid Build Coastguard Worker   }
4070*795d594fSAndroid Build Coastguard Worker }
4071*795d594fSAndroid Build Coastguard Worker 
4072*795d594fSAndroid Build Coastguard Worker // This method loads the field's address referred by a field VarHandle (base + offset).
4073*795d594fSAndroid Build Coastguard Worker // The return value is the register containing object's reference (in case of an instance field)
4074*795d594fSAndroid Build Coastguard Worker // or the declaring class (in case of a static field). The declaring class is stored in temp
4075*795d594fSAndroid Build Coastguard Worker // register. Field's offset is loaded to the `offset` register.
GenerateVarHandleFieldReference(HInvoke * invoke,CodeGeneratorX86 * codegen,Register temp,Register offset)4076*795d594fSAndroid Build Coastguard Worker static Register GenerateVarHandleFieldReference(HInvoke* invoke,
4077*795d594fSAndroid Build Coastguard Worker                                                 CodeGeneratorX86* codegen,
4078*795d594fSAndroid Build Coastguard Worker                                                 Register temp,
4079*795d594fSAndroid Build Coastguard Worker                                                 /*out*/ Register offset) {
4080*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4081*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4082*795d594fSAndroid Build Coastguard Worker   const uint32_t artfield_offset = mirror::FieldVarHandle::ArtFieldOffset().Uint32Value();
4083*795d594fSAndroid Build Coastguard Worker   const uint32_t offset_offset = ArtField::OffsetOffset().Uint32Value();
4084*795d594fSAndroid Build Coastguard Worker   const uint32_t declaring_class_offset = ArtField::DeclaringClassOffset().Uint32Value();
4085*795d594fSAndroid Build Coastguard Worker   Register varhandle_object = locations->InAt(0).AsRegister<Register>();
4086*795d594fSAndroid Build Coastguard Worker 
4087*795d594fSAndroid Build Coastguard Worker   // Load the ArtField* and the offset.
4088*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(varhandle_object, artfield_offset));
4089*795d594fSAndroid Build Coastguard Worker   __ movl(offset, Address(temp, offset_offset));
4090*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4091*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 0) {
4092*795d594fSAndroid Build Coastguard Worker     // For static fields, load the declaring class
4093*795d594fSAndroid Build Coastguard Worker     InstructionCodeGeneratorX86* instr_codegen =
4094*795d594fSAndroid Build Coastguard Worker         down_cast<InstructionCodeGeneratorX86*>(codegen->GetInstructionVisitor());
4095*795d594fSAndroid Build Coastguard Worker     instr_codegen->GenerateGcRootFieldLoad(invoke,
4096*795d594fSAndroid Build Coastguard Worker                                            Location::RegisterLocation(temp),
4097*795d594fSAndroid Build Coastguard Worker                                            Address(temp, declaring_class_offset),
4098*795d594fSAndroid Build Coastguard Worker                                            /* fixup_label= */ nullptr,
4099*795d594fSAndroid Build Coastguard Worker                                            codegen->GetCompilerReadBarrierOption());
4100*795d594fSAndroid Build Coastguard Worker     return temp;
4101*795d594fSAndroid Build Coastguard Worker   }
4102*795d594fSAndroid Build Coastguard Worker 
4103*795d594fSAndroid Build Coastguard Worker   // For instance fields, return the register containing the object.
4104*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(expected_coordinates_count, 1u);
4105*795d594fSAndroid Build Coastguard Worker 
4106*795d594fSAndroid Build Coastguard Worker   return locations->InAt(1).AsRegister<Register>();
4107*795d594fSAndroid Build Coastguard Worker }
4108*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4109*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetLocations(HInvoke* invoke, CodeGeneratorX86* codegen) {
4110*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4111*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4112*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4113*795d594fSAndroid Build Coastguard Worker     return;
4114*795d594fSAndroid Build Coastguard Worker   }
4115*795d594fSAndroid Build Coastguard Worker 
4116*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4117*795d594fSAndroid Build Coastguard Worker     return;
4118*795d594fSAndroid Build Coastguard Worker   }
4119*795d594fSAndroid Build Coastguard Worker 
4120*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4121*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4122*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4123*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4124*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4125*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 1u) {
4126*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object.
4127*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4128*795d594fSAndroid Build Coastguard Worker   }
4129*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
4130*795d594fSAndroid Build Coastguard Worker 
4131*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4132*795d594fSAndroid Build Coastguard Worker   switch (DataType::Kind(type)) {
4133*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
4134*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4135*795d594fSAndroid Build Coastguard Worker       if (invoke->GetIntrinsic() != Intrinsics::kVarHandleGet) {
4136*795d594fSAndroid Build Coastguard Worker         // We need an XmmRegister for Int64 to ensure an atomic load
4137*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresFpuRegister());
4138*795d594fSAndroid Build Coastguard Worker       }
4139*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
4140*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4141*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
4142*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister());
4143*795d594fSAndroid Build Coastguard Worker       break;
4144*795d594fSAndroid Build Coastguard Worker     default:
4145*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsFloatingPointType(type));
4146*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4147*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
4148*795d594fSAndroid Build Coastguard Worker   }
4149*795d594fSAndroid Build Coastguard Worker }
4150*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGet(HInvoke * invoke,CodeGeneratorX86 * codegen)4151*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGet(HInvoke* invoke, CodeGeneratorX86* codegen) {
4152*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4153*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4154*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
4155*795d594fSAndroid Build Coastguard Worker 
4156*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4157*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4158*795d594fSAndroid Build Coastguard Worker   DataType::Type type = invoke->GetType();
4159*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(type, DataType::Type::kVoid);
4160*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
4161*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
4162*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4163*795d594fSAndroid Build Coastguard Worker 
4164*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
4165*795d594fSAndroid Build Coastguard Worker 
4166*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
4167*795d594fSAndroid Build Coastguard Worker   // Use 'out' as a temporary register if it's a core register
4168*795d594fSAndroid Build Coastguard Worker   Register offset =
4169*795d594fSAndroid Build Coastguard Worker       out.IsRegister() ? out.AsRegister<Register>() : locations->GetTemp(1).AsRegister<Register>();
4170*795d594fSAndroid Build Coastguard Worker 
4171*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
4172*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
4173*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'temp' register.
4174*795d594fSAndroid Build Coastguard Worker   Register ref = GenerateVarHandleFieldReference(invoke, codegen, temp, offset);
4175*795d594fSAndroid Build Coastguard Worker   Address field_addr(ref, offset, TIMES_1, 0);
4176*795d594fSAndroid Build Coastguard Worker 
4177*795d594fSAndroid Build Coastguard Worker   // Load the value from the field
4178*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
4179*795d594fSAndroid Build Coastguard Worker     codegen->GenerateReferenceLoadWithBakerReadBarrier(
4180*795d594fSAndroid Build Coastguard Worker         invoke, out, ref, field_addr, /* needs_null_check= */ false);
4181*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kInt64 &&
4182*795d594fSAndroid Build Coastguard Worker              invoke->GetIntrinsic() != Intrinsics::kVarHandleGet) {
4183*795d594fSAndroid Build Coastguard Worker     XmmRegister xmm_temp = locations->GetTemp(2).AsFpuRegister<XmmRegister>();
4184*795d594fSAndroid Build Coastguard Worker     codegen->LoadFromMemoryNoBarrier(
4185*795d594fSAndroid Build Coastguard Worker         type, out, field_addr, /* instr= */ nullptr, xmm_temp, /* is_atomic_load= */ true);
4186*795d594fSAndroid Build Coastguard Worker   } else {
4187*795d594fSAndroid Build Coastguard Worker     codegen->LoadFromMemoryNoBarrier(type, out, field_addr);
4188*795d594fSAndroid Build Coastguard Worker   }
4189*795d594fSAndroid Build Coastguard Worker 
4190*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetVolatile ||
4191*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAcquire) {
4192*795d594fSAndroid Build Coastguard Worker     // Load fence to prevent load-load reordering.
4193*795d594fSAndroid Build Coastguard Worker     // Note that this is a no-op, thanks to the x86 memory model.
4194*795d594fSAndroid Build Coastguard Worker     codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4195*795d594fSAndroid Build Coastguard Worker   }
4196*795d594fSAndroid Build Coastguard Worker 
4197*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4198*795d594fSAndroid Build Coastguard Worker }
4199*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGet(HInvoke * invoke)4200*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGet(HInvoke* invoke) {
4201*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
4202*795d594fSAndroid Build Coastguard Worker }
4203*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGet(HInvoke * invoke)4204*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGet(HInvoke* invoke) {
4205*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_);
4206*795d594fSAndroid Build Coastguard Worker }
4207*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetVolatile(HInvoke * invoke)4208*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetVolatile(HInvoke* invoke) {
4209*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
4210*795d594fSAndroid Build Coastguard Worker }
4211*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetVolatile(HInvoke * invoke)4212*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetVolatile(HInvoke* invoke) {
4213*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_);
4214*795d594fSAndroid Build Coastguard Worker }
4215*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAcquire(HInvoke * invoke)4216*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAcquire(HInvoke* invoke) {
4217*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
4218*795d594fSAndroid Build Coastguard Worker }
4219*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAcquire(HInvoke * invoke)4220*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAcquire(HInvoke* invoke) {
4221*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_);
4222*795d594fSAndroid Build Coastguard Worker }
4223*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetOpaque(HInvoke * invoke)4224*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetOpaque(HInvoke* invoke) {
4225*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetLocations(invoke, codegen_);
4226*795d594fSAndroid Build Coastguard Worker }
4227*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetOpaque(HInvoke * invoke)4228*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetOpaque(HInvoke* invoke) {
4229*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGet(invoke, codegen_);
4230*795d594fSAndroid Build Coastguard Worker }
4231*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleSetLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4232*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleSetLocations(HInvoke* invoke, CodeGeneratorX86* codegen) {
4233*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4234*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4235*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4236*795d594fSAndroid Build Coastguard Worker     return;
4237*795d594fSAndroid Build Coastguard Worker   }
4238*795d594fSAndroid Build Coastguard Worker 
4239*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4240*795d594fSAndroid Build Coastguard Worker     return;
4241*795d594fSAndroid Build Coastguard Worker   }
4242*795d594fSAndroid Build Coastguard Worker 
4243*795d594fSAndroid Build Coastguard Worker   // The last argument should be the value we intend to set.
4244*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4245*795d594fSAndroid Build Coastguard Worker   HInstruction* value = invoke->InputAt(value_index);
4246*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4247*795d594fSAndroid Build Coastguard Worker   bool needs_atomicity = invoke->GetIntrinsic() != Intrinsics::kVarHandleSet;
4248*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kInt64 && (!value->IsConstant() || needs_atomicity)) {
4249*795d594fSAndroid Build Coastguard Worker     // We avoid the case of a non-constant (or volatile) Int64 value because we would need to
4250*795d594fSAndroid Build Coastguard Worker     // place it in a register pair. If the slow path is taken, the ParallelMove might fail to move
4251*795d594fSAndroid Build Coastguard Worker     // the pair according to the X86DexCallingConvention in case of an overlap (e.g., move the
4252*795d594fSAndroid Build Coastguard Worker     // int64 value from <EAX, EBX> to <EBX, ECX>). (Bug: b/168687887)
4253*795d594fSAndroid Build Coastguard Worker     return;
4254*795d594fSAndroid Build Coastguard Worker   }
4255*795d594fSAndroid Build Coastguard Worker 
4256*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4257*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4258*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4259*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4260*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4261*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 1u) {
4262*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object
4263*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4264*795d594fSAndroid Build Coastguard Worker   }
4265*795d594fSAndroid Build Coastguard Worker 
4266*795d594fSAndroid Build Coastguard Worker   switch (value_type) {
4267*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
4268*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
4269*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
4270*795d594fSAndroid Build Coastguard Worker       // Ensure the value is in a byte register
4271*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(value_index, Location::ByteRegisterOrConstant(EBX, value));
4272*795d594fSAndroid Build Coastguard Worker       break;
4273*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
4274*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
4275*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4276*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(value_index, Location::RegisterOrConstant(value));
4277*795d594fSAndroid Build Coastguard Worker       break;
4278*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
4279*795d594fSAndroid Build Coastguard Worker       // We only handle constant non-atomic int64 values.
4280*795d594fSAndroid Build Coastguard Worker       DCHECK(value->IsConstant());
4281*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(value_index, Location::ConstantLocation(value));
4282*795d594fSAndroid Build Coastguard Worker       break;
4283*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
4284*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(value_index, Location::RequiresRegister());
4285*795d594fSAndroid Build Coastguard Worker       break;
4286*795d594fSAndroid Build Coastguard Worker     default:
4287*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsFloatingPointType(value_type));
4288*795d594fSAndroid Build Coastguard Worker       if (needs_atomicity && value_type == DataType::Type::kFloat64) {
4289*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(value_index, Location::RequiresFpuRegister());
4290*795d594fSAndroid Build Coastguard Worker       } else {
4291*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(value_index, Location::FpuRegisterOrConstant(value));
4292*795d594fSAndroid Build Coastguard Worker       }
4293*795d594fSAndroid Build Coastguard Worker   }
4294*795d594fSAndroid Build Coastguard Worker 
4295*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
4296*795d594fSAndroid Build Coastguard Worker   // This temporary register is also used for card for MarkGCCard. Make sure it's a byte register
4297*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EAX));
4298*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 0 && value_type == DataType::Type::kReference) {
4299*795d594fSAndroid Build Coastguard Worker     // For static reference fields, we need another temporary for the declaring class. We set it
4300*795d594fSAndroid Build Coastguard Worker     // last because we want to make sure that the first 2 temps are reserved for HandleFieldSet.
4301*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4302*795d594fSAndroid Build Coastguard Worker   }
4303*795d594fSAndroid Build Coastguard Worker }
4304*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleSet(HInvoke * invoke,CodeGeneratorX86 * codegen)4305*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleSet(HInvoke* invoke, CodeGeneratorX86* codegen) {
4306*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4307*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4308*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
4309*795d594fSAndroid Build Coastguard Worker 
4310*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4311*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4312*795d594fSAndroid Build Coastguard Worker   // The value we want to set is the last argument
4313*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4314*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4315*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
4316*795d594fSAndroid Build Coastguard Worker   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4317*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
4318*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4319*795d594fSAndroid Build Coastguard Worker 
4320*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
4321*795d594fSAndroid Build Coastguard Worker 
4322*795d594fSAndroid Build Coastguard Worker   // For static reference fields, we need another temporary for the declaring class. But since
4323*795d594fSAndroid Build Coastguard Worker   // for instance fields the object is in a separate register, it is safe to use the first
4324*795d594fSAndroid Build Coastguard Worker   // temporary register for GenerateVarHandleFieldReference.
4325*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4326*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kReference && expected_coordinates_count == 0) {
4327*795d594fSAndroid Build Coastguard Worker     temp = locations->GetTemp(2).AsRegister<Register>();
4328*795d594fSAndroid Build Coastguard Worker   }
4329*795d594fSAndroid Build Coastguard Worker 
4330*795d594fSAndroid Build Coastguard Worker   Register offset = temp2;
4331*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
4332*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
4333*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'temp' register.
4334*795d594fSAndroid Build Coastguard Worker   Register reference = GenerateVarHandleFieldReference(invoke, codegen, temp, offset);
4335*795d594fSAndroid Build Coastguard Worker 
4336*795d594fSAndroid Build Coastguard Worker   bool is_volatile = false;
4337*795d594fSAndroid Build Coastguard Worker   switch (invoke->GetIntrinsic()) {
4338*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleSet:
4339*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleSetOpaque:
4340*795d594fSAndroid Build Coastguard Worker       // The only constraint for setOpaque is to ensure bitwise atomicity (atomically set 64 bit
4341*795d594fSAndroid Build Coastguard Worker       // values), but we don't treat Int64 values because we would need to place it in a register
4342*795d594fSAndroid Build Coastguard Worker       // pair. If the slow path is taken, the Parallel move might fail to move the register pair
4343*795d594fSAndroid Build Coastguard Worker       // in case of an overlap (e.g., move from <EAX, EBX> to <EBX, ECX>). (Bug: b/168687887)
4344*795d594fSAndroid Build Coastguard Worker       break;
4345*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleSetRelease:
4346*795d594fSAndroid Build Coastguard Worker       // setRelease needs to ensure atomicity too. See the above comment.
4347*795d594fSAndroid Build Coastguard Worker       codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4348*795d594fSAndroid Build Coastguard Worker       break;
4349*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleSetVolatile:
4350*795d594fSAndroid Build Coastguard Worker       is_volatile = true;
4351*795d594fSAndroid Build Coastguard Worker       break;
4352*795d594fSAndroid Build Coastguard Worker     default:
4353*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "GenerateVarHandleSet received non-set intrinsic " << invoke->GetIntrinsic();
4354*795d594fSAndroid Build Coastguard Worker   }
4355*795d594fSAndroid Build Coastguard Worker 
4356*795d594fSAndroid Build Coastguard Worker   InstructionCodeGeneratorX86* instr_codegen =
4357*795d594fSAndroid Build Coastguard Worker         down_cast<InstructionCodeGeneratorX86*>(codegen->GetInstructionVisitor());
4358*795d594fSAndroid Build Coastguard Worker   // Store the value to the field
4359*795d594fSAndroid Build Coastguard Worker   instr_codegen->HandleFieldSet(
4360*795d594fSAndroid Build Coastguard Worker       invoke,
4361*795d594fSAndroid Build Coastguard Worker       value_index,
4362*795d594fSAndroid Build Coastguard Worker       value_type,
4363*795d594fSAndroid Build Coastguard Worker       Address(reference, offset, TIMES_1, 0),
4364*795d594fSAndroid Build Coastguard Worker       reference,
4365*795d594fSAndroid Build Coastguard Worker       is_volatile,
4366*795d594fSAndroid Build Coastguard Worker       /* value_can_be_null */ true,
4367*795d594fSAndroid Build Coastguard Worker       // Value can be null, and this write barrier is not being relied on for other sets.
4368*795d594fSAndroid Build Coastguard Worker       value_type == DataType::Type::kReference ? WriteBarrierKind::kEmitNotBeingReliedOn :
4369*795d594fSAndroid Build Coastguard Worker                                                  WriteBarrierKind::kDontEmit);
4370*795d594fSAndroid Build Coastguard Worker 
4371*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4372*795d594fSAndroid Build Coastguard Worker }
4373*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSet(HInvoke * invoke)4374*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleSet(HInvoke* invoke) {
4375*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
4376*795d594fSAndroid Build Coastguard Worker }
4377*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSet(HInvoke * invoke)4378*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleSet(HInvoke* invoke) {
4379*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_);
4380*795d594fSAndroid Build Coastguard Worker }
4381*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetVolatile(HInvoke * invoke)4382*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleSetVolatile(HInvoke* invoke) {
4383*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
4384*795d594fSAndroid Build Coastguard Worker }
4385*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetVolatile(HInvoke * invoke)4386*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleSetVolatile(HInvoke* invoke) {
4387*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_);
4388*795d594fSAndroid Build Coastguard Worker }
4389*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetRelease(HInvoke * invoke)4390*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleSetRelease(HInvoke* invoke) {
4391*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
4392*795d594fSAndroid Build Coastguard Worker }
4393*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetRelease(HInvoke * invoke)4394*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleSetRelease(HInvoke* invoke) {
4395*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_);
4396*795d594fSAndroid Build Coastguard Worker }
4397*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetOpaque(HInvoke * invoke)4398*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleSetOpaque(HInvoke* invoke) {
4399*795d594fSAndroid Build Coastguard Worker   CreateVarHandleSetLocations(invoke, codegen_);
4400*795d594fSAndroid Build Coastguard Worker }
4401*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleSetOpaque(HInvoke * invoke)4402*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleSetOpaque(HInvoke* invoke) {
4403*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleSet(invoke, codegen_);
4404*795d594fSAndroid Build Coastguard Worker }
4405*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetAndSetLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4406*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetAndSetLocations(HInvoke* invoke, CodeGeneratorX86* codegen) {
4407*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4408*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4409*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4410*795d594fSAndroid Build Coastguard Worker     return;
4411*795d594fSAndroid Build Coastguard Worker   }
4412*795d594fSAndroid Build Coastguard Worker 
4413*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4414*795d594fSAndroid Build Coastguard Worker     return;
4415*795d594fSAndroid Build Coastguard Worker   }
4416*795d594fSAndroid Build Coastguard Worker 
4417*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
4418*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4419*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = number_of_arguments - 1;
4420*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4421*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
4422*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
4423*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
4424*795d594fSAndroid Build Coastguard Worker 
4425*795d594fSAndroid Build Coastguard Worker   if (DataType::Is64BitType(value_type)) {
4426*795d594fSAndroid Build Coastguard Worker     // We avoid the case of an Int64/Float64 value because we would need to place it in a register
4427*795d594fSAndroid Build Coastguard Worker     // pair. If the slow path is taken, the ParallelMove might fail to move the pair according to
4428*795d594fSAndroid Build Coastguard Worker     // the X86DexCallingConvention in case of an overlap (e.g., move the 64 bit value from
4429*795d594fSAndroid Build Coastguard Worker     // <EAX, EBX> to <EBX, ECX>).
4430*795d594fSAndroid Build Coastguard Worker     return;
4431*795d594fSAndroid Build Coastguard Worker   }
4432*795d594fSAndroid Build Coastguard Worker 
4433*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4434*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4435*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4436*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(2);
4437*795d594fSAndroid Build Coastguard Worker   // We use this temporary for the card, so we need a byte register
4438*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EBX));
4439*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4440*795d594fSAndroid Build Coastguard Worker   if (GetExpectedVarHandleCoordinatesCount(invoke) == 1u) {
4441*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object
4442*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4443*795d594fSAndroid Build Coastguard Worker   } else {
4444*795d594fSAndroid Build Coastguard Worker     // For static fields, we need another temp because one will be busy with the declaring class.
4445*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4446*795d594fSAndroid Build Coastguard Worker   }
4447*795d594fSAndroid Build Coastguard Worker   if (value_type == DataType::Type::kFloat32) {
4448*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(EAX));
4449*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(value_index, Location::FpuRegisterOrConstant(invoke->InputAt(value_index)));
4450*795d594fSAndroid Build Coastguard Worker     // Only set the `out` register if it's needed. In the void case, we will not use `out`.
4451*795d594fSAndroid Build Coastguard Worker     if (!is_void) {
4452*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
4453*795d594fSAndroid Build Coastguard Worker     }
4454*795d594fSAndroid Build Coastguard Worker   } else {
4455*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(value_index, Location::RegisterLocation(EAX));
4456*795d594fSAndroid Build Coastguard Worker     // Only set the `out` register if it's needed. In the void case we can still use EAX in the
4457*795d594fSAndroid Build Coastguard Worker     // same manner as it is marked as a temp register.
4458*795d594fSAndroid Build Coastguard Worker     if (is_void) {
4459*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
4460*795d594fSAndroid Build Coastguard Worker     } else {
4461*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterLocation(EAX));
4462*795d594fSAndroid Build Coastguard Worker     }
4463*795d594fSAndroid Build Coastguard Worker   }
4464*795d594fSAndroid Build Coastguard Worker }
4465*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGetAndSet(HInvoke * invoke,CodeGeneratorX86 * codegen)4466*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGetAndSet(HInvoke* invoke, CodeGeneratorX86* codegen) {
4467*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4468*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4469*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
4470*795d594fSAndroid Build Coastguard Worker 
4471*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4472*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4473*795d594fSAndroid Build Coastguard Worker   // The value we want to set is the last argument
4474*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4475*795d594fSAndroid Build Coastguard Worker   Location value = locations->InAt(value_index);
4476*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
4477*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4478*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(1).AsRegister<Register>();
4479*795d594fSAndroid Build Coastguard Worker   Register temp2 = locations->GetTemp(2).AsRegister<Register>();
4480*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
4481*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4482*795d594fSAndroid Build Coastguard Worker 
4483*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
4484*795d594fSAndroid Build Coastguard Worker 
4485*795d594fSAndroid Build Coastguard Worker   Register offset = locations->GetTemp(0).AsRegister<Register>();
4486*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
4487*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
4488*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'temp' register.
4489*795d594fSAndroid Build Coastguard Worker   Register reference = GenerateVarHandleFieldReference(invoke, codegen, temp, offset);
4490*795d594fSAndroid Build Coastguard Worker   Address field_addr(reference, offset, TIMES_1, 0);
4491*795d594fSAndroid Build Coastguard Worker 
4492*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndSetRelease) {
4493*795d594fSAndroid Build Coastguard Worker     codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4494*795d594fSAndroid Build Coastguard Worker   }
4495*795d594fSAndroid Build Coastguard Worker 
4496*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4497*795d594fSAndroid Build Coastguard Worker   // For static fields, we need another temporary for the declaring class. But since for instance
4498*795d594fSAndroid Build Coastguard Worker   // fields the object is in a separate register, it is safe to use the first temporary register.
4499*795d594fSAndroid Build Coastguard Worker   temp = expected_coordinates_count == 1u ? temp : locations->GetTemp(3).AsRegister<Register>();
4500*795d594fSAndroid Build Coastguard Worker   // No need for a lock prefix. `xchg` has an implicit lock when it is used with an address.
4501*795d594fSAndroid Build Coastguard Worker 
4502*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
4503*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
4504*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
4505*795d594fSAndroid Build Coastguard Worker   switch (value_type) {
4506*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
4507*795d594fSAndroid Build Coastguard Worker       __ xchgb(value.AsRegister<ByteRegister>(), field_addr);
4508*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4509*795d594fSAndroid Build Coastguard Worker         __ movzxb(locations->Out().AsRegister<Register>(),
4510*795d594fSAndroid Build Coastguard Worker                   locations->Out().AsRegister<ByteRegister>());
4511*795d594fSAndroid Build Coastguard Worker       }
4512*795d594fSAndroid Build Coastguard Worker       break;
4513*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
4514*795d594fSAndroid Build Coastguard Worker       __ xchgb(value.AsRegister<ByteRegister>(), field_addr);
4515*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4516*795d594fSAndroid Build Coastguard Worker         __ movsxb(locations->Out().AsRegister<Register>(),
4517*795d594fSAndroid Build Coastguard Worker                   locations->Out().AsRegister<ByteRegister>());
4518*795d594fSAndroid Build Coastguard Worker       }
4519*795d594fSAndroid Build Coastguard Worker       break;
4520*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
4521*795d594fSAndroid Build Coastguard Worker       __ xchgw(value.AsRegister<Register>(), field_addr);
4522*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4523*795d594fSAndroid Build Coastguard Worker         __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
4524*795d594fSAndroid Build Coastguard Worker       }
4525*795d594fSAndroid Build Coastguard Worker       break;
4526*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
4527*795d594fSAndroid Build Coastguard Worker       __ xchgw(value.AsRegister<Register>(), field_addr);
4528*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4529*795d594fSAndroid Build Coastguard Worker         __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
4530*795d594fSAndroid Build Coastguard Worker       }
4531*795d594fSAndroid Build Coastguard Worker       break;
4532*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4533*795d594fSAndroid Build Coastguard Worker       __ xchgl(value.AsRegister<Register>(), field_addr);
4534*795d594fSAndroid Build Coastguard Worker       break;
4535*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4536*795d594fSAndroid Build Coastguard Worker       codegen->Move32(Location::RegisterLocation(EAX), value);
4537*795d594fSAndroid Build Coastguard Worker       __ xchgl(EAX, field_addr);
4538*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4539*795d594fSAndroid Build Coastguard Worker         __ movd(locations->Out().AsFpuRegister<XmmRegister>(), EAX);
4540*795d594fSAndroid Build Coastguard Worker       }
4541*795d594fSAndroid Build Coastguard Worker       break;
4542*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference: {
4543*795d594fSAndroid Build Coastguard Worker       if (codegen->EmitBakerReadBarrier()) {
4544*795d594fSAndroid Build Coastguard Worker         // Need to make sure the reference stored in the field is a to-space
4545*795d594fSAndroid Build Coastguard Worker         // one before attempting the CAS or the CAS could fail incorrectly.
4546*795d594fSAndroid Build Coastguard Worker         codegen->GenerateReferenceLoadWithBakerReadBarrier(
4547*795d594fSAndroid Build Coastguard Worker             invoke,
4548*795d594fSAndroid Build Coastguard Worker             // Unused, used only as a "temporary" within the read barrier.
4549*795d594fSAndroid Build Coastguard Worker             Location::RegisterLocation(temp),
4550*795d594fSAndroid Build Coastguard Worker             reference,
4551*795d594fSAndroid Build Coastguard Worker             field_addr,
4552*795d594fSAndroid Build Coastguard Worker             /* needs_null_check= */ false,
4553*795d594fSAndroid Build Coastguard Worker             /* always_update_field= */ true,
4554*795d594fSAndroid Build Coastguard Worker             &temp2);
4555*795d594fSAndroid Build Coastguard Worker       }
4556*795d594fSAndroid Build Coastguard Worker       codegen->MarkGCCard(temp, temp2, reference);
4557*795d594fSAndroid Build Coastguard Worker       if (kPoisonHeapReferences) {
4558*795d594fSAndroid Build Coastguard Worker         __ movl(temp, value.AsRegister<Register>());
4559*795d594fSAndroid Build Coastguard Worker         __ PoisonHeapReference(temp);
4560*795d594fSAndroid Build Coastguard Worker         __ xchgl(temp, field_addr);
4561*795d594fSAndroid Build Coastguard Worker         if (!is_void) {
4562*795d594fSAndroid Build Coastguard Worker           __ UnpoisonHeapReference(temp);
4563*795d594fSAndroid Build Coastguard Worker           __ movl(locations->Out().AsRegister<Register>(), temp);
4564*795d594fSAndroid Build Coastguard Worker         }
4565*795d594fSAndroid Build Coastguard Worker       } else {
4566*795d594fSAndroid Build Coastguard Worker         DCHECK_IMPLIES(!is_void, locations->Out().Equals(Location::RegisterLocation(EAX)));
4567*795d594fSAndroid Build Coastguard Worker         __ xchgl(Location::RegisterLocation(EAX).AsRegister<Register>(), field_addr);
4568*795d594fSAndroid Build Coastguard Worker       }
4569*795d594fSAndroid Build Coastguard Worker       break;
4570*795d594fSAndroid Build Coastguard Worker     }
4571*795d594fSAndroid Build Coastguard Worker     default:
4572*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type: " << value_type;
4573*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
4574*795d594fSAndroid Build Coastguard Worker   }
4575*795d594fSAndroid Build Coastguard Worker 
4576*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndSetAcquire) {
4577*795d594fSAndroid Build Coastguard Worker     codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4578*795d594fSAndroid Build Coastguard Worker   }
4579*795d594fSAndroid Build Coastguard Worker 
4580*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4581*795d594fSAndroid Build Coastguard Worker }
4582*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSet(HInvoke * invoke)4583*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndSet(HInvoke* invoke) {
4584*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndSetLocations(invoke, codegen_);
4585*795d594fSAndroid Build Coastguard Worker }
4586*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSet(HInvoke * invoke)4587*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndSet(HInvoke* invoke) {
4588*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndSet(invoke, codegen_);
4589*795d594fSAndroid Build Coastguard Worker }
4590*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)4591*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
4592*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndSetLocations(invoke, codegen_);
4593*795d594fSAndroid Build Coastguard Worker }
4594*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)4595*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
4596*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndSet(invoke, codegen_);
4597*795d594fSAndroid Build Coastguard Worker }
4598*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetRelease(HInvoke * invoke)4599*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
4600*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndSetLocations(invoke, codegen_);
4601*795d594fSAndroid Build Coastguard Worker }
4602*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndSetRelease(HInvoke * invoke)4603*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
4604*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndSet(invoke, codegen_);
4605*795d594fSAndroid Build Coastguard Worker }
4606*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4607*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke,
4608*795d594fSAndroid Build Coastguard Worker                                                             CodeGeneratorX86* codegen) {
4609*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4610*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4611*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4612*795d594fSAndroid Build Coastguard Worker     return;
4613*795d594fSAndroid Build Coastguard Worker   }
4614*795d594fSAndroid Build Coastguard Worker 
4615*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4616*795d594fSAndroid Build Coastguard Worker     return;
4617*795d594fSAndroid Build Coastguard Worker   }
4618*795d594fSAndroid Build Coastguard Worker 
4619*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4620*795d594fSAndroid Build Coastguard Worker   uint32_t expected_value_index = number_of_arguments - 2;
4621*795d594fSAndroid Build Coastguard Worker   uint32_t new_value_index = number_of_arguments - 1;
4622*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, expected_value_index);
4623*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, new_value_index));
4624*795d594fSAndroid Build Coastguard Worker 
4625*795d594fSAndroid Build Coastguard Worker   if (DataType::Is64BitType(value_type)) {
4626*795d594fSAndroid Build Coastguard Worker     // We avoid the case of an Int64/Float64 value because we would need to place it in a register
4627*795d594fSAndroid Build Coastguard Worker     // pair. If the slow path is taken, the ParallelMove might fail to move the pair according to
4628*795d594fSAndroid Build Coastguard Worker     // the X86DexCallingConvention in case of an overlap (e.g., move the 64 bit value from
4629*795d594fSAndroid Build Coastguard Worker     // <EAX, EBX> to <EBX, ECX>).
4630*795d594fSAndroid Build Coastguard Worker     return;
4631*795d594fSAndroid Build Coastguard Worker   }
4632*795d594fSAndroid Build Coastguard Worker 
4633*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4634*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4635*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4636*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(2);
4637*795d594fSAndroid Build Coastguard Worker   // We use this temporary for the card, so we need a byte register
4638*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EBX));
4639*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4640*795d594fSAndroid Build Coastguard Worker   if (GetExpectedVarHandleCoordinatesCount(invoke) == 1u) {
4641*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object
4642*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4643*795d594fSAndroid Build Coastguard Worker   } else {
4644*795d594fSAndroid Build Coastguard Worker     // For static fields, we need another temp because one will be busy with the declaring class.
4645*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4646*795d594fSAndroid Build Coastguard Worker   }
4647*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(value_type)) {
4648*795d594fSAndroid Build Coastguard Worker     // We need EAX for placing the expected value
4649*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(EAX));
4650*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(new_value_index,
4651*795d594fSAndroid Build Coastguard Worker                        Location::FpuRegisterOrConstant(invoke->InputAt(new_value_index)));
4652*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(expected_value_index,
4653*795d594fSAndroid Build Coastguard Worker                        Location::FpuRegisterOrConstant(invoke->InputAt(expected_value_index)));
4654*795d594fSAndroid Build Coastguard Worker   } else {
4655*795d594fSAndroid Build Coastguard Worker     // Ensure it's in a byte register
4656*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(new_value_index, Location::RegisterLocation(ECX));
4657*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(expected_value_index, Location::RegisterLocation(EAX));
4658*795d594fSAndroid Build Coastguard Worker   }
4659*795d594fSAndroid Build Coastguard Worker 
4660*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessModeTemplate access_mode_template =
4661*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
4662*795d594fSAndroid Build Coastguard Worker 
4663*795d594fSAndroid Build Coastguard Worker   if (access_mode_template == mirror::VarHandle::AccessModeTemplate::kCompareAndExchange &&
4664*795d594fSAndroid Build Coastguard Worker       value_type == DataType::Type::kFloat32) {
4665*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresFpuRegister());
4666*795d594fSAndroid Build Coastguard Worker   } else {
4667*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RegisterLocation(EAX));
4668*795d594fSAndroid Build Coastguard Worker   }
4669*795d594fSAndroid Build Coastguard Worker }
4670*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleCompareAndSetOrExchange(HInvoke * invoke,CodeGeneratorX86 * codegen)4671*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCompareAndSetOrExchange(HInvoke* invoke, CodeGeneratorX86* codegen) {
4672*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4673*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4674*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
4675*795d594fSAndroid Build Coastguard Worker 
4676*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4677*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4678*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4679*795d594fSAndroid Build Coastguard Worker   uint32_t expected_value_index = number_of_arguments - 2;
4680*795d594fSAndroid Build Coastguard Worker   uint32_t new_value_index = number_of_arguments - 1;
4681*795d594fSAndroid Build Coastguard Worker   DataType::Type type = GetDataTypeFromShorty(invoke, expected_value_index);
4682*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(type, GetDataTypeFromShorty(invoke, new_value_index));
4683*795d594fSAndroid Build Coastguard Worker   Location expected_value = locations->InAt(expected_value_index);
4684*795d594fSAndroid Build Coastguard Worker   Location new_value = locations->InAt(new_value_index);
4685*795d594fSAndroid Build Coastguard Worker   Register offset = locations->GetTemp(0).AsRegister<Register>();
4686*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(1).AsRegister<Register>();
4687*795d594fSAndroid Build Coastguard Worker   Register temp2 = locations->GetTemp(2).AsRegister<Register>();
4688*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
4689*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4690*795d594fSAndroid Build Coastguard Worker 
4691*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
4692*795d594fSAndroid Build Coastguard Worker 
4693*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
4694*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
4695*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'temp' register.
4696*795d594fSAndroid Build Coastguard Worker   Register reference = GenerateVarHandleFieldReference(invoke, codegen, temp, offset);
4697*795d594fSAndroid Build Coastguard Worker 
4698*795d594fSAndroid Build Coastguard Worker   uint32_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4699*795d594fSAndroid Build Coastguard Worker   // For generating the compare and exchange, we need 2 temporaries. In case of a static field, the
4700*795d594fSAndroid Build Coastguard Worker   // first temporary contains the declaring class so we need another temporary. In case of an
4701*795d594fSAndroid Build Coastguard Worker   // instance field, the object comes in a separate register so it's safe to use the first temp.
4702*795d594fSAndroid Build Coastguard Worker   temp = (expected_coordinates_count == 1u) ? temp : locations->GetTemp(3).AsRegister<Register>();
4703*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(temp, reference);
4704*795d594fSAndroid Build Coastguard Worker 
4705*795d594fSAndroid Build Coastguard Worker   // We are using `lock cmpxchg` in all cases because there is no CAS equivalent that has weak
4706*795d594fSAndroid Build Coastguard Worker   // failure semantics. `lock cmpxchg` has full barrier semantics, and we don't need scheduling
4707*795d594fSAndroid Build Coastguard Worker   // barriers at this time.
4708*795d594fSAndroid Build Coastguard Worker 
4709*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::AccessModeTemplate access_mode_template =
4710*795d594fSAndroid Build Coastguard Worker       mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
4711*795d594fSAndroid Build Coastguard Worker   bool is_cmpxchg =
4712*795d594fSAndroid Build Coastguard Worker       access_mode_template == mirror::VarHandle::AccessModeTemplate::kCompareAndExchange;
4713*795d594fSAndroid Build Coastguard Worker 
4714*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
4715*795d594fSAndroid Build Coastguard Worker     GenReferenceCAS(
4716*795d594fSAndroid Build Coastguard Worker         invoke, codegen, expected_value, new_value, reference, offset, temp, temp2, is_cmpxchg);
4717*795d594fSAndroid Build Coastguard Worker   } else {
4718*795d594fSAndroid Build Coastguard Worker     Location out = locations->Out();
4719*795d594fSAndroid Build Coastguard Worker     GenPrimitiveCAS(
4720*795d594fSAndroid Build Coastguard Worker         type, codegen, expected_value, new_value, reference, offset, out, temp, is_cmpxchg);
4721*795d594fSAndroid Build Coastguard Worker   }
4722*795d594fSAndroid Build Coastguard Worker 
4723*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4724*795d594fSAndroid Build Coastguard Worker }
4725*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndSet(HInvoke * invoke)4726*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleCompareAndSet(HInvoke* invoke) {
4727*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4728*795d594fSAndroid Build Coastguard Worker }
4729*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndSet(HInvoke * invoke)4730*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleCompareAndSet(HInvoke* invoke) {
4731*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4732*795d594fSAndroid Build Coastguard Worker }
4733*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)4734*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
4735*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4736*795d594fSAndroid Build Coastguard Worker }
4737*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)4738*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
4739*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4740*795d594fSAndroid Build Coastguard Worker }
4741*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)4742*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
4743*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4744*795d594fSAndroid Build Coastguard Worker }
4745*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)4746*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
4747*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4748*795d594fSAndroid Build Coastguard Worker }
4749*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)4750*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
4751*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4752*795d594fSAndroid Build Coastguard Worker }
4753*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)4754*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
4755*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4756*795d594fSAndroid Build Coastguard Worker }
4757*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)4758*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
4759*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4760*795d594fSAndroid Build Coastguard Worker }
4761*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)4762*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
4763*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4764*795d594fSAndroid Build Coastguard Worker }
4765*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchange(HInvoke * invoke)4766*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
4767*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4768*795d594fSAndroid Build Coastguard Worker }
4769*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchange(HInvoke * invoke)4770*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
4771*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4772*795d594fSAndroid Build Coastguard Worker }
4773*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)4774*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
4775*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4776*795d594fSAndroid Build Coastguard Worker }
4777*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)4778*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
4779*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4780*795d594fSAndroid Build Coastguard Worker }
4781*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)4782*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
4783*795d594fSAndroid Build Coastguard Worker   CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_);
4784*795d594fSAndroid Build Coastguard Worker }
4785*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)4786*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
4787*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCompareAndSetOrExchange(invoke, codegen_);
4788*795d594fSAndroid Build Coastguard Worker }
4789*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetAndAddLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4790*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetAndAddLocations(HInvoke* invoke, CodeGeneratorX86* codegen) {
4791*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4792*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4793*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4794*795d594fSAndroid Build Coastguard Worker     return;
4795*795d594fSAndroid Build Coastguard Worker   }
4796*795d594fSAndroid Build Coastguard Worker 
4797*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4798*795d594fSAndroid Build Coastguard Worker     return;
4799*795d594fSAndroid Build Coastguard Worker   }
4800*795d594fSAndroid Build Coastguard Worker 
4801*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
4802*795d594fSAndroid Build Coastguard Worker   // The last argument should be the value we intend to set.
4803*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4804*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4805*795d594fSAndroid Build Coastguard Worker   if (DataType::Is64BitType(value_type)) {
4806*795d594fSAndroid Build Coastguard Worker     // We avoid the case of an Int64/Float64 value because we would need to place it in a register
4807*795d594fSAndroid Build Coastguard Worker     // pair. If the slow path is taken, the ParallelMove might fail to move the pair according to
4808*795d594fSAndroid Build Coastguard Worker     // the X86DexCallingConvention in case of an overlap (e.g., move the 64 bit value from
4809*795d594fSAndroid Build Coastguard Worker     // <EAX, EBX> to <EBX, ECX>). (Bug: b/168687887)
4810*795d594fSAndroid Build Coastguard Worker     return;
4811*795d594fSAndroid Build Coastguard Worker   }
4812*795d594fSAndroid Build Coastguard Worker 
4813*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4814*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4815*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4816*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(2);
4817*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4818*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4819*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 1u) {
4820*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object
4821*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4822*795d594fSAndroid Build Coastguard Worker   } else {
4823*795d594fSAndroid Build Coastguard Worker     // For static fields, we need another temp because one will be busy with the declaring class.
4824*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
4825*795d594fSAndroid Build Coastguard Worker   }
4826*795d594fSAndroid Build Coastguard Worker 
4827*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
4828*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
4829*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
4830*795d594fSAndroid Build Coastguard Worker 
4831*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(value_type)) {
4832*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
4833*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(EAX));
4834*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(value_index, Location::RequiresFpuRegister());
4835*795d594fSAndroid Build Coastguard Worker     // Only set the `out` register if it's needed. In the void case, we do not use `out`.
4836*795d594fSAndroid Build Coastguard Worker     if (!is_void) {
4837*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
4838*795d594fSAndroid Build Coastguard Worker     }
4839*795d594fSAndroid Build Coastguard Worker   } else {
4840*795d594fSAndroid Build Coastguard Worker     // xadd updates the register argument with the old value. ByteRegister required for xaddb.
4841*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(value_index, Location::RegisterLocation(EAX));
4842*795d594fSAndroid Build Coastguard Worker     // Only set the `out` register if it's needed. In the void case we can still use EAX in the
4843*795d594fSAndroid Build Coastguard Worker     // same manner as it is marked as a temp register.
4844*795d594fSAndroid Build Coastguard Worker     if (is_void) {
4845*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
4846*795d594fSAndroid Build Coastguard Worker     } else {
4847*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterLocation(EAX));
4848*795d594fSAndroid Build Coastguard Worker     }
4849*795d594fSAndroid Build Coastguard Worker   }
4850*795d594fSAndroid Build Coastguard Worker }
4851*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGetAndAdd(HInvoke * invoke,CodeGeneratorX86 * codegen)4852*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGetAndAdd(HInvoke* invoke, CodeGeneratorX86* codegen) {
4853*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4854*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4855*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
4856*795d594fSAndroid Build Coastguard Worker 
4857*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
4858*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
4859*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_arguments = invoke->GetNumberOfArguments();
4860*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = number_of_arguments - 1;
4861*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
4862*795d594fSAndroid Build Coastguard Worker   DataType::Type type = GetDataTypeFromShorty(invoke, value_index);
4863*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
4864*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
4865*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == type);
4866*795d594fSAndroid Build Coastguard Worker   Location value_loc = locations->InAt(value_index);
4867*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
4868*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
4869*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
4870*795d594fSAndroid Build Coastguard Worker 
4871*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
4872*795d594fSAndroid Build Coastguard Worker 
4873*795d594fSAndroid Build Coastguard Worker   Register offset = locations->GetTemp(1).AsRegister<Register>();
4874*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
4875*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
4876*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'temp' register.
4877*795d594fSAndroid Build Coastguard Worker   Register reference = GenerateVarHandleFieldReference(invoke, codegen, temp, offset);
4878*795d594fSAndroid Build Coastguard Worker 
4879*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4880*795d594fSAndroid Build Coastguard Worker   temp = (expected_coordinates_count == 1u) ? temp : locations->GetTemp(2).AsRegister<Register>();
4881*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(temp, reference);
4882*795d594fSAndroid Build Coastguard Worker   Address field_addr(reference, offset, TIMES_1, 0);
4883*795d594fSAndroid Build Coastguard Worker 
4884*795d594fSAndroid Build Coastguard Worker   switch (type) {
4885*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
4886*795d594fSAndroid Build Coastguard Worker       __ LockXaddb(field_addr, value_loc.AsRegister<ByteRegister>());
4887*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4888*795d594fSAndroid Build Coastguard Worker         __ movsxb(locations->Out().AsRegister<Register>(),
4889*795d594fSAndroid Build Coastguard Worker                   locations->Out().AsRegister<ByteRegister>());
4890*795d594fSAndroid Build Coastguard Worker       }
4891*795d594fSAndroid Build Coastguard Worker       break;
4892*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
4893*795d594fSAndroid Build Coastguard Worker       __ LockXaddw(field_addr, value_loc.AsRegister<Register>());
4894*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4895*795d594fSAndroid Build Coastguard Worker         __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
4896*795d594fSAndroid Build Coastguard Worker       }
4897*795d594fSAndroid Build Coastguard Worker       break;
4898*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
4899*795d594fSAndroid Build Coastguard Worker       __ LockXaddw(field_addr, value_loc.AsRegister<Register>());
4900*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4901*795d594fSAndroid Build Coastguard Worker         __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
4902*795d594fSAndroid Build Coastguard Worker       }
4903*795d594fSAndroid Build Coastguard Worker       break;
4904*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4905*795d594fSAndroid Build Coastguard Worker       __ LockXaddl(field_addr, value_loc.AsRegister<Register>());
4906*795d594fSAndroid Build Coastguard Worker       break;
4907*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
4908*795d594fSAndroid Build Coastguard Worker       Location temp_float =
4909*795d594fSAndroid Build Coastguard Worker           (expected_coordinates_count == 1u) ? locations->GetTemp(2) : locations->GetTemp(3);
4910*795d594fSAndroid Build Coastguard Worker       DCHECK(temp_float.IsFpuRegister());
4911*795d594fSAndroid Build Coastguard Worker       Location eax = Location::RegisterLocation(EAX);
4912*795d594fSAndroid Build Coastguard Worker       NearLabel try_again;
4913*795d594fSAndroid Build Coastguard Worker       __ Bind(&try_again);
4914*795d594fSAndroid Build Coastguard Worker       __ movss(temp_float.AsFpuRegister<XmmRegister>(), field_addr);
4915*795d594fSAndroid Build Coastguard Worker       __ movd(EAX, temp_float.AsFpuRegister<XmmRegister>());
4916*795d594fSAndroid Build Coastguard Worker       __ addss(temp_float.AsFpuRegister<XmmRegister>(),
4917*795d594fSAndroid Build Coastguard Worker                value_loc.AsFpuRegister<XmmRegister>());
4918*795d594fSAndroid Build Coastguard Worker       GenPrimitiveLockedCmpxchg(type,
4919*795d594fSAndroid Build Coastguard Worker                                 codegen,
4920*795d594fSAndroid Build Coastguard Worker                                 /* expected_value= */ eax,
4921*795d594fSAndroid Build Coastguard Worker                                 /* new_value= */ temp_float,
4922*795d594fSAndroid Build Coastguard Worker                                 reference,
4923*795d594fSAndroid Build Coastguard Worker                                 offset,
4924*795d594fSAndroid Build Coastguard Worker                                 temp);
4925*795d594fSAndroid Build Coastguard Worker       __ j(kNotZero, &try_again);
4926*795d594fSAndroid Build Coastguard Worker 
4927*795d594fSAndroid Build Coastguard Worker       if (!is_void) {
4928*795d594fSAndroid Build Coastguard Worker         // The old value is present in EAX.
4929*795d594fSAndroid Build Coastguard Worker         codegen->Move32(locations->Out(), eax);
4930*795d594fSAndroid Build Coastguard Worker       }
4931*795d594fSAndroid Build Coastguard Worker       break;
4932*795d594fSAndroid Build Coastguard Worker     }
4933*795d594fSAndroid Build Coastguard Worker     default:
4934*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type: " << type;
4935*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
4936*795d594fSAndroid Build Coastguard Worker   }
4937*795d594fSAndroid Build Coastguard Worker 
4938*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
4939*795d594fSAndroid Build Coastguard Worker }
4940*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAdd(HInvoke * invoke)4941*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndAdd(HInvoke* invoke) {
4942*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndAddLocations(invoke, codegen_);
4943*795d594fSAndroid Build Coastguard Worker }
4944*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAdd(HInvoke * invoke)4945*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndAdd(HInvoke* invoke) {
4946*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndAdd(invoke, codegen_);
4947*795d594fSAndroid Build Coastguard Worker }
4948*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)4949*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
4950*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndAddLocations(invoke, codegen_);
4951*795d594fSAndroid Build Coastguard Worker }
4952*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)4953*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
4954*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndAdd(invoke, codegen_);
4955*795d594fSAndroid Build Coastguard Worker }
4956*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddRelease(HInvoke * invoke)4957*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
4958*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndAddLocations(invoke, codegen_);
4959*795d594fSAndroid Build Coastguard Worker }
4960*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndAddRelease(HInvoke * invoke)4961*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
4962*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndAdd(invoke, codegen_);
4963*795d594fSAndroid Build Coastguard Worker }
4964*795d594fSAndroid Build Coastguard Worker 
CreateVarHandleGetAndBitwiseOpLocations(HInvoke * invoke,CodeGeneratorX86 * codegen)4965*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetAndBitwiseOpLocations(HInvoke* invoke, CodeGeneratorX86* codegen) {
4966*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
4967*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
4968*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
4969*795d594fSAndroid Build Coastguard Worker     return;
4970*795d594fSAndroid Build Coastguard Worker   }
4971*795d594fSAndroid Build Coastguard Worker 
4972*795d594fSAndroid Build Coastguard Worker   if (!HasVarHandleIntrinsicImplementation(invoke)) {
4973*795d594fSAndroid Build Coastguard Worker     return;
4974*795d594fSAndroid Build Coastguard Worker   }
4975*795d594fSAndroid Build Coastguard Worker 
4976*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
4977*795d594fSAndroid Build Coastguard Worker   // The last argument should be the value we intend to set.
4978*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4979*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4980*795d594fSAndroid Build Coastguard Worker   if (DataType::Is64BitType(value_type)) {
4981*795d594fSAndroid Build Coastguard Worker     // We avoid the case of an Int64 value because we would need to place it in a register pair.
4982*795d594fSAndroid Build Coastguard Worker     // If the slow path is taken, the ParallelMove might fail to move the pair according to the
4983*795d594fSAndroid Build Coastguard Worker     // X86DexCallingConvention in case of an overlap (e.g., move the 64 bit value from
4984*795d594fSAndroid Build Coastguard Worker     // <EAX, EBX> to <EBX, ECX>). (Bug: b/168687887)
4985*795d594fSAndroid Build Coastguard Worker     return;
4986*795d594fSAndroid Build Coastguard Worker   }
4987*795d594fSAndroid Build Coastguard Worker 
4988*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
4989*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(
4990*795d594fSAndroid Build Coastguard Worker       invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
4991*795d594fSAndroid Build Coastguard Worker   // We need a byte register temp to store the result of the bitwise operation
4992*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EBX));
4993*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
4994*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
4995*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
4996*795d594fSAndroid Build Coastguard Worker   if (expected_coordinates_count == 1u) {
4997*795d594fSAndroid Build Coastguard Worker     // For instance fields, this is the source object
4998*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
4999*795d594fSAndroid Build Coastguard Worker   } else {
5000*795d594fSAndroid Build Coastguard Worker     // For static fields, we need another temp because one will be busy with the declaring class.
5001*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
5002*795d594fSAndroid Build Coastguard Worker   }
5003*795d594fSAndroid Build Coastguard Worker 
5004*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(value_index, Location::RegisterOrConstant(invoke->InputAt(value_index)));
5005*795d594fSAndroid Build Coastguard Worker 
5006*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
5007*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
5008*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == value_type);
5009*795d594fSAndroid Build Coastguard Worker   if (is_void) {
5010*795d594fSAndroid Build Coastguard Worker     // Used as a temporary, even when we are not outputting it so reserve it. This has to be
5011*795d594fSAndroid Build Coastguard Worker     // requested before the other temporary since there's variable number of temp registers and the
5012*795d594fSAndroid Build Coastguard Worker     // other temp register is expected to be the last one.
5013*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(EAX));
5014*795d594fSAndroid Build Coastguard Worker   } else {
5015*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RegisterLocation(EAX));
5016*795d594fSAndroid Build Coastguard Worker   }
5017*795d594fSAndroid Build Coastguard Worker }
5018*795d594fSAndroid Build Coastguard Worker 
GenerateBitwiseOp(HInvoke * invoke,CodeGeneratorX86 * codegen,Register left,Register right)5019*795d594fSAndroid Build Coastguard Worker static void GenerateBitwiseOp(HInvoke* invoke,
5020*795d594fSAndroid Build Coastguard Worker                               CodeGeneratorX86* codegen,
5021*795d594fSAndroid Build Coastguard Worker                               Register left,
5022*795d594fSAndroid Build Coastguard Worker                               Register right) {
5023*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
5024*795d594fSAndroid Build Coastguard Worker 
5025*795d594fSAndroid Build Coastguard Worker   switch (invoke->GetIntrinsic()) {
5026*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseOr:
5027*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
5028*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
5029*795d594fSAndroid Build Coastguard Worker       __ orl(left, right);
5030*795d594fSAndroid Build Coastguard Worker       break;
5031*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseXor:
5032*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
5033*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
5034*795d594fSAndroid Build Coastguard Worker       __ xorl(left, right);
5035*795d594fSAndroid Build Coastguard Worker       break;
5036*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseAnd:
5037*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
5038*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
5039*795d594fSAndroid Build Coastguard Worker       __ andl(left, right);
5040*795d594fSAndroid Build Coastguard Worker       break;
5041*795d594fSAndroid Build Coastguard Worker     default:
5042*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected intrinsic: " << invoke->GetIntrinsic();
5043*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
5044*795d594fSAndroid Build Coastguard Worker   }
5045*795d594fSAndroid Build Coastguard Worker }
5046*795d594fSAndroid Build Coastguard Worker 
GenerateVarHandleGetAndBitwiseOp(HInvoke * invoke,CodeGeneratorX86 * codegen)5047*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGetAndBitwiseOp(HInvoke* invoke, CodeGeneratorX86* codegen) {
5048*795d594fSAndroid Build Coastguard Worker   // The only read barrier implementation supporting the
5049*795d594fSAndroid Build Coastguard Worker   // VarHandleGet intrinsic is the Baker-style read barriers.
5050*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(codegen->EmitReadBarrier(), kUseBakerReadBarrier);
5051*795d594fSAndroid Build Coastguard Worker 
5052*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
5053*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
5054*795d594fSAndroid Build Coastguard Worker   // Get the type from the shorty as the invokes may not return a value.
5055*795d594fSAndroid Build Coastguard Worker   uint32_t value_index = invoke->GetNumberOfArguments() - 1;
5056*795d594fSAndroid Build Coastguard Worker   DataType::Type type = GetDataTypeFromShorty(invoke, value_index);
5057*795d594fSAndroid Build Coastguard Worker   DataType::Type return_type = invoke->GetType();
5058*795d594fSAndroid Build Coastguard Worker   const bool is_void = return_type == DataType::Type::kVoid;
5059*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, return_type == type);
5060*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
5061*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
5062*795d594fSAndroid Build Coastguard Worker   codegen->AddSlowPath(slow_path);
5063*795d594fSAndroid Build Coastguard Worker 
5064*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleCommonChecks(invoke, temp, slow_path, assembler);
5065*795d594fSAndroid Build Coastguard Worker 
5066*795d594fSAndroid Build Coastguard Worker   Register offset = locations->GetTemp(1).AsRegister<Register>();
5067*795d594fSAndroid Build Coastguard Worker   size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
5068*795d594fSAndroid Build Coastguard Worker   // For static field, we need another temporary because the first one contains the declaring class
5069*795d594fSAndroid Build Coastguard Worker   Register reference =
5070*795d594fSAndroid Build Coastguard Worker       (expected_coordinates_count == 1u) ? temp : locations->GetTemp(2).AsRegister<Register>();
5071*795d594fSAndroid Build Coastguard Worker   // Get the field referred by the VarHandle. The returned register contains the object reference
5072*795d594fSAndroid Build Coastguard Worker   // or the declaring class. The field offset will be placed in 'offset'. For static fields, the
5073*795d594fSAndroid Build Coastguard Worker   // declaring class will be placed in 'reference' register.
5074*795d594fSAndroid Build Coastguard Worker   reference = GenerateVarHandleFieldReference(invoke, codegen, reference, offset);
5075*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(temp, reference);
5076*795d594fSAndroid Build Coastguard Worker   Address field_addr(reference, offset, TIMES_1, 0);
5077*795d594fSAndroid Build Coastguard Worker 
5078*795d594fSAndroid Build Coastguard Worker   Location eax_loc = Location::RegisterLocation(EAX);
5079*795d594fSAndroid Build Coastguard Worker   Register eax = eax_loc.AsRegister<Register>();
5080*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!is_void, locations->Out().Equals(eax_loc));
5081*795d594fSAndroid Build Coastguard Worker 
5082*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseOrRelease ||
5083*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseXorRelease ||
5084*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseAndRelease) {
5085*795d594fSAndroid Build Coastguard Worker     codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
5086*795d594fSAndroid Build Coastguard Worker   }
5087*795d594fSAndroid Build Coastguard Worker 
5088*795d594fSAndroid Build Coastguard Worker   NearLabel try_again;
5089*795d594fSAndroid Build Coastguard Worker   __ Bind(&try_again);
5090*795d594fSAndroid Build Coastguard Worker   // Place the expected value in EAX for cmpxchg
5091*795d594fSAndroid Build Coastguard Worker   codegen->LoadFromMemoryNoBarrier(type, eax_loc, field_addr);
5092*795d594fSAndroid Build Coastguard Worker   codegen->Move32(locations->GetTemp(0), locations->InAt(value_index));
5093*795d594fSAndroid Build Coastguard Worker   GenerateBitwiseOp(invoke, codegen, temp, eax);
5094*795d594fSAndroid Build Coastguard Worker   GenPrimitiveLockedCmpxchg(type,
5095*795d594fSAndroid Build Coastguard Worker                             codegen,
5096*795d594fSAndroid Build Coastguard Worker                             /* expected_value= */ eax_loc,
5097*795d594fSAndroid Build Coastguard Worker                             /* new_value= */ locations->GetTemp(0),
5098*795d594fSAndroid Build Coastguard Worker                             reference,
5099*795d594fSAndroid Build Coastguard Worker                             offset);
5100*795d594fSAndroid Build Coastguard Worker   // If the cmpxchg failed, another thread changed the value so try again.
5101*795d594fSAndroid Build Coastguard Worker   __ j(kNotZero, &try_again);
5102*795d594fSAndroid Build Coastguard Worker 
5103*795d594fSAndroid Build Coastguard Worker   // The old value is present in EAX.
5104*795d594fSAndroid Build Coastguard Worker 
5105*795d594fSAndroid Build Coastguard Worker   if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseOrAcquire ||
5106*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseXorAcquire ||
5107*795d594fSAndroid Build Coastguard Worker       invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseAndAcquire) {
5108*795d594fSAndroid Build Coastguard Worker     codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5109*795d594fSAndroid Build Coastguard Worker   }
5110*795d594fSAndroid Build Coastguard Worker 
5111*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
5112*795d594fSAndroid Build Coastguard Worker }
5113*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)5114*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
5115*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5116*795d594fSAndroid Build Coastguard Worker }
5117*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)5118*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
5119*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5120*795d594fSAndroid Build Coastguard Worker }
5121*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)5122*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
5123*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5124*795d594fSAndroid Build Coastguard Worker }
5125*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)5126*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
5127*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5128*795d594fSAndroid Build Coastguard Worker }
5129*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5130*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5131*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5132*795d594fSAndroid Build Coastguard Worker }
5133*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5134*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5135*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5136*795d594fSAndroid Build Coastguard Worker }
5137*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5138*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5139*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5140*795d594fSAndroid Build Coastguard Worker }
5141*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5142*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5143*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5144*795d594fSAndroid Build Coastguard Worker }
5145*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5146*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5147*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5148*795d594fSAndroid Build Coastguard Worker }
5149*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5150*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5151*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5152*795d594fSAndroid Build Coastguard Worker }
5153*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5154*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5155*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5156*795d594fSAndroid Build Coastguard Worker }
5157*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5158*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5159*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5160*795d594fSAndroid Build Coastguard Worker }
5161*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)5162*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
5163*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5164*795d594fSAndroid Build Coastguard Worker }
5165*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)5166*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
5167*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5168*795d594fSAndroid Build Coastguard Worker }
5169*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)5170*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
5171*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5172*795d594fSAndroid Build Coastguard Worker }
5173*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)5174*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
5175*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5176*795d594fSAndroid Build Coastguard Worker }
5177*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)5178*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
5179*795d594fSAndroid Build Coastguard Worker   CreateVarHandleGetAndBitwiseOpLocations(invoke, codegen_);
5180*795d594fSAndroid Build Coastguard Worker }
5181*795d594fSAndroid Build Coastguard Worker 
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)5182*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
5183*795d594fSAndroid Build Coastguard Worker   GenerateVarHandleGetAndBitwiseOp(invoke, codegen_);
5184*795d594fSAndroid Build Coastguard Worker }
5185*795d594fSAndroid Build Coastguard Worker 
GenerateMathFma(HInvoke * invoke,CodeGeneratorX86 * codegen)5186*795d594fSAndroid Build Coastguard Worker static void GenerateMathFma(HInvoke* invoke, CodeGeneratorX86* codegen) {
5187*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
5188*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
5189*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->InAt(0).Equals(locations->Out()));
5190*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = codegen->GetAssembler();
5191*795d594fSAndroid Build Coastguard Worker   XmmRegister left = locations->InAt(0).AsFpuRegister<XmmRegister>();
5192*795d594fSAndroid Build Coastguard Worker   XmmRegister right = locations->InAt(1).AsFpuRegister<XmmRegister>();
5193*795d594fSAndroid Build Coastguard Worker   XmmRegister accumulator = locations->InAt(2).AsFpuRegister<XmmRegister>();
5194*795d594fSAndroid Build Coastguard Worker   if (invoke->GetType() == DataType::Type::kFloat32) {
5195*795d594fSAndroid Build Coastguard Worker     __ vfmadd213ss(left, right, accumulator);
5196*795d594fSAndroid Build Coastguard Worker   } else {
5197*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(invoke->GetType(), DataType::Type::kFloat64);
5198*795d594fSAndroid Build Coastguard Worker     __ vfmadd213sd(left, right, accumulator);
5199*795d594fSAndroid Build Coastguard Worker   }
5200*795d594fSAndroid Build Coastguard Worker }
5201*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaDouble(HInvoke * invoke)5202*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathFmaDouble(HInvoke* invoke) {
5203*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
5204*795d594fSAndroid Build Coastguard Worker   GenerateMathFma(invoke, codegen_);
5205*795d594fSAndroid Build Coastguard Worker }
5206*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaDouble(HInvoke * invoke)5207*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathFmaDouble(HInvoke* invoke) {
5208*795d594fSAndroid Build Coastguard Worker   if (codegen_->GetInstructionSetFeatures().HasAVX2()) {
5209*795d594fSAndroid Build Coastguard Worker     CreateFPFPFPToFPCallLocations(allocator_, invoke);
5210*795d594fSAndroid Build Coastguard Worker   }
5211*795d594fSAndroid Build Coastguard Worker }
5212*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaFloat(HInvoke * invoke)5213*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorX86::VisitMathFmaFloat(HInvoke* invoke) {
5214*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
5215*795d594fSAndroid Build Coastguard Worker   GenerateMathFma(invoke, codegen_);
5216*795d594fSAndroid Build Coastguard Worker }
5217*795d594fSAndroid Build Coastguard Worker 
VisitMathFmaFloat(HInvoke * invoke)5218*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderX86::VisitMathFmaFloat(HInvoke* invoke) {
5219*795d594fSAndroid Build Coastguard Worker   if (codegen_->GetInstructionSetFeatures().HasAVX2()) {
5220*795d594fSAndroid Build Coastguard Worker     CreateFPFPFPToFPCallLocations(allocator_, invoke);
5221*795d594fSAndroid Build Coastguard Worker   }
5222*795d594fSAndroid Build Coastguard Worker }
5223*795d594fSAndroid Build Coastguard Worker 
5224*795d594fSAndroid Build Coastguard Worker #define MARK_UNIMPLEMENTED(Name) UNIMPLEMENTED_INTRINSIC(X86, Name)
5225*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED_INTRINSIC_LIST_X86(MARK_UNIMPLEMENTED);
5226*795d594fSAndroid Build Coastguard Worker #undef MARK_UNIMPLEMENTED
5227*795d594fSAndroid Build Coastguard Worker 
5228*795d594fSAndroid Build Coastguard Worker UNREACHABLE_INTRINSICS(X86)
5229*795d594fSAndroid Build Coastguard Worker 
5230*795d594fSAndroid Build Coastguard Worker #undef __
5231*795d594fSAndroid Build Coastguard Worker 
5232*795d594fSAndroid Build Coastguard Worker }  // namespace x86
5233*795d594fSAndroid Build Coastguard Worker }  // namespace art
5234