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