xref: /aosp_15_r20/art/compiler/optimizing/code_generator_x86.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "code_generator_x86.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "arch/x86/jni_frame_x86.h"
20*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "class_table.h"
22*795d594fSAndroid Build Coastguard Worker #include "code_generator_utils.h"
23*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints.h"
24*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints_enum.h"
25*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/card_table.h"
26*795d594fSAndroid Build Coastguard Worker #include "gc/space/image_space.h"
27*795d594fSAndroid Build Coastguard Worker #include "heap_poisoning.h"
28*795d594fSAndroid Build Coastguard Worker #include "interpreter/mterp/nterp.h"
29*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
30*795d594fSAndroid Build Coastguard Worker #include "intrinsics_list.h"
31*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
32*795d594fSAndroid Build Coastguard Worker #include "intrinsics_x86.h"
33*795d594fSAndroid Build Coastguard Worker #include "jit/profiling_info.h"
34*795d594fSAndroid Build Coastguard Worker #include "linker/linker_patch.h"
35*795d594fSAndroid Build Coastguard Worker #include "lock_word.h"
36*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
37*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
38*795d594fSAndroid Build Coastguard Worker #include "mirror/var_handle.h"
39*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
40*795d594fSAndroid Build Coastguard Worker #include "profiling_info_builder.h"
41*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "thread.h"
43*795d594fSAndroid Build Coastguard Worker #include "trace.h"
44*795d594fSAndroid Build Coastguard Worker #include "utils/assembler.h"
45*795d594fSAndroid Build Coastguard Worker #include "utils/stack_checks.h"
46*795d594fSAndroid Build Coastguard Worker #include "utils/x86/assembler_x86.h"
47*795d594fSAndroid Build Coastguard Worker #include "utils/x86/constants_x86.h"
48*795d594fSAndroid Build Coastguard Worker #include "utils/x86/managed_register_x86.h"
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker template<class MirrorType>
53*795d594fSAndroid Build Coastguard Worker class GcRoot;
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker namespace x86 {
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker static constexpr int kCurrentMethodStackOffset = 0;
58*795d594fSAndroid Build Coastguard Worker static constexpr Register kMethodRegisterArgument = EAX;
59*795d594fSAndroid Build Coastguard Worker static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker static constexpr int kC2ConditionMask = 0x400;
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker static constexpr int kFakeReturnRegister = Register(8);
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000);
66*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000);
67*795d594fSAndroid Build Coastguard Worker 
OneRegInReferenceOutSaveEverythingCallerSaves()68*795d594fSAndroid Build Coastguard Worker static RegisterSet OneRegInReferenceOutSaveEverythingCallerSaves() {
69*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
70*795d594fSAndroid Build Coastguard Worker   RegisterSet caller_saves = RegisterSet::Empty();
71*795d594fSAndroid Build Coastguard Worker   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
72*795d594fSAndroid Build Coastguard Worker   // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
73*795d594fSAndroid Build Coastguard Worker   // that the kPrimNot result register is the same as the first argument register.
74*795d594fSAndroid Build Coastguard Worker   return caller_saves;
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
78*795d594fSAndroid Build Coastguard Worker #define __ down_cast<X86Assembler*>(codegen->GetAssembler())->  // NOLINT
79*795d594fSAndroid Build Coastguard Worker #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86PointerSize, x).Int32Value()
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker class NullCheckSlowPathX86 : public SlowPathCode {
82*795d594fSAndroid Build Coastguard Worker  public:
NullCheckSlowPathX86(HNullCheck * instruction)83*795d594fSAndroid Build Coastguard Worker   explicit NullCheckSlowPathX86(HNullCheck* instruction) : SlowPathCode(instruction) {}
84*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)85*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
86*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
87*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
88*795d594fSAndroid Build Coastguard Worker     if (instruction_->CanThrowIntoCatchBlock()) {
89*795d594fSAndroid Build Coastguard Worker       // Live registers will be restored in the catch block if caught.
90*795d594fSAndroid Build Coastguard Worker       SaveLiveRegisters(codegen, instruction_->GetLocations());
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickThrowNullPointer,
93*795d594fSAndroid Build Coastguard Worker                                instruction_,
94*795d594fSAndroid Build Coastguard Worker                                instruction_->GetDexPc(),
95*795d594fSAndroid Build Coastguard Worker                                this);
96*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
97*795d594fSAndroid Build Coastguard Worker   }
98*795d594fSAndroid Build Coastguard Worker 
IsFatal() const99*795d594fSAndroid Build Coastguard Worker   bool IsFatal() const override { return true; }
100*795d594fSAndroid Build Coastguard Worker 
GetDescription() const101*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "NullCheckSlowPathX86"; }
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker  private:
104*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
105*795d594fSAndroid Build Coastguard Worker };
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker class DivZeroCheckSlowPathX86 : public SlowPathCode {
108*795d594fSAndroid Build Coastguard Worker  public:
DivZeroCheckSlowPathX86(HDivZeroCheck * instruction)109*795d594fSAndroid Build Coastguard Worker   explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
110*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)111*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
112*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
113*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
114*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
115*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
116*795d594fSAndroid Build Coastguard Worker   }
117*795d594fSAndroid Build Coastguard Worker 
IsFatal() const118*795d594fSAndroid Build Coastguard Worker   bool IsFatal() const override { return true; }
119*795d594fSAndroid Build Coastguard Worker 
GetDescription() const120*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "DivZeroCheckSlowPathX86"; }
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker  private:
123*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
124*795d594fSAndroid Build Coastguard Worker };
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker class DivRemMinusOneSlowPathX86 : public SlowPathCode {
127*795d594fSAndroid Build Coastguard Worker  public:
DivRemMinusOneSlowPathX86(HInstruction * instruction,Register reg,bool is_div)128*795d594fSAndroid Build Coastguard Worker   DivRemMinusOneSlowPathX86(HInstruction* instruction, Register reg, bool is_div)
129*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction), reg_(reg), is_div_(is_div) {}
130*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)131*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
132*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
133*795d594fSAndroid Build Coastguard Worker     if (is_div_) {
134*795d594fSAndroid Build Coastguard Worker       __ negl(reg_);
135*795d594fSAndroid Build Coastguard Worker     } else {
136*795d594fSAndroid Build Coastguard Worker       __ movl(reg_, Immediate(0));
137*795d594fSAndroid Build Coastguard Worker     }
138*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
139*795d594fSAndroid Build Coastguard Worker   }
140*795d594fSAndroid Build Coastguard Worker 
GetDescription() const141*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "DivRemMinusOneSlowPathX86"; }
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker  private:
144*795d594fSAndroid Build Coastguard Worker   Register reg_;
145*795d594fSAndroid Build Coastguard Worker   bool is_div_;
146*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
147*795d594fSAndroid Build Coastguard Worker };
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker class BoundsCheckSlowPathX86 : public SlowPathCode {
150*795d594fSAndroid Build Coastguard Worker  public:
BoundsCheckSlowPathX86(HBoundsCheck * instruction)151*795d594fSAndroid Build Coastguard Worker   explicit BoundsCheckSlowPathX86(HBoundsCheck* instruction) : SlowPathCode(instruction) {}
152*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)153*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
154*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
155*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
156*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
157*795d594fSAndroid Build Coastguard Worker     if (instruction_->CanThrowIntoCatchBlock()) {
158*795d594fSAndroid Build Coastguard Worker       // Live registers will be restored in the catch block if caught.
159*795d594fSAndroid Build Coastguard Worker       SaveLiveRegisters(codegen, locations);
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker     Location index_loc = locations->InAt(0);
163*795d594fSAndroid Build Coastguard Worker     Location length_loc = locations->InAt(1);
164*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
165*795d594fSAndroid Build Coastguard Worker     Location index_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
166*795d594fSAndroid Build Coastguard Worker     Location length_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker     // Are we using an array length from memory?
169*795d594fSAndroid Build Coastguard Worker     if (!length_loc.IsValid()) {
170*795d594fSAndroid Build Coastguard Worker       DCHECK(instruction_->InputAt(1)->IsArrayLength());
171*795d594fSAndroid Build Coastguard Worker       HArrayLength* array_length = instruction_->InputAt(1)->AsArrayLength();
172*795d594fSAndroid Build Coastguard Worker       DCHECK(array_length->IsEmittedAtUseSite());
173*795d594fSAndroid Build Coastguard Worker       uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length);
174*795d594fSAndroid Build Coastguard Worker       Location array_loc = array_length->GetLocations()->InAt(0);
175*795d594fSAndroid Build Coastguard Worker       if (!index_loc.Equals(length_arg)) {
176*795d594fSAndroid Build Coastguard Worker         // The index is not clobbered by loading the length directly to `length_arg`.
177*795d594fSAndroid Build Coastguard Worker         __ movl(length_arg.AsRegister<Register>(),
178*795d594fSAndroid Build Coastguard Worker                 Address(array_loc.AsRegister<Register>(), len_offset));
179*795d594fSAndroid Build Coastguard Worker         x86_codegen->Move32(index_arg, index_loc);
180*795d594fSAndroid Build Coastguard Worker       } else if (!array_loc.Equals(index_arg)) {
181*795d594fSAndroid Build Coastguard Worker         // The array reference is not clobbered by the index move.
182*795d594fSAndroid Build Coastguard Worker         x86_codegen->Move32(index_arg, index_loc);
183*795d594fSAndroid Build Coastguard Worker         __ movl(length_arg.AsRegister<Register>(),
184*795d594fSAndroid Build Coastguard Worker                 Address(array_loc.AsRegister<Register>(), len_offset));
185*795d594fSAndroid Build Coastguard Worker       } else {
186*795d594fSAndroid Build Coastguard Worker         // We do not have a temporary we could use, so swap the registers using the
187*795d594fSAndroid Build Coastguard Worker         // parallel move resolver and replace the array with the length afterwards.
188*795d594fSAndroid Build Coastguard Worker         codegen->EmitParallelMoves(
189*795d594fSAndroid Build Coastguard Worker             index_loc,
190*795d594fSAndroid Build Coastguard Worker             index_arg,
191*795d594fSAndroid Build Coastguard Worker             DataType::Type::kInt32,
192*795d594fSAndroid Build Coastguard Worker             array_loc,
193*795d594fSAndroid Build Coastguard Worker             length_arg,
194*795d594fSAndroid Build Coastguard Worker             DataType::Type::kReference);
195*795d594fSAndroid Build Coastguard Worker         __ movl(length_arg.AsRegister<Register>(),
196*795d594fSAndroid Build Coastguard Worker                 Address(length_arg.AsRegister<Register>(), len_offset));
197*795d594fSAndroid Build Coastguard Worker       }
198*795d594fSAndroid Build Coastguard Worker       if (mirror::kUseStringCompression && array_length->IsStringLength()) {
199*795d594fSAndroid Build Coastguard Worker         __ shrl(length_arg.AsRegister<Register>(), Immediate(1));
200*795d594fSAndroid Build Coastguard Worker       }
201*795d594fSAndroid Build Coastguard Worker     } else {
202*795d594fSAndroid Build Coastguard Worker       // We're moving two locations to locations that could overlap,
203*795d594fSAndroid Build Coastguard Worker       // so we need a parallel move resolver.
204*795d594fSAndroid Build Coastguard Worker       codegen->EmitParallelMoves(
205*795d594fSAndroid Build Coastguard Worker           index_loc,
206*795d594fSAndroid Build Coastguard Worker           index_arg,
207*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32,
208*795d594fSAndroid Build Coastguard Worker           length_loc,
209*795d594fSAndroid Build Coastguard Worker           length_arg,
210*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32);
211*795d594fSAndroid Build Coastguard Worker     }
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker     QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
214*795d594fSAndroid Build Coastguard Worker         ? kQuickThrowStringBounds
215*795d594fSAndroid Build Coastguard Worker         : kQuickThrowArrayBounds;
216*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
217*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
218*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
219*795d594fSAndroid Build Coastguard Worker   }
220*795d594fSAndroid Build Coastguard Worker 
IsFatal() const221*795d594fSAndroid Build Coastguard Worker   bool IsFatal() const override { return true; }
222*795d594fSAndroid Build Coastguard Worker 
GetDescription() const223*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "BoundsCheckSlowPathX86"; }
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker  private:
226*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
227*795d594fSAndroid Build Coastguard Worker };
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker class SuspendCheckSlowPathX86 : public SlowPathCode {
230*795d594fSAndroid Build Coastguard Worker  public:
SuspendCheckSlowPathX86(HSuspendCheck * instruction,HBasicBlock * successor)231*795d594fSAndroid Build Coastguard Worker   SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
232*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction), successor_(successor) {}
233*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)234*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
235*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
236*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
237*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
238*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);  // Only saves full width XMM for SIMD.
239*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
240*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickTestSuspend, void, void>();
241*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);  // Only restores full width XMM for SIMD.
242*795d594fSAndroid Build Coastguard Worker     if (successor_ == nullptr) {
243*795d594fSAndroid Build Coastguard Worker       __ jmp(GetReturnLabel());
244*795d594fSAndroid Build Coastguard Worker     } else {
245*795d594fSAndroid Build Coastguard Worker       __ jmp(x86_codegen->GetLabelOf(successor_));
246*795d594fSAndroid Build Coastguard Worker     }
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker 
GetReturnLabel()249*795d594fSAndroid Build Coastguard Worker   Label* GetReturnLabel() {
250*795d594fSAndroid Build Coastguard Worker     DCHECK(successor_ == nullptr);
251*795d594fSAndroid Build Coastguard Worker     return &return_label_;
252*795d594fSAndroid Build Coastguard Worker   }
253*795d594fSAndroid Build Coastguard Worker 
GetSuccessor() const254*795d594fSAndroid Build Coastguard Worker   HBasicBlock* GetSuccessor() const {
255*795d594fSAndroid Build Coastguard Worker     return successor_;
256*795d594fSAndroid Build Coastguard Worker   }
257*795d594fSAndroid Build Coastguard Worker 
GetDescription() const258*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "SuspendCheckSlowPathX86"; }
259*795d594fSAndroid Build Coastguard Worker 
260*795d594fSAndroid Build Coastguard Worker  private:
261*795d594fSAndroid Build Coastguard Worker   HBasicBlock* const successor_;
262*795d594fSAndroid Build Coastguard Worker   Label return_label_;
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
265*795d594fSAndroid Build Coastguard Worker };
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker class LoadStringSlowPathX86 : public SlowPathCode {
268*795d594fSAndroid Build Coastguard Worker  public:
LoadStringSlowPathX86(HLoadString * instruction)269*795d594fSAndroid Build Coastguard Worker   explicit LoadStringSlowPathX86(HLoadString* instruction): SlowPathCode(instruction) {}
270*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)271*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
272*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
273*795d594fSAndroid Build Coastguard Worker     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
274*795d594fSAndroid Build Coastguard Worker 
275*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
276*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
277*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
280*795d594fSAndroid Build Coastguard Worker     const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
281*795d594fSAndroid Build Coastguard Worker     __ movl(calling_convention.GetRegisterAt(0), Immediate(string_index.index_));
282*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
283*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
284*795d594fSAndroid Build Coastguard Worker     x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
285*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
288*795d594fSAndroid Build Coastguard Worker   }
289*795d594fSAndroid Build Coastguard Worker 
GetDescription() const290*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "LoadStringSlowPathX86"; }
291*795d594fSAndroid Build Coastguard Worker 
292*795d594fSAndroid Build Coastguard Worker  private:
293*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
294*795d594fSAndroid Build Coastguard Worker };
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker class LoadClassSlowPathX86 : public SlowPathCode {
297*795d594fSAndroid Build Coastguard Worker  public:
LoadClassSlowPathX86(HLoadClass * cls,HInstruction * at)298*795d594fSAndroid Build Coastguard Worker   LoadClassSlowPathX86(HLoadClass* cls, HInstruction* at)
299*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(at), cls_(cls) {
300*795d594fSAndroid Build Coastguard Worker     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
301*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
302*795d594fSAndroid Build Coastguard Worker   }
303*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)304*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
305*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
306*795d594fSAndroid Build Coastguard Worker     Location out = locations->Out();
307*795d594fSAndroid Build Coastguard Worker     const uint32_t dex_pc = instruction_->GetDexPc();
308*795d594fSAndroid Build Coastguard Worker     bool must_resolve_type = instruction_->IsLoadClass() && cls_->MustResolveTypeOnSlowPath();
309*795d594fSAndroid Build Coastguard Worker     bool must_do_clinit = instruction_->IsClinitCheck() || cls_->MustGenerateClinitCheck();
310*795d594fSAndroid Build Coastguard Worker 
311*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
312*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
313*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
316*795d594fSAndroid Build Coastguard Worker     if (must_resolve_type) {
317*795d594fSAndroid Build Coastguard Worker       DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_codegen->GetGraph()->GetDexFile()) ||
318*795d594fSAndroid Build Coastguard Worker              x86_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) ||
319*795d594fSAndroid Build Coastguard Worker              ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(),
320*795d594fSAndroid Build Coastguard Worker                              &cls_->GetDexFile()));
321*795d594fSAndroid Build Coastguard Worker       dex::TypeIndex type_index = cls_->GetTypeIndex();
322*795d594fSAndroid Build Coastguard Worker       __ movl(calling_convention.GetRegisterAt(0), Immediate(type_index.index_));
323*795d594fSAndroid Build Coastguard Worker       if (cls_->NeedsAccessCheck()) {
324*795d594fSAndroid Build Coastguard Worker         CheckEntrypointTypes<kQuickResolveTypeAndVerifyAccess, void*, uint32_t>();
325*795d594fSAndroid Build Coastguard Worker         x86_codegen->InvokeRuntime(kQuickResolveTypeAndVerifyAccess, instruction_, dex_pc, this);
326*795d594fSAndroid Build Coastguard Worker       } else {
327*795d594fSAndroid Build Coastguard Worker         CheckEntrypointTypes<kQuickResolveType, void*, uint32_t>();
328*795d594fSAndroid Build Coastguard Worker         x86_codegen->InvokeRuntime(kQuickResolveType, instruction_, dex_pc, this);
329*795d594fSAndroid Build Coastguard Worker       }
330*795d594fSAndroid Build Coastguard Worker       // If we also must_do_clinit, the resolved type is now in the correct register.
331*795d594fSAndroid Build Coastguard Worker     } else {
332*795d594fSAndroid Build Coastguard Worker       DCHECK(must_do_clinit);
333*795d594fSAndroid Build Coastguard Worker       Location source = instruction_->IsLoadClass() ? out : locations->InAt(0);
334*795d594fSAndroid Build Coastguard Worker       x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), source);
335*795d594fSAndroid Build Coastguard Worker     }
336*795d594fSAndroid Build Coastguard Worker     if (must_do_clinit) {
337*795d594fSAndroid Build Coastguard Worker       x86_codegen->InvokeRuntime(kQuickInitializeStaticStorage, instruction_, dex_pc, this);
338*795d594fSAndroid Build Coastguard Worker       CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, mirror::Class*>();
339*795d594fSAndroid Build Coastguard Worker     }
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker     // Move the class to the desired location.
342*795d594fSAndroid Build Coastguard Worker     if (out.IsValid()) {
343*795d594fSAndroid Build Coastguard Worker       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
344*795d594fSAndroid Build Coastguard Worker       x86_codegen->Move32(out, Location::RegisterLocation(EAX));
345*795d594fSAndroid Build Coastguard Worker     }
346*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
347*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
348*795d594fSAndroid Build Coastguard Worker   }
349*795d594fSAndroid Build Coastguard Worker 
GetDescription() const350*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "LoadClassSlowPathX86"; }
351*795d594fSAndroid Build Coastguard Worker 
352*795d594fSAndroid Build Coastguard Worker  private:
353*795d594fSAndroid Build Coastguard Worker   // The class this slow path will load.
354*795d594fSAndroid Build Coastguard Worker   HLoadClass* const cls_;
355*795d594fSAndroid Build Coastguard Worker 
356*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
357*795d594fSAndroid Build Coastguard Worker };
358*795d594fSAndroid Build Coastguard Worker 
359*795d594fSAndroid Build Coastguard Worker class TypeCheckSlowPathX86 : public SlowPathCode {
360*795d594fSAndroid Build Coastguard Worker  public:
TypeCheckSlowPathX86(HInstruction * instruction,bool is_fatal)361*795d594fSAndroid Build Coastguard Worker   TypeCheckSlowPathX86(HInstruction* instruction, bool is_fatal)
362*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction), is_fatal_(is_fatal) {}
363*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)364*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
365*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
366*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsCheckCast()
367*795d594fSAndroid Build Coastguard Worker            || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
370*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences &&
373*795d594fSAndroid Build Coastguard Worker         instruction_->IsCheckCast() &&
374*795d594fSAndroid Build Coastguard Worker         instruction_->AsCheckCast()->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) {
375*795d594fSAndroid Build Coastguard Worker       // First, unpoison the `cls` reference that was poisoned for direct memory comparison.
376*795d594fSAndroid Build Coastguard Worker       __ UnpoisonHeapReference(locations->InAt(1).AsRegister<Register>());
377*795d594fSAndroid Build Coastguard Worker     }
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker     if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
380*795d594fSAndroid Build Coastguard Worker       SaveLiveRegisters(codegen, locations);
381*795d594fSAndroid Build Coastguard Worker     }
382*795d594fSAndroid Build Coastguard Worker 
383*795d594fSAndroid Build Coastguard Worker     // We're moving two locations to locations that could overlap, so we need a parallel
384*795d594fSAndroid Build Coastguard Worker     // move resolver.
385*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
386*795d594fSAndroid Build Coastguard Worker     x86_codegen->EmitParallelMoves(locations->InAt(0),
387*795d594fSAndroid Build Coastguard Worker                                    Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
388*795d594fSAndroid Build Coastguard Worker                                    DataType::Type::kReference,
389*795d594fSAndroid Build Coastguard Worker                                    locations->InAt(1),
390*795d594fSAndroid Build Coastguard Worker                                    Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
391*795d594fSAndroid Build Coastguard Worker                                    DataType::Type::kReference);
392*795d594fSAndroid Build Coastguard Worker     if (instruction_->IsInstanceOf()) {
393*795d594fSAndroid Build Coastguard Worker       x86_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
394*795d594fSAndroid Build Coastguard Worker                                  instruction_,
395*795d594fSAndroid Build Coastguard Worker                                  instruction_->GetDexPc(),
396*795d594fSAndroid Build Coastguard Worker                                  this);
397*795d594fSAndroid Build Coastguard Worker       CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
398*795d594fSAndroid Build Coastguard Worker     } else {
399*795d594fSAndroid Build Coastguard Worker       DCHECK(instruction_->IsCheckCast());
400*795d594fSAndroid Build Coastguard Worker       x86_codegen->InvokeRuntime(kQuickCheckInstanceOf,
401*795d594fSAndroid Build Coastguard Worker                                  instruction_,
402*795d594fSAndroid Build Coastguard Worker                                  instruction_->GetDexPc(),
403*795d594fSAndroid Build Coastguard Worker                                  this);
404*795d594fSAndroid Build Coastguard Worker       CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
405*795d594fSAndroid Build Coastguard Worker     }
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker     if (!is_fatal_) {
408*795d594fSAndroid Build Coastguard Worker       if (instruction_->IsInstanceOf()) {
409*795d594fSAndroid Build Coastguard Worker         x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
410*795d594fSAndroid Build Coastguard Worker       }
411*795d594fSAndroid Build Coastguard Worker       RestoreLiveRegisters(codegen, locations);
412*795d594fSAndroid Build Coastguard Worker 
413*795d594fSAndroid Build Coastguard Worker       __ jmp(GetExitLabel());
414*795d594fSAndroid Build Coastguard Worker     }
415*795d594fSAndroid Build Coastguard Worker   }
416*795d594fSAndroid Build Coastguard Worker 
GetDescription() const417*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "TypeCheckSlowPathX86"; }
IsFatal() const418*795d594fSAndroid Build Coastguard Worker   bool IsFatal() const override { return is_fatal_; }
419*795d594fSAndroid Build Coastguard Worker 
420*795d594fSAndroid Build Coastguard Worker  private:
421*795d594fSAndroid Build Coastguard Worker   const bool is_fatal_;
422*795d594fSAndroid Build Coastguard Worker 
423*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
424*795d594fSAndroid Build Coastguard Worker };
425*795d594fSAndroid Build Coastguard Worker 
426*795d594fSAndroid Build Coastguard Worker class DeoptimizationSlowPathX86 : public SlowPathCode {
427*795d594fSAndroid Build Coastguard Worker  public:
DeoptimizationSlowPathX86(HDeoptimize * instruction)428*795d594fSAndroid Build Coastguard Worker   explicit DeoptimizationSlowPathX86(HDeoptimize* instruction)
429*795d594fSAndroid Build Coastguard Worker     : SlowPathCode(instruction) {}
430*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)431*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
432*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
433*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
434*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
435*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
436*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
437*795d594fSAndroid Build Coastguard Worker     x86_codegen->Load32BitValue(
438*795d594fSAndroid Build Coastguard Worker         calling_convention.GetRegisterAt(0),
439*795d594fSAndroid Build Coastguard Worker         static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
440*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
441*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
442*795d594fSAndroid Build Coastguard Worker   }
443*795d594fSAndroid Build Coastguard Worker 
GetDescription() const444*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "DeoptimizationSlowPathX86"; }
445*795d594fSAndroid Build Coastguard Worker 
446*795d594fSAndroid Build Coastguard Worker  private:
447*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
448*795d594fSAndroid Build Coastguard Worker };
449*795d594fSAndroid Build Coastguard Worker 
450*795d594fSAndroid Build Coastguard Worker class ArraySetSlowPathX86 : public SlowPathCode {
451*795d594fSAndroid Build Coastguard Worker  public:
ArraySetSlowPathX86(HInstruction * instruction)452*795d594fSAndroid Build Coastguard Worker   explicit ArraySetSlowPathX86(HInstruction* instruction) : SlowPathCode(instruction) {}
453*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)454*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
455*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
456*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
457*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
458*795d594fSAndroid Build Coastguard Worker 
459*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
460*795d594fSAndroid Build Coastguard Worker     HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
461*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(
462*795d594fSAndroid Build Coastguard Worker         locations->InAt(0),
463*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
464*795d594fSAndroid Build Coastguard Worker         DataType::Type::kReference,
465*795d594fSAndroid Build Coastguard Worker         nullptr);
466*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(
467*795d594fSAndroid Build Coastguard Worker         locations->InAt(1),
468*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
469*795d594fSAndroid Build Coastguard Worker         DataType::Type::kInt32,
470*795d594fSAndroid Build Coastguard Worker         nullptr);
471*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(
472*795d594fSAndroid Build Coastguard Worker         locations->InAt(2),
473*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
474*795d594fSAndroid Build Coastguard Worker         DataType::Type::kReference,
475*795d594fSAndroid Build Coastguard Worker         nullptr);
476*795d594fSAndroid Build Coastguard Worker     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
477*795d594fSAndroid Build Coastguard Worker 
478*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
479*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
480*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
481*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
482*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
483*795d594fSAndroid Build Coastguard Worker   }
484*795d594fSAndroid Build Coastguard Worker 
GetDescription() const485*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ArraySetSlowPathX86"; }
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker  private:
488*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86);
489*795d594fSAndroid Build Coastguard Worker };
490*795d594fSAndroid Build Coastguard Worker 
491*795d594fSAndroid Build Coastguard Worker // Slow path marking an object reference `ref` during a read
492*795d594fSAndroid Build Coastguard Worker // barrier. The field `obj.field` in the object `obj` holding this
493*795d594fSAndroid Build Coastguard Worker // reference does not get updated by this slow path after marking (see
494*795d594fSAndroid Build Coastguard Worker // ReadBarrierMarkAndUpdateFieldSlowPathX86 below for that).
495*795d594fSAndroid Build Coastguard Worker //
496*795d594fSAndroid Build Coastguard Worker // This means that after the execution of this slow path, `ref` will
497*795d594fSAndroid Build Coastguard Worker // always be up-to-date, but `obj.field` may not; i.e., after the
498*795d594fSAndroid Build Coastguard Worker // flip, `ref` will be a to-space reference, but `obj.field` will
499*795d594fSAndroid Build Coastguard Worker // probably still be a from-space reference (unless it gets updated by
500*795d594fSAndroid Build Coastguard Worker // another thread, or if another thread installed another object
501*795d594fSAndroid Build Coastguard Worker // reference (different from `ref`) in `obj.field`).
502*795d594fSAndroid Build Coastguard Worker class ReadBarrierMarkSlowPathX86 : public SlowPathCode {
503*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierMarkSlowPathX86(HInstruction * instruction,Location ref,bool unpoison_ref_before_marking)504*795d594fSAndroid Build Coastguard Worker   ReadBarrierMarkSlowPathX86(HInstruction* instruction,
505*795d594fSAndroid Build Coastguard Worker                              Location ref,
506*795d594fSAndroid Build Coastguard Worker                              bool unpoison_ref_before_marking)
507*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction),
508*795d594fSAndroid Build Coastguard Worker         ref_(ref),
509*795d594fSAndroid Build Coastguard Worker         unpoison_ref_before_marking_(unpoison_ref_before_marking) {
510*795d594fSAndroid Build Coastguard Worker   }
511*795d594fSAndroid Build Coastguard Worker 
GetDescription() const512*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierMarkSlowPathX86"; }
513*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)514*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
515*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen->EmitReadBarrier());
516*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
517*795d594fSAndroid Build Coastguard Worker     Register ref_reg = ref_.AsRegister<Register>();
518*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
519*795d594fSAndroid Build Coastguard Worker     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
520*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsInstanceFieldGet() ||
521*795d594fSAndroid Build Coastguard Worker            instruction_->IsStaticFieldGet() ||
522*795d594fSAndroid Build Coastguard Worker            instruction_->IsArrayGet() ||
523*795d594fSAndroid Build Coastguard Worker            instruction_->IsArraySet() ||
524*795d594fSAndroid Build Coastguard Worker            instruction_->IsLoadClass() ||
525*795d594fSAndroid Build Coastguard Worker            instruction_->IsLoadString() ||
526*795d594fSAndroid Build Coastguard Worker            instruction_->IsInstanceOf() ||
527*795d594fSAndroid Build Coastguard Worker            instruction_->IsCheckCast() ||
528*795d594fSAndroid Build Coastguard Worker            (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
529*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier marking slow path: "
530*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
531*795d594fSAndroid Build Coastguard Worker 
532*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
533*795d594fSAndroid Build Coastguard Worker     if (unpoison_ref_before_marking_) {
534*795d594fSAndroid Build Coastguard Worker       // Object* ref = ref_addr->AsMirrorPtr()
535*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(ref_reg);
536*795d594fSAndroid Build Coastguard Worker     }
537*795d594fSAndroid Build Coastguard Worker     // No need to save live registers; it's taken care of by the
538*795d594fSAndroid Build Coastguard Worker     // entrypoint. Also, there is no need to update the stack mask,
539*795d594fSAndroid Build Coastguard Worker     // as this runtime call will not trigger a garbage collection.
540*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
541*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(ref_reg, ESP);
542*795d594fSAndroid Build Coastguard Worker     DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
543*795d594fSAndroid Build Coastguard Worker     // "Compact" slow path, saving two moves.
544*795d594fSAndroid Build Coastguard Worker     //
545*795d594fSAndroid Build Coastguard Worker     // Instead of using the standard runtime calling convention (input
546*795d594fSAndroid Build Coastguard Worker     // and output in EAX):
547*795d594fSAndroid Build Coastguard Worker     //
548*795d594fSAndroid Build Coastguard Worker     //   EAX <- ref
549*795d594fSAndroid Build Coastguard Worker     //   EAX <- ReadBarrierMark(EAX)
550*795d594fSAndroid Build Coastguard Worker     //   ref <- EAX
551*795d594fSAndroid Build Coastguard Worker     //
552*795d594fSAndroid Build Coastguard Worker     // we just use rX (the register containing `ref`) as input and output
553*795d594fSAndroid Build Coastguard Worker     // of a dedicated entrypoint:
554*795d594fSAndroid Build Coastguard Worker     //
555*795d594fSAndroid Build Coastguard Worker     //   rX <- ReadBarrierMarkRegX(rX)
556*795d594fSAndroid Build Coastguard Worker     //
557*795d594fSAndroid Build Coastguard Worker     int32_t entry_point_offset = Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(ref_reg);
558*795d594fSAndroid Build Coastguard Worker     // This runtime call does not require a stack map.
559*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
560*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
561*795d594fSAndroid Build Coastguard Worker   }
562*795d594fSAndroid Build Coastguard Worker 
563*795d594fSAndroid Build Coastguard Worker  private:
564*795d594fSAndroid Build Coastguard Worker   // The location (register) of the marked object reference.
565*795d594fSAndroid Build Coastguard Worker   const Location ref_;
566*795d594fSAndroid Build Coastguard Worker   // Should the reference in `ref_` be unpoisoned prior to marking it?
567*795d594fSAndroid Build Coastguard Worker   const bool unpoison_ref_before_marking_;
568*795d594fSAndroid Build Coastguard Worker 
569*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86);
570*795d594fSAndroid Build Coastguard Worker };
571*795d594fSAndroid Build Coastguard Worker 
572*795d594fSAndroid Build Coastguard Worker // Slow path marking an object reference `ref` during a read barrier,
573*795d594fSAndroid Build Coastguard Worker // and if needed, atomically updating the field `obj.field` in the
574*795d594fSAndroid Build Coastguard Worker // object `obj` holding this reference after marking (contrary to
575*795d594fSAndroid Build Coastguard Worker // ReadBarrierMarkSlowPathX86 above, which never tries to update
576*795d594fSAndroid Build Coastguard Worker // `obj.field`).
577*795d594fSAndroid Build Coastguard Worker //
578*795d594fSAndroid Build Coastguard Worker // This means that after the execution of this slow path, both `ref`
579*795d594fSAndroid Build Coastguard Worker // and `obj.field` will be up-to-date; i.e., after the flip, both will
580*795d594fSAndroid Build Coastguard Worker // hold the same to-space reference (unless another thread installed
581*795d594fSAndroid Build Coastguard Worker // another object reference (different from `ref`) in `obj.field`).
582*795d594fSAndroid Build Coastguard Worker class ReadBarrierMarkAndUpdateFieldSlowPathX86 : public SlowPathCode {
583*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierMarkAndUpdateFieldSlowPathX86(HInstruction * instruction,Location ref,Register obj,const Address & field_addr,bool unpoison_ref_before_marking,Register temp)584*795d594fSAndroid Build Coastguard Worker   ReadBarrierMarkAndUpdateFieldSlowPathX86(HInstruction* instruction,
585*795d594fSAndroid Build Coastguard Worker                                            Location ref,
586*795d594fSAndroid Build Coastguard Worker                                            Register obj,
587*795d594fSAndroid Build Coastguard Worker                                            const Address& field_addr,
588*795d594fSAndroid Build Coastguard Worker                                            bool unpoison_ref_before_marking,
589*795d594fSAndroid Build Coastguard Worker                                            Register temp)
590*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction),
591*795d594fSAndroid Build Coastguard Worker         ref_(ref),
592*795d594fSAndroid Build Coastguard Worker         obj_(obj),
593*795d594fSAndroid Build Coastguard Worker         field_addr_(field_addr),
594*795d594fSAndroid Build Coastguard Worker         unpoison_ref_before_marking_(unpoison_ref_before_marking),
595*795d594fSAndroid Build Coastguard Worker         temp_(temp) {
596*795d594fSAndroid Build Coastguard Worker   }
597*795d594fSAndroid Build Coastguard Worker 
GetDescription() const598*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierMarkAndUpdateFieldSlowPathX86"; }
599*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)600*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
601*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen->EmitReadBarrier());
602*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
603*795d594fSAndroid Build Coastguard Worker     Register ref_reg = ref_.AsRegister<Register>();
604*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
605*795d594fSAndroid Build Coastguard Worker     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
606*795d594fSAndroid Build Coastguard Worker     DCHECK((instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
607*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier marking and field updating slow path: "
608*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
609*795d594fSAndroid Build Coastguard Worker     HInvoke* invoke = instruction_->AsInvoke();
610*795d594fSAndroid Build Coastguard Worker     DCHECK(IsUnsafeCASReference(invoke) ||
611*795d594fSAndroid Build Coastguard Worker            IsUnsafeGetAndSetReference(invoke) ||
612*795d594fSAndroid Build Coastguard Worker            IsVarHandleCASFamily(invoke)) << invoke->GetIntrinsic();
613*795d594fSAndroid Build Coastguard Worker 
614*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
615*795d594fSAndroid Build Coastguard Worker     if (unpoison_ref_before_marking_) {
616*795d594fSAndroid Build Coastguard Worker       // Object* ref = ref_addr->AsMirrorPtr()
617*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(ref_reg);
618*795d594fSAndroid Build Coastguard Worker     }
619*795d594fSAndroid Build Coastguard Worker 
620*795d594fSAndroid Build Coastguard Worker     // Save the old (unpoisoned) reference.
621*795d594fSAndroid Build Coastguard Worker     __ movl(temp_, ref_reg);
622*795d594fSAndroid Build Coastguard Worker 
623*795d594fSAndroid Build Coastguard Worker     // No need to save live registers; it's taken care of by the
624*795d594fSAndroid Build Coastguard Worker     // entrypoint. Also, there is no need to update the stack mask,
625*795d594fSAndroid Build Coastguard Worker     // as this runtime call will not trigger a garbage collection.
626*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
627*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(ref_reg, ESP);
628*795d594fSAndroid Build Coastguard Worker     DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
629*795d594fSAndroid Build Coastguard Worker     // "Compact" slow path, saving two moves.
630*795d594fSAndroid Build Coastguard Worker     //
631*795d594fSAndroid Build Coastguard Worker     // Instead of using the standard runtime calling convention (input
632*795d594fSAndroid Build Coastguard Worker     // and output in EAX):
633*795d594fSAndroid Build Coastguard Worker     //
634*795d594fSAndroid Build Coastguard Worker     //   EAX <- ref
635*795d594fSAndroid Build Coastguard Worker     //   EAX <- ReadBarrierMark(EAX)
636*795d594fSAndroid Build Coastguard Worker     //   ref <- EAX
637*795d594fSAndroid Build Coastguard Worker     //
638*795d594fSAndroid Build Coastguard Worker     // we just use rX (the register containing `ref`) as input and output
639*795d594fSAndroid Build Coastguard Worker     // of a dedicated entrypoint:
640*795d594fSAndroid Build Coastguard Worker     //
641*795d594fSAndroid Build Coastguard Worker     //   rX <- ReadBarrierMarkRegX(rX)
642*795d594fSAndroid Build Coastguard Worker     //
643*795d594fSAndroid Build Coastguard Worker     int32_t entry_point_offset = Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(ref_reg);
644*795d594fSAndroid Build Coastguard Worker     // This runtime call does not require a stack map.
645*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
646*795d594fSAndroid Build Coastguard Worker 
647*795d594fSAndroid Build Coastguard Worker     // If the new reference is different from the old reference,
648*795d594fSAndroid Build Coastguard Worker     // update the field in the holder (`*field_addr`).
649*795d594fSAndroid Build Coastguard Worker     //
650*795d594fSAndroid Build Coastguard Worker     // Note that this field could also hold a different object, if
651*795d594fSAndroid Build Coastguard Worker     // another thread had concurrently changed it. In that case, the
652*795d594fSAndroid Build Coastguard Worker     // LOCK CMPXCHGL instruction in the compare-and-set (CAS)
653*795d594fSAndroid Build Coastguard Worker     // operation below would abort the CAS, leaving the field as-is.
654*795d594fSAndroid Build Coastguard Worker     NearLabel done;
655*795d594fSAndroid Build Coastguard Worker     __ cmpl(temp_, ref_reg);
656*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &done);
657*795d594fSAndroid Build Coastguard Worker 
658*795d594fSAndroid Build Coastguard Worker     // Update the holder's field atomically.  This may fail if
659*795d594fSAndroid Build Coastguard Worker     // mutator updates before us, but it's OK.  This is achieved
660*795d594fSAndroid Build Coastguard Worker     // using a strong compare-and-set (CAS) operation with relaxed
661*795d594fSAndroid Build Coastguard Worker     // memory synchronization ordering, where the expected value is
662*795d594fSAndroid Build Coastguard Worker     // the old reference and the desired value is the new reference.
663*795d594fSAndroid Build Coastguard Worker     // This operation is implemented with a 32-bit LOCK CMPXLCHG
664*795d594fSAndroid Build Coastguard Worker     // instruction, which requires the expected value (the old
665*795d594fSAndroid Build Coastguard Worker     // reference) to be in EAX.  Save EAX beforehand, and move the
666*795d594fSAndroid Build Coastguard Worker     // expected value (stored in `temp_`) into EAX.
667*795d594fSAndroid Build Coastguard Worker     __ pushl(EAX);
668*795d594fSAndroid Build Coastguard Worker     __ movl(EAX, temp_);
669*795d594fSAndroid Build Coastguard Worker 
670*795d594fSAndroid Build Coastguard Worker     // Convenience aliases.
671*795d594fSAndroid Build Coastguard Worker     Register base = obj_;
672*795d594fSAndroid Build Coastguard Worker     Register expected = EAX;
673*795d594fSAndroid Build Coastguard Worker     Register value = ref_reg;
674*795d594fSAndroid Build Coastguard Worker 
675*795d594fSAndroid Build Coastguard Worker     bool base_equals_value = (base == value);
676*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences) {
677*795d594fSAndroid Build Coastguard Worker       if (base_equals_value) {
678*795d594fSAndroid Build Coastguard Worker         // If `base` and `value` are the same register location, move
679*795d594fSAndroid Build Coastguard Worker         // `value` to a temporary register.  This way, poisoning
680*795d594fSAndroid Build Coastguard Worker         // `value` won't invalidate `base`.
681*795d594fSAndroid Build Coastguard Worker         value = temp_;
682*795d594fSAndroid Build Coastguard Worker         __ movl(value, base);
683*795d594fSAndroid Build Coastguard Worker       }
684*795d594fSAndroid Build Coastguard Worker 
685*795d594fSAndroid Build Coastguard Worker       // Check that the register allocator did not assign the location
686*795d594fSAndroid Build Coastguard Worker       // of `expected` (EAX) to `value` nor to `base`, so that heap
687*795d594fSAndroid Build Coastguard Worker       // poisoning (when enabled) works as intended below.
688*795d594fSAndroid Build Coastguard Worker       // - If `value` were equal to `expected`, both references would
689*795d594fSAndroid Build Coastguard Worker       //   be poisoned twice, meaning they would not be poisoned at
690*795d594fSAndroid Build Coastguard Worker       //   all, as heap poisoning uses address negation.
691*795d594fSAndroid Build Coastguard Worker       // - If `base` were equal to `expected`, poisoning `expected`
692*795d594fSAndroid Build Coastguard Worker       //   would invalidate `base`.
693*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(value, expected);
694*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(base, expected);
695*795d594fSAndroid Build Coastguard Worker 
696*795d594fSAndroid Build Coastguard Worker       __ PoisonHeapReference(expected);
697*795d594fSAndroid Build Coastguard Worker       __ PoisonHeapReference(value);
698*795d594fSAndroid Build Coastguard Worker     }
699*795d594fSAndroid Build Coastguard Worker 
700*795d594fSAndroid Build Coastguard Worker     __ LockCmpxchgl(field_addr_, value);
701*795d594fSAndroid Build Coastguard Worker 
702*795d594fSAndroid Build Coastguard Worker     // If heap poisoning is enabled, we need to unpoison the values
703*795d594fSAndroid Build Coastguard Worker     // that were poisoned earlier.
704*795d594fSAndroid Build Coastguard Worker     if (kPoisonHeapReferences) {
705*795d594fSAndroid Build Coastguard Worker       if (base_equals_value) {
706*795d594fSAndroid Build Coastguard Worker         // `value` has been moved to a temporary register, no need
707*795d594fSAndroid Build Coastguard Worker         // to unpoison it.
708*795d594fSAndroid Build Coastguard Worker       } else {
709*795d594fSAndroid Build Coastguard Worker         __ UnpoisonHeapReference(value);
710*795d594fSAndroid Build Coastguard Worker       }
711*795d594fSAndroid Build Coastguard Worker       // No need to unpoison `expected` (EAX), as it is be overwritten below.
712*795d594fSAndroid Build Coastguard Worker     }
713*795d594fSAndroid Build Coastguard Worker 
714*795d594fSAndroid Build Coastguard Worker     // Restore EAX.
715*795d594fSAndroid Build Coastguard Worker     __ popl(EAX);
716*795d594fSAndroid Build Coastguard Worker 
717*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
718*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
719*795d594fSAndroid Build Coastguard Worker   }
720*795d594fSAndroid Build Coastguard Worker 
721*795d594fSAndroid Build Coastguard Worker  private:
722*795d594fSAndroid Build Coastguard Worker   // The location (register) of the marked object reference.
723*795d594fSAndroid Build Coastguard Worker   const Location ref_;
724*795d594fSAndroid Build Coastguard Worker   // The register containing the object holding the marked object reference field.
725*795d594fSAndroid Build Coastguard Worker   const Register obj_;
726*795d594fSAndroid Build Coastguard Worker   // The address of the marked reference field.  The base of this address must be `obj_`.
727*795d594fSAndroid Build Coastguard Worker   const Address field_addr_;
728*795d594fSAndroid Build Coastguard Worker 
729*795d594fSAndroid Build Coastguard Worker   // Should the reference in `ref_` be unpoisoned prior to marking it?
730*795d594fSAndroid Build Coastguard Worker   const bool unpoison_ref_before_marking_;
731*795d594fSAndroid Build Coastguard Worker 
732*795d594fSAndroid Build Coastguard Worker   const Register temp_;
733*795d594fSAndroid Build Coastguard Worker 
734*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathX86);
735*795d594fSAndroid Build Coastguard Worker };
736*795d594fSAndroid Build Coastguard Worker 
737*795d594fSAndroid Build Coastguard Worker // Slow path generating a read barrier for a heap reference.
738*795d594fSAndroid Build Coastguard Worker class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode {
739*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierForHeapReferenceSlowPathX86(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)740*795d594fSAndroid Build Coastguard Worker   ReadBarrierForHeapReferenceSlowPathX86(HInstruction* instruction,
741*795d594fSAndroid Build Coastguard Worker                                          Location out,
742*795d594fSAndroid Build Coastguard Worker                                          Location ref,
743*795d594fSAndroid Build Coastguard Worker                                          Location obj,
744*795d594fSAndroid Build Coastguard Worker                                          uint32_t offset,
745*795d594fSAndroid Build Coastguard Worker                                          Location index)
746*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction),
747*795d594fSAndroid Build Coastguard Worker         out_(out),
748*795d594fSAndroid Build Coastguard Worker         ref_(ref),
749*795d594fSAndroid Build Coastguard Worker         obj_(obj),
750*795d594fSAndroid Build Coastguard Worker         offset_(offset),
751*795d594fSAndroid Build Coastguard Worker         index_(index) {
752*795d594fSAndroid Build Coastguard Worker     // If `obj` is equal to `out` or `ref`, it means the initial object
753*795d594fSAndroid Build Coastguard Worker     // has been overwritten by (or after) the heap object reference load
754*795d594fSAndroid Build Coastguard Worker     // to be instrumented, e.g.:
755*795d594fSAndroid Build Coastguard Worker     //
756*795d594fSAndroid Build Coastguard Worker     //   __ movl(out, Address(out, offset));
757*795d594fSAndroid Build Coastguard Worker     //   codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
758*795d594fSAndroid Build Coastguard Worker     //
759*795d594fSAndroid Build Coastguard Worker     // In that case, we have lost the information about the original
760*795d594fSAndroid Build Coastguard Worker     // object, and the emitted read barrier cannot work properly.
761*795d594fSAndroid Build Coastguard Worker     DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
762*795d594fSAndroid Build Coastguard Worker     DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
763*795d594fSAndroid Build Coastguard Worker   }
764*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)765*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
766*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen->EmitReadBarrier());
767*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
768*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
769*795d594fSAndroid Build Coastguard Worker     Register reg_out = out_.AsRegister<Register>();
770*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
771*795d594fSAndroid Build Coastguard Worker     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
772*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsInstanceFieldGet() ||
773*795d594fSAndroid Build Coastguard Worker            instruction_->IsStaticFieldGet() ||
774*795d594fSAndroid Build Coastguard Worker            instruction_->IsArrayGet() ||
775*795d594fSAndroid Build Coastguard Worker            instruction_->IsInstanceOf() ||
776*795d594fSAndroid Build Coastguard Worker            instruction_->IsCheckCast() ||
777*795d594fSAndroid Build Coastguard Worker            (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
778*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier for heap reference slow path: "
779*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
780*795d594fSAndroid Build Coastguard Worker 
781*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
782*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
783*795d594fSAndroid Build Coastguard Worker 
784*795d594fSAndroid Build Coastguard Worker     // We may have to change the index's value, but as `index_` is a
785*795d594fSAndroid Build Coastguard Worker     // constant member (like other "inputs" of this slow path),
786*795d594fSAndroid Build Coastguard Worker     // introduce a copy of it, `index`.
787*795d594fSAndroid Build Coastguard Worker     Location index = index_;
788*795d594fSAndroid Build Coastguard Worker     if (index_.IsValid()) {
789*795d594fSAndroid Build Coastguard Worker       // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
790*795d594fSAndroid Build Coastguard Worker       if (instruction_->IsArrayGet()) {
791*795d594fSAndroid Build Coastguard Worker         // Compute the actual memory offset and store it in `index`.
792*795d594fSAndroid Build Coastguard Worker         Register index_reg = index_.AsRegister<Register>();
793*795d594fSAndroid Build Coastguard Worker         DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
794*795d594fSAndroid Build Coastguard Worker         if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
795*795d594fSAndroid Build Coastguard Worker           // We are about to change the value of `index_reg` (see the
796*795d594fSAndroid Build Coastguard Worker           // calls to art::x86::X86Assembler::shll and
797*795d594fSAndroid Build Coastguard Worker           // art::x86::X86Assembler::AddImmediate below), but it has
798*795d594fSAndroid Build Coastguard Worker           // not been saved by the previous call to
799*795d594fSAndroid Build Coastguard Worker           // art::SlowPathCode::SaveLiveRegisters, as it is a
800*795d594fSAndroid Build Coastguard Worker           // callee-save register --
801*795d594fSAndroid Build Coastguard Worker           // art::SlowPathCode::SaveLiveRegisters does not consider
802*795d594fSAndroid Build Coastguard Worker           // callee-save registers, as it has been designed with the
803*795d594fSAndroid Build Coastguard Worker           // assumption that callee-save registers are supposed to be
804*795d594fSAndroid Build Coastguard Worker           // handled by the called function.  So, as a callee-save
805*795d594fSAndroid Build Coastguard Worker           // register, `index_reg` _would_ eventually be saved onto
806*795d594fSAndroid Build Coastguard Worker           // the stack, but it would be too late: we would have
807*795d594fSAndroid Build Coastguard Worker           // changed its value earlier.  Therefore, we manually save
808*795d594fSAndroid Build Coastguard Worker           // it here into another freely available register,
809*795d594fSAndroid Build Coastguard Worker           // `free_reg`, chosen of course among the caller-save
810*795d594fSAndroid Build Coastguard Worker           // registers (as a callee-save `free_reg` register would
811*795d594fSAndroid Build Coastguard Worker           // exhibit the same problem).
812*795d594fSAndroid Build Coastguard Worker           //
813*795d594fSAndroid Build Coastguard Worker           // Note we could have requested a temporary register from
814*795d594fSAndroid Build Coastguard Worker           // the register allocator instead; but we prefer not to, as
815*795d594fSAndroid Build Coastguard Worker           // this is a slow path, and we know we can find a
816*795d594fSAndroid Build Coastguard Worker           // caller-save register that is available.
817*795d594fSAndroid Build Coastguard Worker           Register free_reg = FindAvailableCallerSaveRegister(codegen);
818*795d594fSAndroid Build Coastguard Worker           __ movl(free_reg, index_reg);
819*795d594fSAndroid Build Coastguard Worker           index_reg = free_reg;
820*795d594fSAndroid Build Coastguard Worker           index = Location::RegisterLocation(index_reg);
821*795d594fSAndroid Build Coastguard Worker         } else {
822*795d594fSAndroid Build Coastguard Worker           // The initial register stored in `index_` has already been
823*795d594fSAndroid Build Coastguard Worker           // saved in the call to art::SlowPathCode::SaveLiveRegisters
824*795d594fSAndroid Build Coastguard Worker           // (as it is not a callee-save register), so we can freely
825*795d594fSAndroid Build Coastguard Worker           // use it.
826*795d594fSAndroid Build Coastguard Worker         }
827*795d594fSAndroid Build Coastguard Worker         // Shifting the index value contained in `index_reg` by the scale
828*795d594fSAndroid Build Coastguard Worker         // factor (2) cannot overflow in practice, as the runtime is
829*795d594fSAndroid Build Coastguard Worker         // unable to allocate object arrays with a size larger than
830*795d594fSAndroid Build Coastguard Worker         // 2^26 - 1 (that is, 2^28 - 4 bytes).
831*795d594fSAndroid Build Coastguard Worker         __ shll(index_reg, Immediate(TIMES_4));
832*795d594fSAndroid Build Coastguard Worker         static_assert(
833*795d594fSAndroid Build Coastguard Worker             sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
834*795d594fSAndroid Build Coastguard Worker             "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
835*795d594fSAndroid Build Coastguard Worker         __ AddImmediate(index_reg, Immediate(offset_));
836*795d594fSAndroid Build Coastguard Worker       } else {
837*795d594fSAndroid Build Coastguard Worker         // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
838*795d594fSAndroid Build Coastguard Worker         // intrinsics, `index_` is not shifted by a scale factor of 2
839*795d594fSAndroid Build Coastguard Worker         // (as in the case of ArrayGet), as it is actually an offset
840*795d594fSAndroid Build Coastguard Worker         // to an object field within an object.
841*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
842*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction_->GetLocations()->Intrinsified());
843*795d594fSAndroid Build Coastguard Worker         DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
844*795d594fSAndroid Build Coastguard Worker                (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile) ||
845*795d594fSAndroid Build Coastguard Worker                (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kJdkUnsafeGetReference) ||
846*795d594fSAndroid Build Coastguard Worker                (instruction_->AsInvoke()->GetIntrinsic() ==
847*795d594fSAndroid Build Coastguard Worker                     Intrinsics::kJdkUnsafeGetReferenceVolatile) ||
848*795d594fSAndroid Build Coastguard Worker                (instruction_->AsInvoke()->GetIntrinsic() ==
849*795d594fSAndroid Build Coastguard Worker                     Intrinsics::kJdkUnsafeGetReferenceAcquire))
850*795d594fSAndroid Build Coastguard Worker             << instruction_->AsInvoke()->GetIntrinsic();
851*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(offset_, 0U);
852*795d594fSAndroid Build Coastguard Worker         DCHECK(index_.IsRegisterPair());
853*795d594fSAndroid Build Coastguard Worker         // UnsafeGet's offset location is a register pair, the low
854*795d594fSAndroid Build Coastguard Worker         // part contains the correct offset.
855*795d594fSAndroid Build Coastguard Worker         index = index_.ToLow();
856*795d594fSAndroid Build Coastguard Worker       }
857*795d594fSAndroid Build Coastguard Worker     }
858*795d594fSAndroid Build Coastguard Worker 
859*795d594fSAndroid Build Coastguard Worker     // We're moving two or three locations to locations that could
860*795d594fSAndroid Build Coastguard Worker     // overlap, so we need a parallel move resolver.
861*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
862*795d594fSAndroid Build Coastguard Worker     HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
863*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(ref_,
864*795d594fSAndroid Build Coastguard Worker                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
865*795d594fSAndroid Build Coastguard Worker                           DataType::Type::kReference,
866*795d594fSAndroid Build Coastguard Worker                           nullptr);
867*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(obj_,
868*795d594fSAndroid Build Coastguard Worker                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
869*795d594fSAndroid Build Coastguard Worker                           DataType::Type::kReference,
870*795d594fSAndroid Build Coastguard Worker                           nullptr);
871*795d594fSAndroid Build Coastguard Worker     if (index.IsValid()) {
872*795d594fSAndroid Build Coastguard Worker       parallel_move.AddMove(index,
873*795d594fSAndroid Build Coastguard Worker                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
874*795d594fSAndroid Build Coastguard Worker                             DataType::Type::kInt32,
875*795d594fSAndroid Build Coastguard Worker                             nullptr);
876*795d594fSAndroid Build Coastguard Worker       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
877*795d594fSAndroid Build Coastguard Worker     } else {
878*795d594fSAndroid Build Coastguard Worker       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
879*795d594fSAndroid Build Coastguard Worker       __ movl(calling_convention.GetRegisterAt(2), Immediate(offset_));
880*795d594fSAndroid Build Coastguard Worker     }
881*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
882*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<
883*795d594fSAndroid Build Coastguard Worker         kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
884*795d594fSAndroid Build Coastguard Worker     x86_codegen->Move32(out_, Location::RegisterLocation(EAX));
885*795d594fSAndroid Build Coastguard Worker 
886*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
887*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
888*795d594fSAndroid Build Coastguard Worker   }
889*795d594fSAndroid Build Coastguard Worker 
GetDescription() const890*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierForHeapReferenceSlowPathX86"; }
891*795d594fSAndroid Build Coastguard Worker 
892*795d594fSAndroid Build Coastguard Worker  private:
FindAvailableCallerSaveRegister(CodeGenerator * codegen)893*795d594fSAndroid Build Coastguard Worker   Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
894*795d594fSAndroid Build Coastguard Worker     size_t ref = static_cast<int>(ref_.AsRegister<Register>());
895*795d594fSAndroid Build Coastguard Worker     size_t obj = static_cast<int>(obj_.AsRegister<Register>());
896*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
897*795d594fSAndroid Build Coastguard Worker       if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
898*795d594fSAndroid Build Coastguard Worker         return static_cast<Register>(i);
899*795d594fSAndroid Build Coastguard Worker       }
900*795d594fSAndroid Build Coastguard Worker     }
901*795d594fSAndroid Build Coastguard Worker     // We shall never fail to find a free caller-save register, as
902*795d594fSAndroid Build Coastguard Worker     // there are more than two core caller-save registers on x86
903*795d594fSAndroid Build Coastguard Worker     // (meaning it is possible to find one which is different from
904*795d594fSAndroid Build Coastguard Worker     // `ref` and `obj`).
905*795d594fSAndroid Build Coastguard Worker     DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
906*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Could not find a free caller-save register";
907*795d594fSAndroid Build Coastguard Worker     UNREACHABLE();
908*795d594fSAndroid Build Coastguard Worker   }
909*795d594fSAndroid Build Coastguard Worker 
910*795d594fSAndroid Build Coastguard Worker   const Location out_;
911*795d594fSAndroid Build Coastguard Worker   const Location ref_;
912*795d594fSAndroid Build Coastguard Worker   const Location obj_;
913*795d594fSAndroid Build Coastguard Worker   const uint32_t offset_;
914*795d594fSAndroid Build Coastguard Worker   // An additional location containing an index to an array.
915*795d594fSAndroid Build Coastguard Worker   // Only used for HArrayGet and the UnsafeGetObject &
916*795d594fSAndroid Build Coastguard Worker   // UnsafeGetObjectVolatile intrinsics.
917*795d594fSAndroid Build Coastguard Worker   const Location index_;
918*795d594fSAndroid Build Coastguard Worker 
919*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86);
920*795d594fSAndroid Build Coastguard Worker };
921*795d594fSAndroid Build Coastguard Worker 
922*795d594fSAndroid Build Coastguard Worker // Slow path generating a read barrier for a GC root.
923*795d594fSAndroid Build Coastguard Worker class ReadBarrierForRootSlowPathX86 : public SlowPathCode {
924*795d594fSAndroid Build Coastguard Worker  public:
ReadBarrierForRootSlowPathX86(HInstruction * instruction,Location out,Location root)925*795d594fSAndroid Build Coastguard Worker   ReadBarrierForRootSlowPathX86(HInstruction* instruction, Location out, Location root)
926*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(instruction), out_(out), root_(root) {
927*795d594fSAndroid Build Coastguard Worker   }
928*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)929*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
930*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen->EmitReadBarrier());
931*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
932*795d594fSAndroid Build Coastguard Worker     Register reg_out = out_.AsRegister<Register>();
933*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->CanCall());
934*795d594fSAndroid Build Coastguard Worker     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
935*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
936*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction in read barrier for GC root slow path: "
937*795d594fSAndroid Build Coastguard Worker         << instruction_->DebugName();
938*795d594fSAndroid Build Coastguard Worker 
939*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
940*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
941*795d594fSAndroid Build Coastguard Worker 
942*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
943*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
944*795d594fSAndroid Build Coastguard Worker     x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
945*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
946*795d594fSAndroid Build Coastguard Worker                                instruction_,
947*795d594fSAndroid Build Coastguard Worker                                instruction_->GetDexPc(),
948*795d594fSAndroid Build Coastguard Worker                                this);
949*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
950*795d594fSAndroid Build Coastguard Worker     x86_codegen->Move32(out_, Location::RegisterLocation(EAX));
951*795d594fSAndroid Build Coastguard Worker 
952*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
953*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
954*795d594fSAndroid Build Coastguard Worker   }
955*795d594fSAndroid Build Coastguard Worker 
GetDescription() const956*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override { return "ReadBarrierForRootSlowPathX86"; }
957*795d594fSAndroid Build Coastguard Worker 
958*795d594fSAndroid Build Coastguard Worker  private:
959*795d594fSAndroid Build Coastguard Worker   const Location out_;
960*795d594fSAndroid Build Coastguard Worker   const Location root_;
961*795d594fSAndroid Build Coastguard Worker 
962*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86);
963*795d594fSAndroid Build Coastguard Worker };
964*795d594fSAndroid Build Coastguard Worker 
965*795d594fSAndroid Build Coastguard Worker class MethodEntryExitHooksSlowPathX86 : public SlowPathCode {
966*795d594fSAndroid Build Coastguard Worker  public:
MethodEntryExitHooksSlowPathX86(HInstruction * instruction)967*795d594fSAndroid Build Coastguard Worker   explicit MethodEntryExitHooksSlowPathX86(HInstruction* instruction) : SlowPathCode(instruction) {}
968*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)969*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
970*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
971*795d594fSAndroid Build Coastguard Worker     LocationSummary* locations = instruction_->GetLocations();
972*795d594fSAndroid Build Coastguard Worker     QuickEntrypointEnum entry_point =
973*795d594fSAndroid Build Coastguard Worker         (instruction_->IsMethodEntryHook()) ? kQuickMethodEntryHook : kQuickMethodExitHook;
974*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
975*795d594fSAndroid Build Coastguard Worker     SaveLiveRegisters(codegen, locations);
976*795d594fSAndroid Build Coastguard Worker     if (instruction_->IsMethodExitHook()) {
977*795d594fSAndroid Build Coastguard Worker       __ movl(EBX, Immediate(codegen->GetFrameSize()));
978*795d594fSAndroid Build Coastguard Worker     }
979*795d594fSAndroid Build Coastguard Worker     x86_codegen->InvokeRuntime(entry_point, instruction_, instruction_->GetDexPc(), this);
980*795d594fSAndroid Build Coastguard Worker     RestoreLiveRegisters(codegen, locations);
981*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
982*795d594fSAndroid Build Coastguard Worker   }
983*795d594fSAndroid Build Coastguard Worker 
GetDescription() const984*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override {
985*795d594fSAndroid Build Coastguard Worker     return "MethodEntryExitHooksSlowPath";
986*795d594fSAndroid Build Coastguard Worker   }
987*795d594fSAndroid Build Coastguard Worker 
988*795d594fSAndroid Build Coastguard Worker  private:
989*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(MethodEntryExitHooksSlowPathX86);
990*795d594fSAndroid Build Coastguard Worker };
991*795d594fSAndroid Build Coastguard Worker 
992*795d594fSAndroid Build Coastguard Worker class CompileOptimizedSlowPathX86 : public SlowPathCode {
993*795d594fSAndroid Build Coastguard Worker  public:
CompileOptimizedSlowPathX86(HSuspendCheck * suspend_check,uint32_t counter_address)994*795d594fSAndroid Build Coastguard Worker   CompileOptimizedSlowPathX86(HSuspendCheck* suspend_check, uint32_t counter_address)
995*795d594fSAndroid Build Coastguard Worker       : SlowPathCode(suspend_check),
996*795d594fSAndroid Build Coastguard Worker         counter_address_(counter_address) {}
997*795d594fSAndroid Build Coastguard Worker 
EmitNativeCode(CodeGenerator * codegen)998*795d594fSAndroid Build Coastguard Worker   void EmitNativeCode(CodeGenerator* codegen) override {
999*795d594fSAndroid Build Coastguard Worker     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
1000*795d594fSAndroid Build Coastguard Worker     __ Bind(GetEntryLabel());
1001*795d594fSAndroid Build Coastguard Worker     __ movw(Address::Absolute(counter_address_), Immediate(ProfilingInfo::GetOptimizeThreshold()));
1002*795d594fSAndroid Build Coastguard Worker     if (instruction_ != nullptr) {
1003*795d594fSAndroid Build Coastguard Worker       // Only saves full width XMM for SIMD.
1004*795d594fSAndroid Build Coastguard Worker       SaveLiveRegisters(codegen, instruction_->GetLocations());
1005*795d594fSAndroid Build Coastguard Worker     }
1006*795d594fSAndroid Build Coastguard Worker     x86_codegen->GenerateInvokeRuntime(
1007*795d594fSAndroid Build Coastguard Worker         GetThreadOffset<kX86PointerSize>(kQuickCompileOptimized).Int32Value());
1008*795d594fSAndroid Build Coastguard Worker     if (instruction_ != nullptr) {
1009*795d594fSAndroid Build Coastguard Worker       // Only restores full width XMM for SIMD.
1010*795d594fSAndroid Build Coastguard Worker       RestoreLiveRegisters(codegen, instruction_->GetLocations());
1011*795d594fSAndroid Build Coastguard Worker     }
1012*795d594fSAndroid Build Coastguard Worker     __ jmp(GetExitLabel());
1013*795d594fSAndroid Build Coastguard Worker   }
1014*795d594fSAndroid Build Coastguard Worker 
GetDescription() const1015*795d594fSAndroid Build Coastguard Worker   const char* GetDescription() const override {
1016*795d594fSAndroid Build Coastguard Worker     return "CompileOptimizedSlowPath";
1017*795d594fSAndroid Build Coastguard Worker   }
1018*795d594fSAndroid Build Coastguard Worker 
1019*795d594fSAndroid Build Coastguard Worker  private:
1020*795d594fSAndroid Build Coastguard Worker   uint32_t counter_address_;
1021*795d594fSAndroid Build Coastguard Worker 
1022*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(CompileOptimizedSlowPathX86);
1023*795d594fSAndroid Build Coastguard Worker };
1024*795d594fSAndroid Build Coastguard Worker 
1025*795d594fSAndroid Build Coastguard Worker #undef __
1026*795d594fSAndroid Build Coastguard Worker // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1027*795d594fSAndroid Build Coastguard Worker #define __ down_cast<X86Assembler*>(GetAssembler())->  // NOLINT
1028*795d594fSAndroid Build Coastguard Worker 
X86Condition(IfCondition cond)1029*795d594fSAndroid Build Coastguard Worker inline Condition X86Condition(IfCondition cond) {
1030*795d594fSAndroid Build Coastguard Worker   switch (cond) {
1031*795d594fSAndroid Build Coastguard Worker     case kCondEQ: return kEqual;
1032*795d594fSAndroid Build Coastguard Worker     case kCondNE: return kNotEqual;
1033*795d594fSAndroid Build Coastguard Worker     case kCondLT: return kLess;
1034*795d594fSAndroid Build Coastguard Worker     case kCondLE: return kLessEqual;
1035*795d594fSAndroid Build Coastguard Worker     case kCondGT: return kGreater;
1036*795d594fSAndroid Build Coastguard Worker     case kCondGE: return kGreaterEqual;
1037*795d594fSAndroid Build Coastguard Worker     case kCondB:  return kBelow;
1038*795d594fSAndroid Build Coastguard Worker     case kCondBE: return kBelowEqual;
1039*795d594fSAndroid Build Coastguard Worker     case kCondA:  return kAbove;
1040*795d594fSAndroid Build Coastguard Worker     case kCondAE: return kAboveEqual;
1041*795d594fSAndroid Build Coastguard Worker   }
1042*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
1043*795d594fSAndroid Build Coastguard Worker   UNREACHABLE();
1044*795d594fSAndroid Build Coastguard Worker }
1045*795d594fSAndroid Build Coastguard Worker 
1046*795d594fSAndroid Build Coastguard Worker // Maps signed condition to unsigned condition and FP condition to x86 name.
X86UnsignedOrFPCondition(IfCondition cond)1047*795d594fSAndroid Build Coastguard Worker inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
1048*795d594fSAndroid Build Coastguard Worker   switch (cond) {
1049*795d594fSAndroid Build Coastguard Worker     case kCondEQ: return kEqual;
1050*795d594fSAndroid Build Coastguard Worker     case kCondNE: return kNotEqual;
1051*795d594fSAndroid Build Coastguard Worker     // Signed to unsigned, and FP to x86 name.
1052*795d594fSAndroid Build Coastguard Worker     case kCondLT: return kBelow;
1053*795d594fSAndroid Build Coastguard Worker     case kCondLE: return kBelowEqual;
1054*795d594fSAndroid Build Coastguard Worker     case kCondGT: return kAbove;
1055*795d594fSAndroid Build Coastguard Worker     case kCondGE: return kAboveEqual;
1056*795d594fSAndroid Build Coastguard Worker     // Unsigned remain unchanged.
1057*795d594fSAndroid Build Coastguard Worker     case kCondB:  return kBelow;
1058*795d594fSAndroid Build Coastguard Worker     case kCondBE: return kBelowEqual;
1059*795d594fSAndroid Build Coastguard Worker     case kCondA:  return kAbove;
1060*795d594fSAndroid Build Coastguard Worker     case kCondAE: return kAboveEqual;
1061*795d594fSAndroid Build Coastguard Worker   }
1062*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
1063*795d594fSAndroid Build Coastguard Worker   UNREACHABLE();
1064*795d594fSAndroid Build Coastguard Worker }
1065*795d594fSAndroid Build Coastguard Worker 
DumpCoreRegister(std::ostream & stream,int reg) const1066*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
1067*795d594fSAndroid Build Coastguard Worker   stream << Register(reg);
1068*795d594fSAndroid Build Coastguard Worker }
1069*795d594fSAndroid Build Coastguard Worker 
DumpFloatingPointRegister(std::ostream & stream,int reg) const1070*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
1071*795d594fSAndroid Build Coastguard Worker   stream << XmmRegister(reg);
1072*795d594fSAndroid Build Coastguard Worker }
1073*795d594fSAndroid Build Coastguard Worker 
GetInstructionSetFeatures() const1074*795d594fSAndroid Build Coastguard Worker const X86InstructionSetFeatures& CodeGeneratorX86::GetInstructionSetFeatures() const {
1075*795d594fSAndroid Build Coastguard Worker   return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86InstructionSetFeatures();
1076*795d594fSAndroid Build Coastguard Worker }
1077*795d594fSAndroid Build Coastguard Worker 
SaveCoreRegister(size_t stack_index,uint32_t reg_id)1078*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1079*795d594fSAndroid Build Coastguard Worker   __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
1080*795d594fSAndroid Build Coastguard Worker   return kX86WordSize;
1081*795d594fSAndroid Build Coastguard Worker }
1082*795d594fSAndroid Build Coastguard Worker 
RestoreCoreRegister(size_t stack_index,uint32_t reg_id)1083*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1084*795d594fSAndroid Build Coastguard Worker   __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
1085*795d594fSAndroid Build Coastguard Worker   return kX86WordSize;
1086*795d594fSAndroid Build Coastguard Worker }
1087*795d594fSAndroid Build Coastguard Worker 
SaveFloatingPointRegister(size_t stack_index,uint32_t reg_id)1088*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1089*795d594fSAndroid Build Coastguard Worker   if (GetGraph()->HasSIMD()) {
1090*795d594fSAndroid Build Coastguard Worker     __ movups(Address(ESP, stack_index), XmmRegister(reg_id));
1091*795d594fSAndroid Build Coastguard Worker   } else {
1092*795d594fSAndroid Build Coastguard Worker     __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
1093*795d594fSAndroid Build Coastguard Worker   }
1094*795d594fSAndroid Build Coastguard Worker   return GetSlowPathFPWidth();
1095*795d594fSAndroid Build Coastguard Worker }
1096*795d594fSAndroid Build Coastguard Worker 
RestoreFloatingPointRegister(size_t stack_index,uint32_t reg_id)1097*795d594fSAndroid Build Coastguard Worker size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1098*795d594fSAndroid Build Coastguard Worker   if (GetGraph()->HasSIMD()) {
1099*795d594fSAndroid Build Coastguard Worker     __ movups(XmmRegister(reg_id), Address(ESP, stack_index));
1100*795d594fSAndroid Build Coastguard Worker   } else {
1101*795d594fSAndroid Build Coastguard Worker     __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
1102*795d594fSAndroid Build Coastguard Worker   }
1103*795d594fSAndroid Build Coastguard Worker   return GetSlowPathFPWidth();
1104*795d594fSAndroid Build Coastguard Worker }
1105*795d594fSAndroid Build Coastguard Worker 
InvokeRuntime(QuickEntrypointEnum entrypoint,HInstruction * instruction,uint32_t dex_pc,SlowPathCode * slow_path)1106*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint,
1107*795d594fSAndroid Build Coastguard Worker                                      HInstruction* instruction,
1108*795d594fSAndroid Build Coastguard Worker                                      uint32_t dex_pc,
1109*795d594fSAndroid Build Coastguard Worker                                      SlowPathCode* slow_path) {
1110*795d594fSAndroid Build Coastguard Worker   ValidateInvokeRuntime(entrypoint, instruction, slow_path);
1111*795d594fSAndroid Build Coastguard Worker   GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(entrypoint).Int32Value());
1112*795d594fSAndroid Build Coastguard Worker   if (EntrypointRequiresStackMap(entrypoint)) {
1113*795d594fSAndroid Build Coastguard Worker     RecordPcInfo(instruction, dex_pc, slow_path);
1114*795d594fSAndroid Build Coastguard Worker   }
1115*795d594fSAndroid Build Coastguard Worker }
1116*795d594fSAndroid Build Coastguard Worker 
InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,HInstruction * instruction,SlowPathCode * slow_path)1117*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1118*795d594fSAndroid Build Coastguard Worker                                                            HInstruction* instruction,
1119*795d594fSAndroid Build Coastguard Worker                                                            SlowPathCode* slow_path) {
1120*795d594fSAndroid Build Coastguard Worker   ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1121*795d594fSAndroid Build Coastguard Worker   GenerateInvokeRuntime(entry_point_offset);
1122*795d594fSAndroid Build Coastguard Worker }
1123*795d594fSAndroid Build Coastguard Worker 
GenerateInvokeRuntime(int32_t entry_point_offset)1124*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateInvokeRuntime(int32_t entry_point_offset) {
1125*795d594fSAndroid Build Coastguard Worker   __ fs()->call(Address::Absolute(entry_point_offset));
1126*795d594fSAndroid Build Coastguard Worker }
1127*795d594fSAndroid Build Coastguard Worker 
1128*795d594fSAndroid Build Coastguard Worker namespace detail {
1129*795d594fSAndroid Build Coastguard Worker 
1130*795d594fSAndroid Build Coastguard Worker // Mark which intrinsics we don't have handcrafted code for.
1131*795d594fSAndroid Build Coastguard Worker template <Intrinsics T>
1132*795d594fSAndroid Build Coastguard Worker struct IsUnimplemented {
1133*795d594fSAndroid Build Coastguard Worker   bool is_unimplemented = false;
1134*795d594fSAndroid Build Coastguard Worker };
1135*795d594fSAndroid Build Coastguard Worker 
1136*795d594fSAndroid Build Coastguard Worker #define TRUE_OVERRIDE(Name)                     \
1137*795d594fSAndroid Build Coastguard Worker   template <>                                   \
1138*795d594fSAndroid Build Coastguard Worker   struct IsUnimplemented<Intrinsics::k##Name> { \
1139*795d594fSAndroid Build Coastguard Worker     bool is_unimplemented = true;               \
1140*795d594fSAndroid Build Coastguard Worker   };
1141*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED_INTRINSIC_LIST_X86(TRUE_OVERRIDE)
1142*795d594fSAndroid Build Coastguard Worker #undef TRUE_OVERRIDE
1143*795d594fSAndroid Build Coastguard Worker 
1144*795d594fSAndroid Build Coastguard Worker static constexpr bool kIsIntrinsicUnimplemented[] = {
1145*795d594fSAndroid Build Coastguard Worker     false,  // kNone
1146*795d594fSAndroid Build Coastguard Worker #define IS_UNIMPLEMENTED(Intrinsic, ...) \
1147*795d594fSAndroid Build Coastguard Worker     IsUnimplemented<Intrinsics::k##Intrinsic>().is_unimplemented,
1148*795d594fSAndroid Build Coastguard Worker     ART_INTRINSICS_LIST(IS_UNIMPLEMENTED)
1149*795d594fSAndroid Build Coastguard Worker #undef IS_UNIMPLEMENTED
1150*795d594fSAndroid Build Coastguard Worker };
1151*795d594fSAndroid Build Coastguard Worker 
1152*795d594fSAndroid Build Coastguard Worker }  // namespace detail
1153*795d594fSAndroid Build Coastguard Worker 
CodeGeneratorX86(HGraph * graph,const CompilerOptions & compiler_options,OptimizingCompilerStats * stats)1154*795d594fSAndroid Build Coastguard Worker CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
1155*795d594fSAndroid Build Coastguard Worker                                    const CompilerOptions& compiler_options,
1156*795d594fSAndroid Build Coastguard Worker                                    OptimizingCompilerStats* stats)
1157*795d594fSAndroid Build Coastguard Worker     : CodeGenerator(graph,
1158*795d594fSAndroid Build Coastguard Worker                     kNumberOfCpuRegisters,
1159*795d594fSAndroid Build Coastguard Worker                     kNumberOfXmmRegisters,
1160*795d594fSAndroid Build Coastguard Worker                     kNumberOfRegisterPairs,
1161*795d594fSAndroid Build Coastguard Worker                     ComputeRegisterMask(kCoreCalleeSaves, arraysize(kCoreCalleeSaves))
1162*795d594fSAndroid Build Coastguard Worker                         | (1 << kFakeReturnRegister),
1163*795d594fSAndroid Build Coastguard Worker                     0,
1164*795d594fSAndroid Build Coastguard Worker                     compiler_options,
1165*795d594fSAndroid Build Coastguard Worker                     stats,
1166*795d594fSAndroid Build Coastguard Worker                     ArrayRef<const bool>(detail::kIsIntrinsicUnimplemented)),
1167*795d594fSAndroid Build Coastguard Worker       block_labels_(nullptr),
1168*795d594fSAndroid Build Coastguard Worker       location_builder_(graph, this),
1169*795d594fSAndroid Build Coastguard Worker       instruction_visitor_(graph, this),
1170*795d594fSAndroid Build Coastguard Worker       move_resolver_(graph->GetAllocator(), this),
1171*795d594fSAndroid Build Coastguard Worker       assembler_(graph->GetAllocator(),
1172*795d594fSAndroid Build Coastguard Worker                  compiler_options.GetInstructionSetFeatures()->AsX86InstructionSetFeatures()),
1173*795d594fSAndroid Build Coastguard Worker       boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1174*795d594fSAndroid Build Coastguard Worker       app_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1175*795d594fSAndroid Build Coastguard Worker       method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1176*795d594fSAndroid Build Coastguard Worker       boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1177*795d594fSAndroid Build Coastguard Worker       app_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1178*795d594fSAndroid Build Coastguard Worker       type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1179*795d594fSAndroid Build Coastguard Worker       public_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1180*795d594fSAndroid Build Coastguard Worker       package_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1181*795d594fSAndroid Build Coastguard Worker       boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1182*795d594fSAndroid Build Coastguard Worker       string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1183*795d594fSAndroid Build Coastguard Worker       boot_image_jni_entrypoint_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1184*795d594fSAndroid Build Coastguard Worker       boot_image_other_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1185*795d594fSAndroid Build Coastguard Worker       jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1186*795d594fSAndroid Build Coastguard Worker       jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1187*795d594fSAndroid Build Coastguard Worker       constant_area_start_(-1),
1188*795d594fSAndroid Build Coastguard Worker       fixups_to_jump_tables_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1189*795d594fSAndroid Build Coastguard Worker       method_address_offset_(std::less<uint32_t>(),
1190*795d594fSAndroid Build Coastguard Worker                              graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
1191*795d594fSAndroid Build Coastguard Worker   // Use a fake return address register to mimic Quick.
1192*795d594fSAndroid Build Coastguard Worker   AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
1193*795d594fSAndroid Build Coastguard Worker }
1194*795d594fSAndroid Build Coastguard Worker 
SetupBlockedRegisters() const1195*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::SetupBlockedRegisters() const {
1196*795d594fSAndroid Build Coastguard Worker   // Stack register is always reserved.
1197*795d594fSAndroid Build Coastguard Worker   blocked_core_registers_[ESP] = true;
1198*795d594fSAndroid Build Coastguard Worker }
1199*795d594fSAndroid Build Coastguard Worker 
InstructionCodeGeneratorX86(HGraph * graph,CodeGeneratorX86 * codegen)1200*795d594fSAndroid Build Coastguard Worker InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
1201*795d594fSAndroid Build Coastguard Worker       : InstructionCodeGenerator(graph, codegen),
1202*795d594fSAndroid Build Coastguard Worker         assembler_(codegen->GetAssembler()),
1203*795d594fSAndroid Build Coastguard Worker         codegen_(codegen) {}
1204*795d594fSAndroid Build Coastguard Worker 
DWARFReg(Register reg)1205*795d594fSAndroid Build Coastguard Worker static dwarf::Reg DWARFReg(Register reg) {
1206*795d594fSAndroid Build Coastguard Worker   return dwarf::Reg::X86Core(static_cast<int>(reg));
1207*795d594fSAndroid Build Coastguard Worker }
1208*795d594fSAndroid Build Coastguard Worker 
SetInForReturnValue(HInstruction * ret,LocationSummary * locations)1209*795d594fSAndroid Build Coastguard Worker void SetInForReturnValue(HInstruction* ret, LocationSummary* locations) {
1210*795d594fSAndroid Build Coastguard Worker   switch (ret->InputAt(0)->GetType()) {
1211*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1212*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1213*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1214*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1215*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1216*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1217*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1218*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterLocation(EAX));
1219*795d594fSAndroid Build Coastguard Worker       break;
1220*795d594fSAndroid Build Coastguard Worker 
1221*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1222*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterPairLocation(EAX, EDX));
1223*795d594fSAndroid Build Coastguard Worker       break;
1224*795d594fSAndroid Build Coastguard Worker 
1225*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
1226*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
1227*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
1228*795d594fSAndroid Build Coastguard Worker       break;
1229*795d594fSAndroid Build Coastguard Worker 
1230*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
1231*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::NoLocation());
1232*795d594fSAndroid Build Coastguard Worker       break;
1233*795d594fSAndroid Build Coastguard Worker 
1234*795d594fSAndroid Build Coastguard Worker     default:
1235*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
1236*795d594fSAndroid Build Coastguard Worker   }
1237*795d594fSAndroid Build Coastguard Worker }
1238*795d594fSAndroid Build Coastguard Worker 
VisitMethodExitHook(HMethodExitHook * method_hook)1239*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMethodExitHook(HMethodExitHook* method_hook) {
1240*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator())
1241*795d594fSAndroid Build Coastguard Worker       LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1242*795d594fSAndroid Build Coastguard Worker   SetInForReturnValue(method_hook, locations);
1243*795d594fSAndroid Build Coastguard Worker   // We use rdtsc to obtain a timestamp for tracing. rdtsc returns the results in EAX + EDX.
1244*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EAX));
1245*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDX));
1246*795d594fSAndroid Build Coastguard Worker   // An additional temporary register to hold address to store the timestamp counter.
1247*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
1248*795d594fSAndroid Build Coastguard Worker }
1249*795d594fSAndroid Build Coastguard Worker 
GenerateMethodEntryExitHook(HInstruction * instruction)1250*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateMethodEntryExitHook(HInstruction* instruction) {
1251*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path =
1252*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) MethodEntryExitHooksSlowPathX86(instruction);
1253*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
1254*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
1255*795d594fSAndroid Build Coastguard Worker 
1256*795d594fSAndroid Build Coastguard Worker   if (instruction->IsMethodExitHook()) {
1257*795d594fSAndroid Build Coastguard Worker     // Check if we are required to check if the caller needs a deoptimization. Strictly speaking it
1258*795d594fSAndroid Build Coastguard Worker     // would be sufficient to check if CheckCallerForDeopt bit is set. Though it is faster to check
1259*795d594fSAndroid Build Coastguard Worker     // if it is just non-zero. kCHA bit isn't used in debuggable runtimes as cha optimization is
1260*795d594fSAndroid Build Coastguard Worker     // disabled in debuggable runtime. The other bit is used when this method itself requires a
1261*795d594fSAndroid Build Coastguard Worker     // deoptimization due to redefinition. So it is safe to just check for non-zero value here.
1262*795d594fSAndroid Build Coastguard Worker     __ cmpl(Address(ESP, codegen_->GetStackOffsetOfShouldDeoptimizeFlag()), Immediate(0));
1263*795d594fSAndroid Build Coastguard Worker     __ j(kNotEqual, slow_path->GetEntryLabel());
1264*795d594fSAndroid Build Coastguard Worker   }
1265*795d594fSAndroid Build Coastguard Worker 
1266*795d594fSAndroid Build Coastguard Worker   uint64_t address = reinterpret_cast64<uint64_t>(Runtime::Current()->GetInstrumentation());
1267*795d594fSAndroid Build Coastguard Worker   MemberOffset  offset = instruction->IsMethodExitHook() ?
1268*795d594fSAndroid Build Coastguard Worker       instrumentation::Instrumentation::HaveMethodExitListenersOffset() :
1269*795d594fSAndroid Build Coastguard Worker       instrumentation::Instrumentation::HaveMethodEntryListenersOffset();
1270*795d594fSAndroid Build Coastguard Worker   __ cmpb(Address::Absolute(address + offset.Int32Value()),
1271*795d594fSAndroid Build Coastguard Worker           Immediate(instrumentation::Instrumentation::kFastTraceListeners));
1272*795d594fSAndroid Build Coastguard Worker   // Check if there are any trace method entry / exit listeners. If no, continue.
1273*795d594fSAndroid Build Coastguard Worker   __ j(kLess, slow_path->GetExitLabel());
1274*795d594fSAndroid Build Coastguard Worker   // Check if there are any slow (jvmti / trace with thread cpu time) method entry / exit listeners.
1275*795d594fSAndroid Build Coastguard Worker   // If yes, just take the slow path.
1276*795d594fSAndroid Build Coastguard Worker   __ j(kGreater, slow_path->GetEntryLabel());
1277*795d594fSAndroid Build Coastguard Worker 
1278*795d594fSAndroid Build Coastguard Worker   // For curr_entry use the register that isn't EAX or EDX. We need this after
1279*795d594fSAndroid Build Coastguard Worker   // rdtsc which returns values in EAX + EDX.
1280*795d594fSAndroid Build Coastguard Worker   Register curr_entry = locations->GetTemp(2).AsRegister<Register>();
1281*795d594fSAndroid Build Coastguard Worker   Register init_entry = locations->GetTemp(1).AsRegister<Register>();
1282*795d594fSAndroid Build Coastguard Worker 
1283*795d594fSAndroid Build Coastguard Worker   // Check if there is place in the buffer for a new entry, if no, take slow path.
1284*795d594fSAndroid Build Coastguard Worker   uint32_t trace_buffer_ptr = Thread::TraceBufferPtrOffset<kX86PointerSize>().Int32Value();
1285*795d594fSAndroid Build Coastguard Worker   uint64_t trace_buffer_curr_entry_offset =
1286*795d594fSAndroid Build Coastguard Worker       Thread::TraceBufferCurrPtrOffset<kX86PointerSize>().Int32Value();
1287*795d594fSAndroid Build Coastguard Worker 
1288*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(curr_entry, Address::Absolute(trace_buffer_curr_entry_offset));
1289*795d594fSAndroid Build Coastguard Worker   __ subl(curr_entry, Immediate(kNumEntriesForWallClock * sizeof(void*)));
1290*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(init_entry, Address::Absolute(trace_buffer_ptr));
1291*795d594fSAndroid Build Coastguard Worker   __ cmpl(curr_entry, init_entry);
1292*795d594fSAndroid Build Coastguard Worker   __ j(kLess, slow_path->GetEntryLabel());
1293*795d594fSAndroid Build Coastguard Worker 
1294*795d594fSAndroid Build Coastguard Worker   // Update the index in the `Thread`.
1295*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(Address::Absolute(trace_buffer_curr_entry_offset), curr_entry);
1296*795d594fSAndroid Build Coastguard Worker 
1297*795d594fSAndroid Build Coastguard Worker   // Record method pointer and trace action.
1298*795d594fSAndroid Build Coastguard Worker   Register method = init_entry;
1299*795d594fSAndroid Build Coastguard Worker   __ movl(method, Address(ESP, kCurrentMethodStackOffset));
1300*795d594fSAndroid Build Coastguard Worker   // Use last two bits to encode trace method action. For MethodEntry it is 0
1301*795d594fSAndroid Build Coastguard Worker   // so no need to set the bits since they are 0 already.
1302*795d594fSAndroid Build Coastguard Worker   if (instruction->IsMethodExitHook()) {
1303*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(ArtMethod::Alignment(kRuntimePointerSize), static_cast<size_t>(4));
1304*795d594fSAndroid Build Coastguard Worker     static_assert(enum_cast<int32_t>(TraceAction::kTraceMethodEnter) == 0);
1305*795d594fSAndroid Build Coastguard Worker     static_assert(enum_cast<int32_t>(TraceAction::kTraceMethodExit) == 1);
1306*795d594fSAndroid Build Coastguard Worker     __ orl(method, Immediate(enum_cast<int32_t>(TraceAction::kTraceMethodExit)));
1307*795d594fSAndroid Build Coastguard Worker   }
1308*795d594fSAndroid Build Coastguard Worker   __ movl(Address(curr_entry, kMethodOffsetInBytes), method);
1309*795d594fSAndroid Build Coastguard Worker   // Get the timestamp. rdtsc returns timestamp in EAX + EDX.
1310*795d594fSAndroid Build Coastguard Worker   __ rdtsc();
1311*795d594fSAndroid Build Coastguard Worker   __ movl(Address(curr_entry, kTimestampOffsetInBytes), EAX);
1312*795d594fSAndroid Build Coastguard Worker   __ movl(Address(curr_entry, kHighTimestampOffsetInBytes), EDX);
1313*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
1314*795d594fSAndroid Build Coastguard Worker }
1315*795d594fSAndroid Build Coastguard Worker 
VisitMethodExitHook(HMethodExitHook * instruction)1316*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMethodExitHook(HMethodExitHook* instruction) {
1317*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1318*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->RequiresCurrentMethod());
1319*795d594fSAndroid Build Coastguard Worker   GenerateMethodEntryExitHook(instruction);
1320*795d594fSAndroid Build Coastguard Worker }
1321*795d594fSAndroid Build Coastguard Worker 
VisitMethodEntryHook(HMethodEntryHook * method_hook)1322*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMethodEntryHook(HMethodEntryHook* method_hook) {
1323*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator())
1324*795d594fSAndroid Build Coastguard Worker       LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1325*795d594fSAndroid Build Coastguard Worker   // We use rdtsc to obtain a timestamp for tracing. rdtsc returns the results in EAX + EDX.
1326*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EAX));
1327*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RegisterLocation(EDX));
1328*795d594fSAndroid Build Coastguard Worker   // An additional temporary register to hold address to store the timestamp counter.
1329*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
1330*795d594fSAndroid Build Coastguard Worker }
1331*795d594fSAndroid Build Coastguard Worker 
VisitMethodEntryHook(HMethodEntryHook * instruction)1332*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMethodEntryHook(HMethodEntryHook* instruction) {
1333*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1334*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->RequiresCurrentMethod());
1335*795d594fSAndroid Build Coastguard Worker   GenerateMethodEntryExitHook(instruction);
1336*795d594fSAndroid Build Coastguard Worker }
1337*795d594fSAndroid Build Coastguard Worker 
MaybeIncrementHotness(HSuspendCheck * suspend_check,bool is_frame_entry)1338*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry) {
1339*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().CountHotnessInCompiledCode()) {
1340*795d594fSAndroid Build Coastguard Worker     Register reg = EAX;
1341*795d594fSAndroid Build Coastguard Worker     if (is_frame_entry) {
1342*795d594fSAndroid Build Coastguard Worker       reg = kMethodRegisterArgument;
1343*795d594fSAndroid Build Coastguard Worker     } else {
1344*795d594fSAndroid Build Coastguard Worker       __ pushl(EAX);
1345*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(4);
1346*795d594fSAndroid Build Coastguard Worker       __ movl(EAX, Address(ESP, kX86WordSize));
1347*795d594fSAndroid Build Coastguard Worker     }
1348*795d594fSAndroid Build Coastguard Worker     NearLabel overflow;
1349*795d594fSAndroid Build Coastguard Worker     __ cmpw(Address(reg, ArtMethod::HotnessCountOffset().Int32Value()),
1350*795d594fSAndroid Build Coastguard Worker             Immediate(interpreter::kNterpHotnessValue));
1351*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &overflow);
1352*795d594fSAndroid Build Coastguard Worker     __ addw(Address(reg, ArtMethod::HotnessCountOffset().Int32Value()), Immediate(-1));
1353*795d594fSAndroid Build Coastguard Worker     __ Bind(&overflow);
1354*795d594fSAndroid Build Coastguard Worker     if (!is_frame_entry) {
1355*795d594fSAndroid Build Coastguard Worker       __ popl(EAX);
1356*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(-4);
1357*795d594fSAndroid Build Coastguard Worker     }
1358*795d594fSAndroid Build Coastguard Worker   }
1359*795d594fSAndroid Build Coastguard Worker 
1360*795d594fSAndroid Build Coastguard Worker   if (GetGraph()->IsCompilingBaseline() &&
1361*795d594fSAndroid Build Coastguard Worker       GetGraph()->IsUsefulOptimizing() &&
1362*795d594fSAndroid Build Coastguard Worker       !Runtime::Current()->IsAotCompiler()) {
1363*795d594fSAndroid Build Coastguard Worker     ProfilingInfo* info = GetGraph()->GetProfilingInfo();
1364*795d594fSAndroid Build Coastguard Worker     DCHECK(info != nullptr);
1365*795d594fSAndroid Build Coastguard Worker     uint32_t address = reinterpret_cast32<uint32_t>(info) +
1366*795d594fSAndroid Build Coastguard Worker         ProfilingInfo::BaselineHotnessCountOffset().Int32Value();
1367*795d594fSAndroid Build Coastguard Worker     DCHECK(!HasEmptyFrame());
1368*795d594fSAndroid Build Coastguard Worker     SlowPathCode* slow_path =
1369*795d594fSAndroid Build Coastguard Worker         new (GetScopedAllocator()) CompileOptimizedSlowPathX86(suspend_check, address);
1370*795d594fSAndroid Build Coastguard Worker     AddSlowPath(slow_path);
1371*795d594fSAndroid Build Coastguard Worker     // With multiple threads, this can overflow. This is OK, we will eventually get to see
1372*795d594fSAndroid Build Coastguard Worker     // it reaching 0. Also, at this point we have no register available to look
1373*795d594fSAndroid Build Coastguard Worker     // at the counter directly.
1374*795d594fSAndroid Build Coastguard Worker     __ addw(Address::Absolute(address), Immediate(-1));
1375*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, slow_path->GetEntryLabel());
1376*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
1377*795d594fSAndroid Build Coastguard Worker   }
1378*795d594fSAndroid Build Coastguard Worker }
1379*795d594fSAndroid Build Coastguard Worker 
GenerateFrameEntry()1380*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateFrameEntry() {
1381*795d594fSAndroid Build Coastguard Worker   __ cfi().SetCurrentCFAOffset(kX86WordSize);  // return address
1382*795d594fSAndroid Build Coastguard Worker 
1383*795d594fSAndroid Build Coastguard Worker   // Check if we need to generate the clinit check. We will jump to the
1384*795d594fSAndroid Build Coastguard Worker   // resolution stub if the class is not initialized and the executing thread is
1385*795d594fSAndroid Build Coastguard Worker   // not the thread initializing it.
1386*795d594fSAndroid Build Coastguard Worker   // We do this before constructing the frame to get the correct stack trace if
1387*795d594fSAndroid Build Coastguard Worker   // an exception is thrown.
1388*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().ShouldCompileWithClinitCheck(GetGraph()->GetArtMethod())) {
1389*795d594fSAndroid Build Coastguard Worker     NearLabel continue_execution, resolution;
1390*795d594fSAndroid Build Coastguard Worker     // We'll use EBP as temporary.
1391*795d594fSAndroid Build Coastguard Worker     __ pushl(EBP);
1392*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(4);
1393*795d594fSAndroid Build Coastguard Worker     // Check if we're visibly initialized.
1394*795d594fSAndroid Build Coastguard Worker 
1395*795d594fSAndroid Build Coastguard Worker     // We don't emit a read barrier here to save on code size. We rely on the
1396*795d594fSAndroid Build Coastguard Worker     // resolution trampoline to do a suspend check before re-entering this code.
1397*795d594fSAndroid Build Coastguard Worker     __ movl(EBP, Address(kMethodRegisterArgument, ArtMethod::DeclaringClassOffset().Int32Value()));
1398*795d594fSAndroid Build Coastguard Worker     __ cmpb(Address(EBP, kClassStatusByteOffset), Immediate(kShiftedVisiblyInitializedValue));
1399*795d594fSAndroid Build Coastguard Worker     __ j(kAboveEqual, &continue_execution);
1400*795d594fSAndroid Build Coastguard Worker 
1401*795d594fSAndroid Build Coastguard Worker     // Check if we're initializing and the thread initializing is the one
1402*795d594fSAndroid Build Coastguard Worker     // executing the code.
1403*795d594fSAndroid Build Coastguard Worker     __ cmpb(Address(EBP, kClassStatusByteOffset), Immediate(kShiftedInitializingValue));
1404*795d594fSAndroid Build Coastguard Worker     __ j(kBelow, &resolution);
1405*795d594fSAndroid Build Coastguard Worker 
1406*795d594fSAndroid Build Coastguard Worker     __ movl(EBP, Address(EBP, mirror::Class::ClinitThreadIdOffset().Int32Value()));
1407*795d594fSAndroid Build Coastguard Worker     __ fs()->cmpl(EBP, Address::Absolute(Thread::TidOffset<kX86PointerSize>().Int32Value()));
1408*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &continue_execution);
1409*795d594fSAndroid Build Coastguard Worker     __ Bind(&resolution);
1410*795d594fSAndroid Build Coastguard Worker 
1411*795d594fSAndroid Build Coastguard Worker     __ popl(EBP);
1412*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(-4);
1413*795d594fSAndroid Build Coastguard Worker     // Jump to the resolution stub.
1414*795d594fSAndroid Build Coastguard Worker     ThreadOffset32 entrypoint_offset =
1415*795d594fSAndroid Build Coastguard Worker         GetThreadOffset<kX86PointerSize>(kQuickQuickResolutionTrampoline);
1416*795d594fSAndroid Build Coastguard Worker     __ fs()->jmp(Address::Absolute(entrypoint_offset));
1417*795d594fSAndroid Build Coastguard Worker 
1418*795d594fSAndroid Build Coastguard Worker     __ Bind(&continue_execution);
1419*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(4);  // Undo the `-4` adjustment above. We get here with EBP pushed.
1420*795d594fSAndroid Build Coastguard Worker     __ popl(EBP);
1421*795d594fSAndroid Build Coastguard Worker     __ cfi().AdjustCFAOffset(-4);
1422*795d594fSAndroid Build Coastguard Worker   }
1423*795d594fSAndroid Build Coastguard Worker 
1424*795d594fSAndroid Build Coastguard Worker   __ Bind(&frame_entry_label_);
1425*795d594fSAndroid Build Coastguard Worker   bool skip_overflow_check =
1426*795d594fSAndroid Build Coastguard Worker       IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
1427*795d594fSAndroid Build Coastguard Worker   DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
1428*795d594fSAndroid Build Coastguard Worker 
1429*795d594fSAndroid Build Coastguard Worker   if (!skip_overflow_check) {
1430*795d594fSAndroid Build Coastguard Worker     size_t reserved_bytes = GetStackOverflowReservedBytes(InstructionSet::kX86);
1431*795d594fSAndroid Build Coastguard Worker     __ testl(EAX, Address(ESP, -static_cast<int32_t>(reserved_bytes)));
1432*795d594fSAndroid Build Coastguard Worker     RecordPcInfo(nullptr, 0);
1433*795d594fSAndroid Build Coastguard Worker   }
1434*795d594fSAndroid Build Coastguard Worker 
1435*795d594fSAndroid Build Coastguard Worker   if (!HasEmptyFrame()) {
1436*795d594fSAndroid Build Coastguard Worker     // Make sure the frame size isn't unreasonably large.
1437*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(GetFrameSize(), GetMaximumFrameSize());
1438*795d594fSAndroid Build Coastguard Worker 
1439*795d594fSAndroid Build Coastguard Worker     for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
1440*795d594fSAndroid Build Coastguard Worker       Register reg = kCoreCalleeSaves[i];
1441*795d594fSAndroid Build Coastguard Worker       if (allocated_registers_.ContainsCoreRegister(reg)) {
1442*795d594fSAndroid Build Coastguard Worker         __ pushl(reg);
1443*795d594fSAndroid Build Coastguard Worker         __ cfi().AdjustCFAOffset(kX86WordSize);
1444*795d594fSAndroid Build Coastguard Worker         __ cfi().RelOffset(DWARFReg(reg), 0);
1445*795d594fSAndroid Build Coastguard Worker       }
1446*795d594fSAndroid Build Coastguard Worker     }
1447*795d594fSAndroid Build Coastguard Worker 
1448*795d594fSAndroid Build Coastguard Worker     int adjust = GetFrameSize() - FrameEntrySpillSize();
1449*795d594fSAndroid Build Coastguard Worker     IncreaseFrame(adjust);
1450*795d594fSAndroid Build Coastguard Worker     // Save the current method if we need it. Note that we do not
1451*795d594fSAndroid Build Coastguard Worker     // do this in HCurrentMethod, as the instruction might have been removed
1452*795d594fSAndroid Build Coastguard Worker     // in the SSA graph.
1453*795d594fSAndroid Build Coastguard Worker     if (RequiresCurrentMethod()) {
1454*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
1455*795d594fSAndroid Build Coastguard Worker     }
1456*795d594fSAndroid Build Coastguard Worker 
1457*795d594fSAndroid Build Coastguard Worker     if (GetGraph()->HasShouldDeoptimizeFlag()) {
1458*795d594fSAndroid Build Coastguard Worker       // Initialize should_deoptimize flag to 0.
1459*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, GetStackOffsetOfShouldDeoptimizeFlag()), Immediate(0));
1460*795d594fSAndroid Build Coastguard Worker     }
1461*795d594fSAndroid Build Coastguard Worker   }
1462*795d594fSAndroid Build Coastguard Worker 
1463*795d594fSAndroid Build Coastguard Worker   MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true);
1464*795d594fSAndroid Build Coastguard Worker }
1465*795d594fSAndroid Build Coastguard Worker 
GenerateFrameExit()1466*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateFrameExit() {
1467*795d594fSAndroid Build Coastguard Worker   __ cfi().RememberState();
1468*795d594fSAndroid Build Coastguard Worker   if (!HasEmptyFrame()) {
1469*795d594fSAndroid Build Coastguard Worker     int adjust = GetFrameSize() - FrameEntrySpillSize();
1470*795d594fSAndroid Build Coastguard Worker     DecreaseFrame(adjust);
1471*795d594fSAndroid Build Coastguard Worker 
1472*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1473*795d594fSAndroid Build Coastguard Worker       Register reg = kCoreCalleeSaves[i];
1474*795d594fSAndroid Build Coastguard Worker       if (allocated_registers_.ContainsCoreRegister(reg)) {
1475*795d594fSAndroid Build Coastguard Worker         __ popl(reg);
1476*795d594fSAndroid Build Coastguard Worker         __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
1477*795d594fSAndroid Build Coastguard Worker         __ cfi().Restore(DWARFReg(reg));
1478*795d594fSAndroid Build Coastguard Worker       }
1479*795d594fSAndroid Build Coastguard Worker     }
1480*795d594fSAndroid Build Coastguard Worker   }
1481*795d594fSAndroid Build Coastguard Worker   __ ret();
1482*795d594fSAndroid Build Coastguard Worker   __ cfi().RestoreState();
1483*795d594fSAndroid Build Coastguard Worker   __ cfi().DefCFAOffset(GetFrameSize());
1484*795d594fSAndroid Build Coastguard Worker }
1485*795d594fSAndroid Build Coastguard Worker 
Bind(HBasicBlock * block)1486*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Bind(HBasicBlock* block) {
1487*795d594fSAndroid Build Coastguard Worker   __ Bind(GetLabelOf(block));
1488*795d594fSAndroid Build Coastguard Worker }
1489*795d594fSAndroid Build Coastguard Worker 
GetReturnLocation(DataType::Type type) const1490*795d594fSAndroid Build Coastguard Worker Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
1491*795d594fSAndroid Build Coastguard Worker   switch (type) {
1492*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1493*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1494*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1495*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1496*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1497*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1498*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
1499*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1500*795d594fSAndroid Build Coastguard Worker       return Location::RegisterLocation(EAX);
1501*795d594fSAndroid Build Coastguard Worker 
1502*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
1503*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
1504*795d594fSAndroid Build Coastguard Worker       return Location::RegisterPairLocation(EAX, EDX);
1505*795d594fSAndroid Build Coastguard Worker 
1506*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
1507*795d594fSAndroid Build Coastguard Worker       return Location::NoLocation();
1508*795d594fSAndroid Build Coastguard Worker 
1509*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
1510*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
1511*795d594fSAndroid Build Coastguard Worker       return Location::FpuRegisterLocation(XMM0);
1512*795d594fSAndroid Build Coastguard Worker   }
1513*795d594fSAndroid Build Coastguard Worker }
1514*795d594fSAndroid Build Coastguard Worker 
GetMethodLocation() const1515*795d594fSAndroid Build Coastguard Worker Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
1516*795d594fSAndroid Build Coastguard Worker   return Location::RegisterLocation(kMethodRegisterArgument);
1517*795d594fSAndroid Build Coastguard Worker }
1518*795d594fSAndroid Build Coastguard Worker 
GetNextLocation(DataType::Type type)1519*795d594fSAndroid Build Coastguard Worker Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
1520*795d594fSAndroid Build Coastguard Worker   switch (type) {
1521*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1522*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1523*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1524*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1525*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1526*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1527*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
1528*795d594fSAndroid Build Coastguard Worker       uint32_t index = gp_index_++;
1529*795d594fSAndroid Build Coastguard Worker       stack_index_++;
1530*795d594fSAndroid Build Coastguard Worker       if (index < calling_convention.GetNumberOfRegisters()) {
1531*795d594fSAndroid Build Coastguard Worker         return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
1532*795d594fSAndroid Build Coastguard Worker       } else {
1533*795d594fSAndroid Build Coastguard Worker         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1534*795d594fSAndroid Build Coastguard Worker       }
1535*795d594fSAndroid Build Coastguard Worker     }
1536*795d594fSAndroid Build Coastguard Worker 
1537*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
1538*795d594fSAndroid Build Coastguard Worker       uint32_t index = gp_index_;
1539*795d594fSAndroid Build Coastguard Worker       gp_index_ += 2;
1540*795d594fSAndroid Build Coastguard Worker       stack_index_ += 2;
1541*795d594fSAndroid Build Coastguard Worker       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1542*795d594fSAndroid Build Coastguard Worker         X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
1543*795d594fSAndroid Build Coastguard Worker             calling_convention.GetRegisterPairAt(index));
1544*795d594fSAndroid Build Coastguard Worker         return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
1545*795d594fSAndroid Build Coastguard Worker       } else {
1546*795d594fSAndroid Build Coastguard Worker         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1547*795d594fSAndroid Build Coastguard Worker       }
1548*795d594fSAndroid Build Coastguard Worker     }
1549*795d594fSAndroid Build Coastguard Worker 
1550*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
1551*795d594fSAndroid Build Coastguard Worker       uint32_t index = float_index_++;
1552*795d594fSAndroid Build Coastguard Worker       stack_index_++;
1553*795d594fSAndroid Build Coastguard Worker       if (index < calling_convention.GetNumberOfFpuRegisters()) {
1554*795d594fSAndroid Build Coastguard Worker         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
1555*795d594fSAndroid Build Coastguard Worker       } else {
1556*795d594fSAndroid Build Coastguard Worker         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1557*795d594fSAndroid Build Coastguard Worker       }
1558*795d594fSAndroid Build Coastguard Worker     }
1559*795d594fSAndroid Build Coastguard Worker 
1560*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
1561*795d594fSAndroid Build Coastguard Worker       uint32_t index = float_index_++;
1562*795d594fSAndroid Build Coastguard Worker       stack_index_ += 2;
1563*795d594fSAndroid Build Coastguard Worker       if (index < calling_convention.GetNumberOfFpuRegisters()) {
1564*795d594fSAndroid Build Coastguard Worker         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
1565*795d594fSAndroid Build Coastguard Worker       } else {
1566*795d594fSAndroid Build Coastguard Worker         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1567*795d594fSAndroid Build Coastguard Worker       }
1568*795d594fSAndroid Build Coastguard Worker     }
1569*795d594fSAndroid Build Coastguard Worker 
1570*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
1571*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
1572*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
1573*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected parameter type " << type;
1574*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
1575*795d594fSAndroid Build Coastguard Worker   }
1576*795d594fSAndroid Build Coastguard Worker   return Location::NoLocation();
1577*795d594fSAndroid Build Coastguard Worker }
1578*795d594fSAndroid Build Coastguard Worker 
GetNextLocation(DataType::Type type)1579*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
1580*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(type, DataType::Type::kReference);
1581*795d594fSAndroid Build Coastguard Worker 
1582*795d594fSAndroid Build Coastguard Worker   Location location;
1583*795d594fSAndroid Build Coastguard Worker   if (DataType::Is64BitType(type)) {
1584*795d594fSAndroid Build Coastguard Worker     location = Location::DoubleStackSlot(stack_offset_);
1585*795d594fSAndroid Build Coastguard Worker     stack_offset_ += 2 * kFramePointerSize;
1586*795d594fSAndroid Build Coastguard Worker   } else {
1587*795d594fSAndroid Build Coastguard Worker     location = Location::StackSlot(stack_offset_);
1588*795d594fSAndroid Build Coastguard Worker     stack_offset_ += kFramePointerSize;
1589*795d594fSAndroid Build Coastguard Worker   }
1590*795d594fSAndroid Build Coastguard Worker   if (for_register_allocation_) {
1591*795d594fSAndroid Build Coastguard Worker     location = Location::Any();
1592*795d594fSAndroid Build Coastguard Worker   }
1593*795d594fSAndroid Build Coastguard Worker   return location;
1594*795d594fSAndroid Build Coastguard Worker }
1595*795d594fSAndroid Build Coastguard Worker 
GetReturnLocation(DataType::Type type) const1596*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
1597*795d594fSAndroid Build Coastguard Worker   // We perform conversion to the managed ABI return register after the call if needed.
1598*795d594fSAndroid Build Coastguard Worker   InvokeDexCallingConventionVisitorX86 dex_calling_convention;
1599*795d594fSAndroid Build Coastguard Worker   return dex_calling_convention.GetReturnLocation(type);
1600*795d594fSAndroid Build Coastguard Worker }
1601*795d594fSAndroid Build Coastguard Worker 
GetMethodLocation() const1602*795d594fSAndroid Build Coastguard Worker Location CriticalNativeCallingConventionVisitorX86::GetMethodLocation() const {
1603*795d594fSAndroid Build Coastguard Worker   // Pass the method in the hidden argument EAX.
1604*795d594fSAndroid Build Coastguard Worker   return Location::RegisterLocation(EAX);
1605*795d594fSAndroid Build Coastguard Worker }
1606*795d594fSAndroid Build Coastguard Worker 
Move32(Location destination,Location source)1607*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Move32(Location destination, Location source) {
1608*795d594fSAndroid Build Coastguard Worker   if (source.Equals(destination)) {
1609*795d594fSAndroid Build Coastguard Worker     return;
1610*795d594fSAndroid Build Coastguard Worker   }
1611*795d594fSAndroid Build Coastguard Worker   if (destination.IsRegister()) {
1612*795d594fSAndroid Build Coastguard Worker     if (source.IsRegister()) {
1613*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
1614*795d594fSAndroid Build Coastguard Worker     } else if (source.IsFpuRegister()) {
1615*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
1616*795d594fSAndroid Build Coastguard Worker     } else if (source.IsConstant()) {
1617*795d594fSAndroid Build Coastguard Worker       int32_t value = GetInt32ValueOf(source.GetConstant());
1618*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegister<Register>(), Immediate(value));
1619*795d594fSAndroid Build Coastguard Worker     } else {
1620*795d594fSAndroid Build Coastguard Worker       DCHECK(source.IsStackSlot());
1621*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
1622*795d594fSAndroid Build Coastguard Worker     }
1623*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsFpuRegister()) {
1624*795d594fSAndroid Build Coastguard Worker     if (source.IsRegister()) {
1625*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
1626*795d594fSAndroid Build Coastguard Worker     } else if (source.IsFpuRegister()) {
1627*795d594fSAndroid Build Coastguard Worker       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
1628*795d594fSAndroid Build Coastguard Worker     } else {
1629*795d594fSAndroid Build Coastguard Worker       DCHECK(source.IsStackSlot());
1630*795d594fSAndroid Build Coastguard Worker       __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
1631*795d594fSAndroid Build Coastguard Worker     }
1632*795d594fSAndroid Build Coastguard Worker   } else {
1633*795d594fSAndroid Build Coastguard Worker     DCHECK(destination.IsStackSlot()) << destination;
1634*795d594fSAndroid Build Coastguard Worker     if (source.IsRegister()) {
1635*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
1636*795d594fSAndroid Build Coastguard Worker     } else if (source.IsFpuRegister()) {
1637*795d594fSAndroid Build Coastguard Worker       __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
1638*795d594fSAndroid Build Coastguard Worker     } else if (source.IsConstant()) {
1639*795d594fSAndroid Build Coastguard Worker       HConstant* constant = source.GetConstant();
1640*795d594fSAndroid Build Coastguard Worker       int32_t value = GetInt32ValueOf(constant);
1641*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
1642*795d594fSAndroid Build Coastguard Worker     } else {
1643*795d594fSAndroid Build Coastguard Worker       DCHECK(source.IsStackSlot());
1644*795d594fSAndroid Build Coastguard Worker       __ pushl(Address(ESP, source.GetStackIndex()));
1645*795d594fSAndroid Build Coastguard Worker       __ popl(Address(ESP, destination.GetStackIndex()));
1646*795d594fSAndroid Build Coastguard Worker     }
1647*795d594fSAndroid Build Coastguard Worker   }
1648*795d594fSAndroid Build Coastguard Worker }
1649*795d594fSAndroid Build Coastguard Worker 
Move64(Location destination,Location source)1650*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Move64(Location destination, Location source) {
1651*795d594fSAndroid Build Coastguard Worker   if (source.Equals(destination)) {
1652*795d594fSAndroid Build Coastguard Worker     return;
1653*795d594fSAndroid Build Coastguard Worker   }
1654*795d594fSAndroid Build Coastguard Worker   if (destination.IsRegisterPair()) {
1655*795d594fSAndroid Build Coastguard Worker     if (source.IsRegisterPair()) {
1656*795d594fSAndroid Build Coastguard Worker       EmitParallelMoves(
1657*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1658*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
1659*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32,
1660*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
1661*795d594fSAndroid Build Coastguard Worker           Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1662*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32);
1663*795d594fSAndroid Build Coastguard Worker     } else if (source.IsFpuRegister()) {
1664*795d594fSAndroid Build Coastguard Worker       XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
1665*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
1666*795d594fSAndroid Build Coastguard Worker       __ psrlq(src_reg, Immediate(32));
1667*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsRegisterPairHigh<Register>(), src_reg);
1668*795d594fSAndroid Build Coastguard Worker     } else {
1669*795d594fSAndroid Build Coastguard Worker       // No conflict possible, so just do the moves.
1670*795d594fSAndroid Build Coastguard Worker       DCHECK(source.IsDoubleStackSlot());
1671*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
1672*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairHigh<Register>(),
1673*795d594fSAndroid Build Coastguard Worker               Address(ESP, source.GetHighStackIndex(kX86WordSize)));
1674*795d594fSAndroid Build Coastguard Worker     }
1675*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsFpuRegister()) {
1676*795d594fSAndroid Build Coastguard Worker     if (source.IsFpuRegister()) {
1677*795d594fSAndroid Build Coastguard Worker       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
1678*795d594fSAndroid Build Coastguard Worker     } else if (source.IsDoubleStackSlot()) {
1679*795d594fSAndroid Build Coastguard Worker       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
1680*795d594fSAndroid Build Coastguard Worker     } else if (source.IsRegisterPair()) {
1681*795d594fSAndroid Build Coastguard Worker       size_t elem_size = DataType::Size(DataType::Type::kInt32);
1682*795d594fSAndroid Build Coastguard Worker       // Push the 2 source registers to the stack.
1683*795d594fSAndroid Build Coastguard Worker       __ pushl(source.AsRegisterPairHigh<Register>());
1684*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(elem_size);
1685*795d594fSAndroid Build Coastguard Worker       __ pushl(source.AsRegisterPairLow<Register>());
1686*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(elem_size);
1687*795d594fSAndroid Build Coastguard Worker       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
1688*795d594fSAndroid Build Coastguard Worker       // And remove the temporary stack space we allocated.
1689*795d594fSAndroid Build Coastguard Worker       DecreaseFrame(2 * elem_size);
1690*795d594fSAndroid Build Coastguard Worker     } else {
1691*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unimplemented";
1692*795d594fSAndroid Build Coastguard Worker     }
1693*795d594fSAndroid Build Coastguard Worker   } else {
1694*795d594fSAndroid Build Coastguard Worker     DCHECK(destination.IsDoubleStackSlot()) << destination;
1695*795d594fSAndroid Build Coastguard Worker     if (source.IsRegisterPair()) {
1696*795d594fSAndroid Build Coastguard Worker       // No conflict possible, so just do the moves.
1697*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
1698*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
1699*795d594fSAndroid Build Coastguard Worker               source.AsRegisterPairHigh<Register>());
1700*795d594fSAndroid Build Coastguard Worker     } else if (source.IsFpuRegister()) {
1701*795d594fSAndroid Build Coastguard Worker       __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
1702*795d594fSAndroid Build Coastguard Worker     } else if (source.IsConstant()) {
1703*795d594fSAndroid Build Coastguard Worker       HConstant* constant = source.GetConstant();
1704*795d594fSAndroid Build Coastguard Worker       DCHECK(constant->IsLongConstant() || constant->IsDoubleConstant());
1705*795d594fSAndroid Build Coastguard Worker       int64_t value = GetInt64ValueOf(constant);
1706*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
1707*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
1708*795d594fSAndroid Build Coastguard Worker               Immediate(High32Bits(value)));
1709*795d594fSAndroid Build Coastguard Worker     } else {
1710*795d594fSAndroid Build Coastguard Worker       DCHECK(source.IsDoubleStackSlot()) << source;
1711*795d594fSAndroid Build Coastguard Worker       EmitParallelMoves(
1712*795d594fSAndroid Build Coastguard Worker           Location::StackSlot(source.GetStackIndex()),
1713*795d594fSAndroid Build Coastguard Worker           Location::StackSlot(destination.GetStackIndex()),
1714*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32,
1715*795d594fSAndroid Build Coastguard Worker           Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
1716*795d594fSAndroid Build Coastguard Worker           Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
1717*795d594fSAndroid Build Coastguard Worker           DataType::Type::kInt32);
1718*795d594fSAndroid Build Coastguard Worker     }
1719*795d594fSAndroid Build Coastguard Worker   }
1720*795d594fSAndroid Build Coastguard Worker }
1721*795d594fSAndroid Build Coastguard Worker 
CreateAddress(Register base,Register index=Register::kNoRegister,ScaleFactor scale=TIMES_1,int32_t disp=0)1722*795d594fSAndroid Build Coastguard Worker static Address CreateAddress(Register base,
1723*795d594fSAndroid Build Coastguard Worker                              Register index = Register::kNoRegister,
1724*795d594fSAndroid Build Coastguard Worker                              ScaleFactor scale = TIMES_1,
1725*795d594fSAndroid Build Coastguard Worker                              int32_t disp = 0) {
1726*795d594fSAndroid Build Coastguard Worker   if (index == Register::kNoRegister) {
1727*795d594fSAndroid Build Coastguard Worker     return Address(base, disp);
1728*795d594fSAndroid Build Coastguard Worker   }
1729*795d594fSAndroid Build Coastguard Worker 
1730*795d594fSAndroid Build Coastguard Worker   return Address(base, index, scale, disp);
1731*795d594fSAndroid Build Coastguard Worker }
1732*795d594fSAndroid Build Coastguard Worker 
LoadFromMemoryNoBarrier(DataType::Type dst_type,Location dst,Address src,HInstruction * instr,XmmRegister temp,bool is_atomic_load)1733*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::LoadFromMemoryNoBarrier(DataType::Type dst_type,
1734*795d594fSAndroid Build Coastguard Worker                                                Location dst,
1735*795d594fSAndroid Build Coastguard Worker                                                Address src,
1736*795d594fSAndroid Build Coastguard Worker                                                HInstruction* instr,
1737*795d594fSAndroid Build Coastguard Worker                                                XmmRegister temp,
1738*795d594fSAndroid Build Coastguard Worker                                                bool is_atomic_load) {
1739*795d594fSAndroid Build Coastguard Worker   switch (dst_type) {
1740*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1741*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1742*795d594fSAndroid Build Coastguard Worker       __ movzxb(dst.AsRegister<Register>(), src);
1743*795d594fSAndroid Build Coastguard Worker       break;
1744*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
1745*795d594fSAndroid Build Coastguard Worker       __ movsxb(dst.AsRegister<Register>(), src);
1746*795d594fSAndroid Build Coastguard Worker       break;
1747*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
1748*795d594fSAndroid Build Coastguard Worker       __ movsxw(dst.AsRegister<Register>(), src);
1749*795d594fSAndroid Build Coastguard Worker       break;
1750*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1751*795d594fSAndroid Build Coastguard Worker       __ movzxw(dst.AsRegister<Register>(), src);
1752*795d594fSAndroid Build Coastguard Worker       break;
1753*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
1754*795d594fSAndroid Build Coastguard Worker       __ movl(dst.AsRegister<Register>(), src);
1755*795d594fSAndroid Build Coastguard Worker       break;
1756*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
1757*795d594fSAndroid Build Coastguard Worker       if (is_atomic_load) {
1758*795d594fSAndroid Build Coastguard Worker         __ movsd(temp, src);
1759*795d594fSAndroid Build Coastguard Worker         if (instr != nullptr) {
1760*795d594fSAndroid Build Coastguard Worker           MaybeRecordImplicitNullCheck(instr);
1761*795d594fSAndroid Build Coastguard Worker         }
1762*795d594fSAndroid Build Coastguard Worker         __ movd(dst.AsRegisterPairLow<Register>(), temp);
1763*795d594fSAndroid Build Coastguard Worker         __ psrlq(temp, Immediate(32));
1764*795d594fSAndroid Build Coastguard Worker         __ movd(dst.AsRegisterPairHigh<Register>(), temp);
1765*795d594fSAndroid Build Coastguard Worker       } else {
1766*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(src.GetBaseRegister(), dst.AsRegisterPairLow<Register>());
1767*795d594fSAndroid Build Coastguard Worker         Address src_high = Address::displace(src, kX86WordSize);
1768*795d594fSAndroid Build Coastguard Worker         __ movl(dst.AsRegisterPairLow<Register>(), src);
1769*795d594fSAndroid Build Coastguard Worker         if (instr != nullptr) {
1770*795d594fSAndroid Build Coastguard Worker           MaybeRecordImplicitNullCheck(instr);
1771*795d594fSAndroid Build Coastguard Worker         }
1772*795d594fSAndroid Build Coastguard Worker         __ movl(dst.AsRegisterPairHigh<Register>(), src_high);
1773*795d594fSAndroid Build Coastguard Worker       }
1774*795d594fSAndroid Build Coastguard Worker       break;
1775*795d594fSAndroid Build Coastguard Worker     }
1776*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
1777*795d594fSAndroid Build Coastguard Worker       __ movss(dst.AsFpuRegister<XmmRegister>(), src);
1778*795d594fSAndroid Build Coastguard Worker       break;
1779*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
1780*795d594fSAndroid Build Coastguard Worker       __ movsd(dst.AsFpuRegister<XmmRegister>(), src);
1781*795d594fSAndroid Build Coastguard Worker       break;
1782*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1783*795d594fSAndroid Build Coastguard Worker       DCHECK(!EmitReadBarrier());
1784*795d594fSAndroid Build Coastguard Worker       __ movl(dst.AsRegister<Register>(), src);
1785*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(dst.AsRegister<Register>());
1786*795d594fSAndroid Build Coastguard Worker       break;
1787*795d594fSAndroid Build Coastguard Worker     default:
1788*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable type " << dst_type;
1789*795d594fSAndroid Build Coastguard Worker   }
1790*795d594fSAndroid Build Coastguard Worker   if (instr != nullptr && dst_type != DataType::Type::kInt64) {
1791*795d594fSAndroid Build Coastguard Worker     // kInt64 needs special handling that is done in the above switch.
1792*795d594fSAndroid Build Coastguard Worker     MaybeRecordImplicitNullCheck(instr);
1793*795d594fSAndroid Build Coastguard Worker   }
1794*795d594fSAndroid Build Coastguard Worker }
1795*795d594fSAndroid Build Coastguard Worker 
MoveToMemory(DataType::Type src_type,Location src,Register dst_base,Register dst_index,ScaleFactor dst_scale,int32_t dst_disp)1796*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MoveToMemory(DataType::Type src_type,
1797*795d594fSAndroid Build Coastguard Worker                                     Location src,
1798*795d594fSAndroid Build Coastguard Worker                                     Register dst_base,
1799*795d594fSAndroid Build Coastguard Worker                                     Register dst_index,
1800*795d594fSAndroid Build Coastguard Worker                                     ScaleFactor dst_scale,
1801*795d594fSAndroid Build Coastguard Worker                                     int32_t dst_disp) {
1802*795d594fSAndroid Build Coastguard Worker   DCHECK(dst_base != Register::kNoRegister);
1803*795d594fSAndroid Build Coastguard Worker   Address dst = CreateAddress(dst_base, dst_index, dst_scale, dst_disp);
1804*795d594fSAndroid Build Coastguard Worker 
1805*795d594fSAndroid Build Coastguard Worker   switch (src_type) {
1806*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
1807*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
1808*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8: {
1809*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1810*795d594fSAndroid Build Coastguard Worker         __ movb(dst, Immediate(CodeGenerator::GetInt8ValueOf(src.GetConstant())));
1811*795d594fSAndroid Build Coastguard Worker       } else {
1812*795d594fSAndroid Build Coastguard Worker         __ movb(dst, src.AsRegister<ByteRegister>());
1813*795d594fSAndroid Build Coastguard Worker       }
1814*795d594fSAndroid Build Coastguard Worker       break;
1815*795d594fSAndroid Build Coastguard Worker     }
1816*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
1817*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16: {
1818*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1819*795d594fSAndroid Build Coastguard Worker         __ movw(dst, Immediate(CodeGenerator::GetInt16ValueOf(src.GetConstant())));
1820*795d594fSAndroid Build Coastguard Worker       } else {
1821*795d594fSAndroid Build Coastguard Worker         __ movw(dst, src.AsRegister<Register>());
1822*795d594fSAndroid Build Coastguard Worker       }
1823*795d594fSAndroid Build Coastguard Worker       break;
1824*795d594fSAndroid Build Coastguard Worker     }
1825*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
1826*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
1827*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1828*795d594fSAndroid Build Coastguard Worker         int32_t v = CodeGenerator::GetInt32ValueOf(src.GetConstant());
1829*795d594fSAndroid Build Coastguard Worker         __ movl(dst, Immediate(v));
1830*795d594fSAndroid Build Coastguard Worker       } else {
1831*795d594fSAndroid Build Coastguard Worker         __ movl(dst, src.AsRegister<Register>());
1832*795d594fSAndroid Build Coastguard Worker       }
1833*795d594fSAndroid Build Coastguard Worker       break;
1834*795d594fSAndroid Build Coastguard Worker     }
1835*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
1836*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
1837*795d594fSAndroid Build Coastguard Worker       Address dst_next_4_bytes = CreateAddress(dst_base, dst_index, dst_scale, dst_disp + 4);
1838*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1839*795d594fSAndroid Build Coastguard Worker         int64_t v = CodeGenerator::GetInt64ValueOf(src.GetConstant());
1840*795d594fSAndroid Build Coastguard Worker         __ movl(dst, Immediate(Low32Bits(v)));
1841*795d594fSAndroid Build Coastguard Worker         __ movl(dst_next_4_bytes, Immediate(High32Bits(v)));
1842*795d594fSAndroid Build Coastguard Worker       } else {
1843*795d594fSAndroid Build Coastguard Worker         __ movl(dst, src.AsRegisterPairLow<Register>());
1844*795d594fSAndroid Build Coastguard Worker         __ movl(dst_next_4_bytes, src.AsRegisterPairHigh<Register>());
1845*795d594fSAndroid Build Coastguard Worker       }
1846*795d594fSAndroid Build Coastguard Worker       break;
1847*795d594fSAndroid Build Coastguard Worker     }
1848*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
1849*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1850*795d594fSAndroid Build Coastguard Worker         int32_t v = CodeGenerator::GetInt32ValueOf(src.GetConstant());
1851*795d594fSAndroid Build Coastguard Worker         __ movl(dst, Immediate(v));
1852*795d594fSAndroid Build Coastguard Worker       } else {
1853*795d594fSAndroid Build Coastguard Worker         __ movss(dst, src.AsFpuRegister<XmmRegister>());
1854*795d594fSAndroid Build Coastguard Worker       }
1855*795d594fSAndroid Build Coastguard Worker       break;
1856*795d594fSAndroid Build Coastguard Worker     }
1857*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
1858*795d594fSAndroid Build Coastguard Worker       Address dst_next_4_bytes = CreateAddress(dst_base, dst_index, dst_scale, dst_disp + 4);
1859*795d594fSAndroid Build Coastguard Worker       if (src.IsConstant()) {
1860*795d594fSAndroid Build Coastguard Worker         int64_t v = CodeGenerator::GetInt64ValueOf(src.GetConstant());
1861*795d594fSAndroid Build Coastguard Worker         __ movl(dst, Immediate(Low32Bits(v)));
1862*795d594fSAndroid Build Coastguard Worker         __ movl(dst_next_4_bytes, Immediate(High32Bits(v)));
1863*795d594fSAndroid Build Coastguard Worker       } else {
1864*795d594fSAndroid Build Coastguard Worker         __ movsd(dst, src.AsFpuRegister<XmmRegister>());
1865*795d594fSAndroid Build Coastguard Worker       }
1866*795d594fSAndroid Build Coastguard Worker       break;
1867*795d594fSAndroid Build Coastguard Worker     }
1868*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
1869*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
1870*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable type " << src_type;
1871*795d594fSAndroid Build Coastguard Worker   }
1872*795d594fSAndroid Build Coastguard Worker }
1873*795d594fSAndroid Build Coastguard Worker 
MoveConstant(Location location,int32_t value)1874*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
1875*795d594fSAndroid Build Coastguard Worker   DCHECK(location.IsRegister());
1876*795d594fSAndroid Build Coastguard Worker   __ movl(location.AsRegister<Register>(), Immediate(value));
1877*795d594fSAndroid Build Coastguard Worker }
1878*795d594fSAndroid Build Coastguard Worker 
MoveLocation(Location dst,Location src,DataType::Type dst_type)1879*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MoveLocation(Location dst, Location src, DataType::Type dst_type) {
1880*795d594fSAndroid Build Coastguard Worker   HParallelMove move(GetGraph()->GetAllocator());
1881*795d594fSAndroid Build Coastguard Worker   if (dst_type == DataType::Type::kInt64 && !src.IsConstant() && !src.IsFpuRegister()) {
1882*795d594fSAndroid Build Coastguard Worker     move.AddMove(src.ToLow(), dst.ToLow(), DataType::Type::kInt32, nullptr);
1883*795d594fSAndroid Build Coastguard Worker     move.AddMove(src.ToHigh(), dst.ToHigh(), DataType::Type::kInt32, nullptr);
1884*795d594fSAndroid Build Coastguard Worker   } else {
1885*795d594fSAndroid Build Coastguard Worker     move.AddMove(src, dst, dst_type, nullptr);
1886*795d594fSAndroid Build Coastguard Worker   }
1887*795d594fSAndroid Build Coastguard Worker   GetMoveResolver()->EmitNativeCode(&move);
1888*795d594fSAndroid Build Coastguard Worker }
1889*795d594fSAndroid Build Coastguard Worker 
AddLocationAsTemp(Location location,LocationSummary * locations)1890*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) {
1891*795d594fSAndroid Build Coastguard Worker   if (location.IsRegister()) {
1892*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(location);
1893*795d594fSAndroid Build Coastguard Worker   } else if (location.IsRegisterPair()) {
1894*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1895*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1896*795d594fSAndroid Build Coastguard Worker   } else {
1897*795d594fSAndroid Build Coastguard Worker     UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1898*795d594fSAndroid Build Coastguard Worker   }
1899*795d594fSAndroid Build Coastguard Worker }
1900*795d594fSAndroid Build Coastguard Worker 
HandleGoto(HInstruction * got,HBasicBlock * successor)1901*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
1902*795d594fSAndroid Build Coastguard Worker   if (successor->IsExitBlock()) {
1903*795d594fSAndroid Build Coastguard Worker     DCHECK(got->GetPrevious()->AlwaysThrows());
1904*795d594fSAndroid Build Coastguard Worker     return;  // no code needed
1905*795d594fSAndroid Build Coastguard Worker   }
1906*795d594fSAndroid Build Coastguard Worker 
1907*795d594fSAndroid Build Coastguard Worker   HBasicBlock* block = got->GetBlock();
1908*795d594fSAndroid Build Coastguard Worker   HInstruction* previous = got->GetPrevious();
1909*795d594fSAndroid Build Coastguard Worker 
1910*795d594fSAndroid Build Coastguard Worker   HLoopInformation* info = block->GetLoopInformation();
1911*795d594fSAndroid Build Coastguard Worker   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
1912*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false);
1913*795d594fSAndroid Build Coastguard Worker     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1914*795d594fSAndroid Build Coastguard Worker     return;
1915*795d594fSAndroid Build Coastguard Worker   }
1916*795d594fSAndroid Build Coastguard Worker 
1917*795d594fSAndroid Build Coastguard Worker   if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1918*795d594fSAndroid Build Coastguard Worker     GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1919*795d594fSAndroid Build Coastguard Worker   }
1920*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
1921*795d594fSAndroid Build Coastguard Worker     __ jmp(codegen_->GetLabelOf(successor));
1922*795d594fSAndroid Build Coastguard Worker   }
1923*795d594fSAndroid Build Coastguard Worker }
1924*795d594fSAndroid Build Coastguard Worker 
VisitGoto(HGoto * got)1925*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitGoto(HGoto* got) {
1926*795d594fSAndroid Build Coastguard Worker   got->SetLocations(nullptr);
1927*795d594fSAndroid Build Coastguard Worker }
1928*795d594fSAndroid Build Coastguard Worker 
VisitGoto(HGoto * got)1929*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
1930*795d594fSAndroid Build Coastguard Worker   HandleGoto(got, got->GetSuccessor());
1931*795d594fSAndroid Build Coastguard Worker }
1932*795d594fSAndroid Build Coastguard Worker 
VisitTryBoundary(HTryBoundary * try_boundary)1933*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1934*795d594fSAndroid Build Coastguard Worker   try_boundary->SetLocations(nullptr);
1935*795d594fSAndroid Build Coastguard Worker }
1936*795d594fSAndroid Build Coastguard Worker 
VisitTryBoundary(HTryBoundary * try_boundary)1937*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1938*795d594fSAndroid Build Coastguard Worker   HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1939*795d594fSAndroid Build Coastguard Worker   if (!successor->IsExitBlock()) {
1940*795d594fSAndroid Build Coastguard Worker     HandleGoto(try_boundary, successor);
1941*795d594fSAndroid Build Coastguard Worker   }
1942*795d594fSAndroid Build Coastguard Worker }
1943*795d594fSAndroid Build Coastguard Worker 
VisitExit(HExit * exit)1944*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitExit(HExit* exit) {
1945*795d594fSAndroid Build Coastguard Worker   exit->SetLocations(nullptr);
1946*795d594fSAndroid Build Coastguard Worker }
1947*795d594fSAndroid Build Coastguard Worker 
VisitExit(HExit * exit)1948*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitExit([[maybe_unused]] HExit* exit) {}
1949*795d594fSAndroid Build Coastguard Worker 
1950*795d594fSAndroid Build Coastguard Worker template<class LabelType>
GenerateFPJumps(HCondition * cond,LabelType * true_label,LabelType * false_label)1951*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
1952*795d594fSAndroid Build Coastguard Worker                                                   LabelType* true_label,
1953*795d594fSAndroid Build Coastguard Worker                                                   LabelType* false_label) {
1954*795d594fSAndroid Build Coastguard Worker   if (cond->IsFPConditionTrueIfNaN()) {
1955*795d594fSAndroid Build Coastguard Worker     __ j(kUnordered, true_label);
1956*795d594fSAndroid Build Coastguard Worker   } else if (cond->IsFPConditionFalseIfNaN()) {
1957*795d594fSAndroid Build Coastguard Worker     __ j(kUnordered, false_label);
1958*795d594fSAndroid Build Coastguard Worker   }
1959*795d594fSAndroid Build Coastguard Worker   __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
1960*795d594fSAndroid Build Coastguard Worker }
1961*795d594fSAndroid Build Coastguard Worker 
1962*795d594fSAndroid Build Coastguard Worker template<class LabelType>
GenerateLongComparesAndJumps(HCondition * cond,LabelType * true_label,LabelType * false_label)1963*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
1964*795d594fSAndroid Build Coastguard Worker                                                                LabelType* true_label,
1965*795d594fSAndroid Build Coastguard Worker                                                                LabelType* false_label) {
1966*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = cond->GetLocations();
1967*795d594fSAndroid Build Coastguard Worker   Location left = locations->InAt(0);
1968*795d594fSAndroid Build Coastguard Worker   Location right = locations->InAt(1);
1969*795d594fSAndroid Build Coastguard Worker   IfCondition if_cond = cond->GetCondition();
1970*795d594fSAndroid Build Coastguard Worker 
1971*795d594fSAndroid Build Coastguard Worker   Register left_high = left.AsRegisterPairHigh<Register>();
1972*795d594fSAndroid Build Coastguard Worker   Register left_low = left.AsRegisterPairLow<Register>();
1973*795d594fSAndroid Build Coastguard Worker   IfCondition true_high_cond = if_cond;
1974*795d594fSAndroid Build Coastguard Worker   IfCondition false_high_cond = cond->GetOppositeCondition();
1975*795d594fSAndroid Build Coastguard Worker   Condition final_condition = X86UnsignedOrFPCondition(if_cond);  // unsigned on lower part
1976*795d594fSAndroid Build Coastguard Worker 
1977*795d594fSAndroid Build Coastguard Worker   // Set the conditions for the test, remembering that == needs to be
1978*795d594fSAndroid Build Coastguard Worker   // decided using the low words.
1979*795d594fSAndroid Build Coastguard Worker   switch (if_cond) {
1980*795d594fSAndroid Build Coastguard Worker     case kCondEQ:
1981*795d594fSAndroid Build Coastguard Worker     case kCondNE:
1982*795d594fSAndroid Build Coastguard Worker       // Nothing to do.
1983*795d594fSAndroid Build Coastguard Worker       break;
1984*795d594fSAndroid Build Coastguard Worker     case kCondLT:
1985*795d594fSAndroid Build Coastguard Worker       false_high_cond = kCondGT;
1986*795d594fSAndroid Build Coastguard Worker       break;
1987*795d594fSAndroid Build Coastguard Worker     case kCondLE:
1988*795d594fSAndroid Build Coastguard Worker       true_high_cond = kCondLT;
1989*795d594fSAndroid Build Coastguard Worker       break;
1990*795d594fSAndroid Build Coastguard Worker     case kCondGT:
1991*795d594fSAndroid Build Coastguard Worker       false_high_cond = kCondLT;
1992*795d594fSAndroid Build Coastguard Worker       break;
1993*795d594fSAndroid Build Coastguard Worker     case kCondGE:
1994*795d594fSAndroid Build Coastguard Worker       true_high_cond = kCondGT;
1995*795d594fSAndroid Build Coastguard Worker       break;
1996*795d594fSAndroid Build Coastguard Worker     case kCondB:
1997*795d594fSAndroid Build Coastguard Worker       false_high_cond = kCondA;
1998*795d594fSAndroid Build Coastguard Worker       break;
1999*795d594fSAndroid Build Coastguard Worker     case kCondBE:
2000*795d594fSAndroid Build Coastguard Worker       true_high_cond = kCondB;
2001*795d594fSAndroid Build Coastguard Worker       break;
2002*795d594fSAndroid Build Coastguard Worker     case kCondA:
2003*795d594fSAndroid Build Coastguard Worker       false_high_cond = kCondB;
2004*795d594fSAndroid Build Coastguard Worker       break;
2005*795d594fSAndroid Build Coastguard Worker     case kCondAE:
2006*795d594fSAndroid Build Coastguard Worker       true_high_cond = kCondA;
2007*795d594fSAndroid Build Coastguard Worker       break;
2008*795d594fSAndroid Build Coastguard Worker   }
2009*795d594fSAndroid Build Coastguard Worker 
2010*795d594fSAndroid Build Coastguard Worker   if (right.IsConstant()) {
2011*795d594fSAndroid Build Coastguard Worker     int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2012*795d594fSAndroid Build Coastguard Worker     int32_t val_high = High32Bits(value);
2013*795d594fSAndroid Build Coastguard Worker     int32_t val_low = Low32Bits(value);
2014*795d594fSAndroid Build Coastguard Worker 
2015*795d594fSAndroid Build Coastguard Worker     codegen_->Compare32BitValue(left_high, val_high);
2016*795d594fSAndroid Build Coastguard Worker     if (if_cond == kCondNE) {
2017*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2018*795d594fSAndroid Build Coastguard Worker     } else if (if_cond == kCondEQ) {
2019*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2020*795d594fSAndroid Build Coastguard Worker     } else {
2021*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2022*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2023*795d594fSAndroid Build Coastguard Worker     }
2024*795d594fSAndroid Build Coastguard Worker     // Must be equal high, so compare the lows.
2025*795d594fSAndroid Build Coastguard Worker     codegen_->Compare32BitValue(left_low, val_low);
2026*795d594fSAndroid Build Coastguard Worker   } else if (right.IsRegisterPair()) {
2027*795d594fSAndroid Build Coastguard Worker     Register right_high = right.AsRegisterPairHigh<Register>();
2028*795d594fSAndroid Build Coastguard Worker     Register right_low = right.AsRegisterPairLow<Register>();
2029*795d594fSAndroid Build Coastguard Worker 
2030*795d594fSAndroid Build Coastguard Worker     __ cmpl(left_high, right_high);
2031*795d594fSAndroid Build Coastguard Worker     if (if_cond == kCondNE) {
2032*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2033*795d594fSAndroid Build Coastguard Worker     } else if (if_cond == kCondEQ) {
2034*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2035*795d594fSAndroid Build Coastguard Worker     } else {
2036*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2037*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2038*795d594fSAndroid Build Coastguard Worker     }
2039*795d594fSAndroid Build Coastguard Worker     // Must be equal high, so compare the lows.
2040*795d594fSAndroid Build Coastguard Worker     __ cmpl(left_low, right_low);
2041*795d594fSAndroid Build Coastguard Worker   } else {
2042*795d594fSAndroid Build Coastguard Worker     DCHECK(right.IsDoubleStackSlot());
2043*795d594fSAndroid Build Coastguard Worker     __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
2044*795d594fSAndroid Build Coastguard Worker     if (if_cond == kCondNE) {
2045*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2046*795d594fSAndroid Build Coastguard Worker     } else if (if_cond == kCondEQ) {
2047*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2048*795d594fSAndroid Build Coastguard Worker     } else {
2049*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(true_high_cond), true_label);
2050*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(false_high_cond), false_label);
2051*795d594fSAndroid Build Coastguard Worker     }
2052*795d594fSAndroid Build Coastguard Worker     // Must be equal high, so compare the lows.
2053*795d594fSAndroid Build Coastguard Worker     __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
2054*795d594fSAndroid Build Coastguard Worker   }
2055*795d594fSAndroid Build Coastguard Worker   // The last comparison might be unsigned.
2056*795d594fSAndroid Build Coastguard Worker   __ j(final_condition, true_label);
2057*795d594fSAndroid Build Coastguard Worker }
2058*795d594fSAndroid Build Coastguard Worker 
GenerateFPCompare(Location lhs,Location rhs,HInstruction * insn,bool is_double)2059*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateFPCompare(Location lhs,
2060*795d594fSAndroid Build Coastguard Worker                                                     Location rhs,
2061*795d594fSAndroid Build Coastguard Worker                                                     HInstruction* insn,
2062*795d594fSAndroid Build Coastguard Worker                                                     bool is_double) {
2063*795d594fSAndroid Build Coastguard Worker   HX86LoadFromConstantTable* const_area = insn->InputAt(1)->AsX86LoadFromConstantTableOrNull();
2064*795d594fSAndroid Build Coastguard Worker   if (is_double) {
2065*795d594fSAndroid Build Coastguard Worker     if (rhs.IsFpuRegister()) {
2066*795d594fSAndroid Build Coastguard Worker       __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
2067*795d594fSAndroid Build Coastguard Worker     } else if (const_area != nullptr) {
2068*795d594fSAndroid Build Coastguard Worker       DCHECK(const_area->IsEmittedAtUseSite());
2069*795d594fSAndroid Build Coastguard Worker       __ ucomisd(lhs.AsFpuRegister<XmmRegister>(),
2070*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralDoubleAddress(
2071*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2072*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
2073*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2074*795d594fSAndroid Build Coastguard Worker     } else {
2075*795d594fSAndroid Build Coastguard Worker       DCHECK(rhs.IsDoubleStackSlot());
2076*795d594fSAndroid Build Coastguard Worker       __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
2077*795d594fSAndroid Build Coastguard Worker     }
2078*795d594fSAndroid Build Coastguard Worker   } else {
2079*795d594fSAndroid Build Coastguard Worker     if (rhs.IsFpuRegister()) {
2080*795d594fSAndroid Build Coastguard Worker       __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
2081*795d594fSAndroid Build Coastguard Worker     } else if (const_area != nullptr) {
2082*795d594fSAndroid Build Coastguard Worker       DCHECK(const_area->IsEmittedAtUseSite());
2083*795d594fSAndroid Build Coastguard Worker       __ ucomiss(lhs.AsFpuRegister<XmmRegister>(),
2084*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralFloatAddress(
2085*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsFloatConstant()->GetValue(),
2086*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
2087*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2088*795d594fSAndroid Build Coastguard Worker     } else {
2089*795d594fSAndroid Build Coastguard Worker       DCHECK(rhs.IsStackSlot());
2090*795d594fSAndroid Build Coastguard Worker       __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
2091*795d594fSAndroid Build Coastguard Worker     }
2092*795d594fSAndroid Build Coastguard Worker   }
2093*795d594fSAndroid Build Coastguard Worker }
2094*795d594fSAndroid Build Coastguard Worker 
2095*795d594fSAndroid Build Coastguard Worker template<class LabelType>
GenerateCompareTestAndBranch(HCondition * condition,LabelType * true_target_in,LabelType * false_target_in)2096*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condition,
2097*795d594fSAndroid Build Coastguard Worker                                                                LabelType* true_target_in,
2098*795d594fSAndroid Build Coastguard Worker                                                                LabelType* false_target_in) {
2099*795d594fSAndroid Build Coastguard Worker   // Generated branching requires both targets to be explicit. If either of the
2100*795d594fSAndroid Build Coastguard Worker   // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2101*795d594fSAndroid Build Coastguard Worker   LabelType fallthrough_target;
2102*795d594fSAndroid Build Coastguard Worker   LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2103*795d594fSAndroid Build Coastguard Worker   LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2104*795d594fSAndroid Build Coastguard Worker 
2105*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = condition->GetLocations();
2106*795d594fSAndroid Build Coastguard Worker   Location left = locations->InAt(0);
2107*795d594fSAndroid Build Coastguard Worker   Location right = locations->InAt(1);
2108*795d594fSAndroid Build Coastguard Worker 
2109*795d594fSAndroid Build Coastguard Worker   DataType::Type type = condition->InputAt(0)->GetType();
2110*795d594fSAndroid Build Coastguard Worker   switch (type) {
2111*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
2112*795d594fSAndroid Build Coastguard Worker       GenerateLongComparesAndJumps(condition, true_target, false_target);
2113*795d594fSAndroid Build Coastguard Worker       break;
2114*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
2115*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(left, right, condition, false);
2116*795d594fSAndroid Build Coastguard Worker       GenerateFPJumps(condition, true_target, false_target);
2117*795d594fSAndroid Build Coastguard Worker       break;
2118*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
2119*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(left, right, condition, true);
2120*795d594fSAndroid Build Coastguard Worker       GenerateFPJumps(condition, true_target, false_target);
2121*795d594fSAndroid Build Coastguard Worker       break;
2122*795d594fSAndroid Build Coastguard Worker     default:
2123*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected compare type " << type;
2124*795d594fSAndroid Build Coastguard Worker   }
2125*795d594fSAndroid Build Coastguard Worker 
2126*795d594fSAndroid Build Coastguard Worker   if (false_target != &fallthrough_target) {
2127*795d594fSAndroid Build Coastguard Worker     __ jmp(false_target);
2128*795d594fSAndroid Build Coastguard Worker   }
2129*795d594fSAndroid Build Coastguard Worker 
2130*795d594fSAndroid Build Coastguard Worker   if (fallthrough_target.IsLinked()) {
2131*795d594fSAndroid Build Coastguard Worker     __ Bind(&fallthrough_target);
2132*795d594fSAndroid Build Coastguard Worker   }
2133*795d594fSAndroid Build Coastguard Worker }
2134*795d594fSAndroid Build Coastguard Worker 
AreEflagsSetFrom(HInstruction * cond,HInstruction * branch,const CompilerOptions & compiler_options)2135*795d594fSAndroid Build Coastguard Worker static bool AreEflagsSetFrom(HInstruction* cond,
2136*795d594fSAndroid Build Coastguard Worker                              HInstruction* branch,
2137*795d594fSAndroid Build Coastguard Worker                              const CompilerOptions& compiler_options) {
2138*795d594fSAndroid Build Coastguard Worker   // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
2139*795d594fSAndroid Build Coastguard Worker   // are set only strictly before `branch`. We can't use the eflags on long/FP
2140*795d594fSAndroid Build Coastguard Worker   // conditions if they are materialized due to the complex branching.
2141*795d594fSAndroid Build Coastguard Worker   return cond->IsCondition() &&
2142*795d594fSAndroid Build Coastguard Worker          cond->GetNext() == branch &&
2143*795d594fSAndroid Build Coastguard Worker          cond->InputAt(0)->GetType() != DataType::Type::kInt64 &&
2144*795d594fSAndroid Build Coastguard Worker          !DataType::IsFloatingPointType(cond->InputAt(0)->GetType()) &&
2145*795d594fSAndroid Build Coastguard Worker          !(cond->GetBlock()->GetGraph()->IsCompilingBaseline() &&
2146*795d594fSAndroid Build Coastguard Worker            compiler_options.ProfileBranches());
2147*795d594fSAndroid Build Coastguard Worker }
2148*795d594fSAndroid Build Coastguard Worker 
2149*795d594fSAndroid Build Coastguard Worker template<class LabelType>
GenerateTestAndBranch(HInstruction * instruction,size_t condition_input_index,LabelType * true_target,LabelType * false_target)2150*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
2151*795d594fSAndroid Build Coastguard Worker                                                         size_t condition_input_index,
2152*795d594fSAndroid Build Coastguard Worker                                                         LabelType* true_target,
2153*795d594fSAndroid Build Coastguard Worker                                                         LabelType* false_target) {
2154*795d594fSAndroid Build Coastguard Worker   HInstruction* cond = instruction->InputAt(condition_input_index);
2155*795d594fSAndroid Build Coastguard Worker 
2156*795d594fSAndroid Build Coastguard Worker   if (true_target == nullptr && false_target == nullptr) {
2157*795d594fSAndroid Build Coastguard Worker     // Nothing to do. The code always falls through.
2158*795d594fSAndroid Build Coastguard Worker     return;
2159*795d594fSAndroid Build Coastguard Worker   } else if (cond->IsIntConstant()) {
2160*795d594fSAndroid Build Coastguard Worker     // Constant condition, statically compared against "true" (integer value 1).
2161*795d594fSAndroid Build Coastguard Worker     if (cond->AsIntConstant()->IsTrue()) {
2162*795d594fSAndroid Build Coastguard Worker       if (true_target != nullptr) {
2163*795d594fSAndroid Build Coastguard Worker         __ jmp(true_target);
2164*795d594fSAndroid Build Coastguard Worker       }
2165*795d594fSAndroid Build Coastguard Worker     } else {
2166*795d594fSAndroid Build Coastguard Worker       DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
2167*795d594fSAndroid Build Coastguard Worker       if (false_target != nullptr) {
2168*795d594fSAndroid Build Coastguard Worker         __ jmp(false_target);
2169*795d594fSAndroid Build Coastguard Worker       }
2170*795d594fSAndroid Build Coastguard Worker     }
2171*795d594fSAndroid Build Coastguard Worker     return;
2172*795d594fSAndroid Build Coastguard Worker   }
2173*795d594fSAndroid Build Coastguard Worker 
2174*795d594fSAndroid Build Coastguard Worker   // The following code generates these patterns:
2175*795d594fSAndroid Build Coastguard Worker   //  (1) true_target == nullptr && false_target != nullptr
2176*795d594fSAndroid Build Coastguard Worker   //        - opposite condition true => branch to false_target
2177*795d594fSAndroid Build Coastguard Worker   //  (2) true_target != nullptr && false_target == nullptr
2178*795d594fSAndroid Build Coastguard Worker   //        - condition true => branch to true_target
2179*795d594fSAndroid Build Coastguard Worker   //  (3) true_target != nullptr && false_target != nullptr
2180*795d594fSAndroid Build Coastguard Worker   //        - condition true => branch to true_target
2181*795d594fSAndroid Build Coastguard Worker   //        - branch to false_target
2182*795d594fSAndroid Build Coastguard Worker   if (IsBooleanValueOrMaterializedCondition(cond)) {
2183*795d594fSAndroid Build Coastguard Worker     if (AreEflagsSetFrom(cond, instruction, codegen_->GetCompilerOptions())) {
2184*795d594fSAndroid Build Coastguard Worker       if (true_target == nullptr) {
2185*795d594fSAndroid Build Coastguard Worker         __ j(X86Condition(cond->AsCondition()->GetOppositeCondition()), false_target);
2186*795d594fSAndroid Build Coastguard Worker       } else {
2187*795d594fSAndroid Build Coastguard Worker         __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
2188*795d594fSAndroid Build Coastguard Worker       }
2189*795d594fSAndroid Build Coastguard Worker     } else {
2190*795d594fSAndroid Build Coastguard Worker       // Materialized condition, compare against 0.
2191*795d594fSAndroid Build Coastguard Worker       Location lhs = instruction->GetLocations()->InAt(condition_input_index);
2192*795d594fSAndroid Build Coastguard Worker       if (lhs.IsRegister()) {
2193*795d594fSAndroid Build Coastguard Worker         __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
2194*795d594fSAndroid Build Coastguard Worker       } else {
2195*795d594fSAndroid Build Coastguard Worker         __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
2196*795d594fSAndroid Build Coastguard Worker       }
2197*795d594fSAndroid Build Coastguard Worker       if (true_target == nullptr) {
2198*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, false_target);
2199*795d594fSAndroid Build Coastguard Worker       } else {
2200*795d594fSAndroid Build Coastguard Worker         __ j(kNotEqual, true_target);
2201*795d594fSAndroid Build Coastguard Worker       }
2202*795d594fSAndroid Build Coastguard Worker     }
2203*795d594fSAndroid Build Coastguard Worker   } else {
2204*795d594fSAndroid Build Coastguard Worker     // Condition has not been materialized, use its inputs as the comparison and
2205*795d594fSAndroid Build Coastguard Worker     // its condition as the branch condition.
2206*795d594fSAndroid Build Coastguard Worker     HCondition* condition = cond->AsCondition();
2207*795d594fSAndroid Build Coastguard Worker 
2208*795d594fSAndroid Build Coastguard Worker     // If this is a long or FP comparison that has been folded into
2209*795d594fSAndroid Build Coastguard Worker     // the HCondition, generate the comparison directly.
2210*795d594fSAndroid Build Coastguard Worker     DataType::Type type = condition->InputAt(0)->GetType();
2211*795d594fSAndroid Build Coastguard Worker     if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
2212*795d594fSAndroid Build Coastguard Worker       GenerateCompareTestAndBranch(condition, true_target, false_target);
2213*795d594fSAndroid Build Coastguard Worker       return;
2214*795d594fSAndroid Build Coastguard Worker     }
2215*795d594fSAndroid Build Coastguard Worker 
2216*795d594fSAndroid Build Coastguard Worker     Location lhs = condition->GetLocations()->InAt(0);
2217*795d594fSAndroid Build Coastguard Worker     Location rhs = condition->GetLocations()->InAt(1);
2218*795d594fSAndroid Build Coastguard Worker     // LHS is guaranteed to be in a register (see LocationsBuilderX86::HandleCondition).
2219*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateIntCompare(lhs, rhs);
2220*795d594fSAndroid Build Coastguard Worker     if (true_target == nullptr) {
2221*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(condition->GetOppositeCondition()), false_target);
2222*795d594fSAndroid Build Coastguard Worker     } else {
2223*795d594fSAndroid Build Coastguard Worker       __ j(X86Condition(condition->GetCondition()), true_target);
2224*795d594fSAndroid Build Coastguard Worker     }
2225*795d594fSAndroid Build Coastguard Worker   }
2226*795d594fSAndroid Build Coastguard Worker 
2227*795d594fSAndroid Build Coastguard Worker   // If neither branch falls through (case 3), the conditional branch to `true_target`
2228*795d594fSAndroid Build Coastguard Worker   // was already emitted (case 2) and we need to emit a jump to `false_target`.
2229*795d594fSAndroid Build Coastguard Worker   if (true_target != nullptr && false_target != nullptr) {
2230*795d594fSAndroid Build Coastguard Worker     __ jmp(false_target);
2231*795d594fSAndroid Build Coastguard Worker   }
2232*795d594fSAndroid Build Coastguard Worker }
2233*795d594fSAndroid Build Coastguard Worker 
VisitIf(HIf * if_instr)2234*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitIf(HIf* if_instr) {
2235*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
2236*795d594fSAndroid Build Coastguard Worker   if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
2237*795d594fSAndroid Build Coastguard Worker     if (GetGraph()->IsCompilingBaseline() &&
2238*795d594fSAndroid Build Coastguard Worker         codegen_->GetCompilerOptions().ProfileBranches() &&
2239*795d594fSAndroid Build Coastguard Worker         !Runtime::Current()->IsAotCompiler()) {
2240*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
2241*795d594fSAndroid Build Coastguard Worker       locations->AddRegisterTemps(2);
2242*795d594fSAndroid Build Coastguard Worker     } else {
2243*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::Any());
2244*795d594fSAndroid Build Coastguard Worker     }
2245*795d594fSAndroid Build Coastguard Worker   }
2246*795d594fSAndroid Build Coastguard Worker }
2247*795d594fSAndroid Build Coastguard Worker 
VisitIf(HIf * if_instr)2248*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
2249*795d594fSAndroid Build Coastguard Worker   HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2250*795d594fSAndroid Build Coastguard Worker   HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2251*795d594fSAndroid Build Coastguard Worker   Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2252*795d594fSAndroid Build Coastguard Worker       nullptr : codegen_->GetLabelOf(true_successor);
2253*795d594fSAndroid Build Coastguard Worker   Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2254*795d594fSAndroid Build Coastguard Worker       nullptr : codegen_->GetLabelOf(false_successor);
2255*795d594fSAndroid Build Coastguard Worker   if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
2256*795d594fSAndroid Build Coastguard Worker     if (GetGraph()->IsCompilingBaseline() &&
2257*795d594fSAndroid Build Coastguard Worker         codegen_->GetCompilerOptions().ProfileBranches() &&
2258*795d594fSAndroid Build Coastguard Worker         !Runtime::Current()->IsAotCompiler()) {
2259*795d594fSAndroid Build Coastguard Worker       DCHECK(if_instr->InputAt(0)->IsCondition());
2260*795d594fSAndroid Build Coastguard Worker       Register temp = if_instr->GetLocations()->GetTemp(0).AsRegister<Register>();
2261*795d594fSAndroid Build Coastguard Worker       Register counter = if_instr->GetLocations()->GetTemp(1).AsRegister<Register>();
2262*795d594fSAndroid Build Coastguard Worker       ProfilingInfo* info = GetGraph()->GetProfilingInfo();
2263*795d594fSAndroid Build Coastguard Worker       DCHECK(info != nullptr);
2264*795d594fSAndroid Build Coastguard Worker       BranchCache* cache = info->GetBranchCache(if_instr->GetDexPc());
2265*795d594fSAndroid Build Coastguard Worker       // Currently, not all If branches are profiled.
2266*795d594fSAndroid Build Coastguard Worker       if (cache != nullptr) {
2267*795d594fSAndroid Build Coastguard Worker         uint64_t address =
2268*795d594fSAndroid Build Coastguard Worker             reinterpret_cast64<uint64_t>(cache) + BranchCache::FalseOffset().Int32Value();
2269*795d594fSAndroid Build Coastguard Worker         static_assert(
2270*795d594fSAndroid Build Coastguard Worker             BranchCache::TrueOffset().Int32Value() - BranchCache::FalseOffset().Int32Value() == 2,
2271*795d594fSAndroid Build Coastguard Worker             "Unexpected offsets for BranchCache");
2272*795d594fSAndroid Build Coastguard Worker         NearLabel done;
2273*795d594fSAndroid Build Coastguard Worker         Location lhs = if_instr->GetLocations()->InAt(0);
2274*795d594fSAndroid Build Coastguard Worker         __ movl(temp, Immediate(address));
2275*795d594fSAndroid Build Coastguard Worker         __ movzxw(counter, Address(temp, lhs.AsRegister<Register>(), TIMES_2, 0));
2276*795d594fSAndroid Build Coastguard Worker         __ addw(counter, Immediate(1));
2277*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, &done);
2278*795d594fSAndroid Build Coastguard Worker         __ movw(Address(temp, lhs.AsRegister<Register>(), TIMES_2, 0), counter);
2279*795d594fSAndroid Build Coastguard Worker         __ Bind(&done);
2280*795d594fSAndroid Build Coastguard Worker       }
2281*795d594fSAndroid Build Coastguard Worker     }
2282*795d594fSAndroid Build Coastguard Worker   }
2283*795d594fSAndroid Build Coastguard Worker   GenerateTestAndBranch(if_instr, /* condition_input_index= */ 0, true_target, false_target);
2284*795d594fSAndroid Build Coastguard Worker }
2285*795d594fSAndroid Build Coastguard Worker 
VisitDeoptimize(HDeoptimize * deoptimize)2286*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
2287*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator())
2288*795d594fSAndroid Build Coastguard Worker       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
2289*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
2290*795d594fSAndroid Build Coastguard Worker   RegisterSet caller_saves = RegisterSet::Empty();
2291*795d594fSAndroid Build Coastguard Worker   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2292*795d594fSAndroid Build Coastguard Worker   locations->SetCustomSlowPathCallerSaves(caller_saves);
2293*795d594fSAndroid Build Coastguard Worker   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
2294*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::Any());
2295*795d594fSAndroid Build Coastguard Worker   }
2296*795d594fSAndroid Build Coastguard Worker }
2297*795d594fSAndroid Build Coastguard Worker 
VisitDeoptimize(HDeoptimize * deoptimize)2298*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
2299*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathX86>(deoptimize);
2300*795d594fSAndroid Build Coastguard Worker   GenerateTestAndBranch<Label>(deoptimize,
2301*795d594fSAndroid Build Coastguard Worker                                /* condition_input_index= */ 0,
2302*795d594fSAndroid Build Coastguard Worker                                slow_path->GetEntryLabel(),
2303*795d594fSAndroid Build Coastguard Worker                                /* false_target= */ nullptr);
2304*795d594fSAndroid Build Coastguard Worker }
2305*795d594fSAndroid Build Coastguard Worker 
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)2306*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2307*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator())
2308*795d594fSAndroid Build Coastguard Worker       LocationSummary(flag, LocationSummary::kNoCall);
2309*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
2310*795d594fSAndroid Build Coastguard Worker }
2311*795d594fSAndroid Build Coastguard Worker 
VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag * flag)2312*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2313*795d594fSAndroid Build Coastguard Worker   __ movl(flag->GetLocations()->Out().AsRegister<Register>(),
2314*795d594fSAndroid Build Coastguard Worker           Address(ESP, codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
2315*795d594fSAndroid Build Coastguard Worker }
2316*795d594fSAndroid Build Coastguard Worker 
SelectCanUseCMOV(HSelect * select)2317*795d594fSAndroid Build Coastguard Worker static bool SelectCanUseCMOV(HSelect* select) {
2318*795d594fSAndroid Build Coastguard Worker   // There are no conditional move instructions for XMMs.
2319*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(select->GetType())) {
2320*795d594fSAndroid Build Coastguard Worker     return false;
2321*795d594fSAndroid Build Coastguard Worker   }
2322*795d594fSAndroid Build Coastguard Worker 
2323*795d594fSAndroid Build Coastguard Worker   // A FP condition doesn't generate the single CC that we need.
2324*795d594fSAndroid Build Coastguard Worker   // In 32 bit mode, a long condition doesn't generate a single CC either.
2325*795d594fSAndroid Build Coastguard Worker   HInstruction* condition = select->GetCondition();
2326*795d594fSAndroid Build Coastguard Worker   if (condition->IsCondition()) {
2327*795d594fSAndroid Build Coastguard Worker     DataType::Type compare_type = condition->InputAt(0)->GetType();
2328*795d594fSAndroid Build Coastguard Worker     if (compare_type == DataType::Type::kInt64 ||
2329*795d594fSAndroid Build Coastguard Worker         DataType::IsFloatingPointType(compare_type)) {
2330*795d594fSAndroid Build Coastguard Worker       return false;
2331*795d594fSAndroid Build Coastguard Worker     }
2332*795d594fSAndroid Build Coastguard Worker   }
2333*795d594fSAndroid Build Coastguard Worker 
2334*795d594fSAndroid Build Coastguard Worker   // We can generate a CMOV for this Select.
2335*795d594fSAndroid Build Coastguard Worker   return true;
2336*795d594fSAndroid Build Coastguard Worker }
2337*795d594fSAndroid Build Coastguard Worker 
VisitSelect(HSelect * select)2338*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitSelect(HSelect* select) {
2339*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
2340*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(select->GetType())) {
2341*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresFpuRegister());
2342*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::Any());
2343*795d594fSAndroid Build Coastguard Worker   } else {
2344*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
2345*795d594fSAndroid Build Coastguard Worker     if (SelectCanUseCMOV(select)) {
2346*795d594fSAndroid Build Coastguard Worker       if (select->InputAt(1)->IsConstant()) {
2347*795d594fSAndroid Build Coastguard Worker         // Cmov can't handle a constant value.
2348*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresRegister());
2349*795d594fSAndroid Build Coastguard Worker       } else {
2350*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
2351*795d594fSAndroid Build Coastguard Worker       }
2352*795d594fSAndroid Build Coastguard Worker     } else {
2353*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
2354*795d594fSAndroid Build Coastguard Worker     }
2355*795d594fSAndroid Build Coastguard Worker   }
2356*795d594fSAndroid Build Coastguard Worker   if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
2357*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::RequiresRegister());
2358*795d594fSAndroid Build Coastguard Worker   }
2359*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
2360*795d594fSAndroid Build Coastguard Worker }
2361*795d594fSAndroid Build Coastguard Worker 
VisitSelect(HSelect * select)2362*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitSelect(HSelect* select) {
2363*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = select->GetLocations();
2364*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->InAt(0).Equals(locations->Out()));
2365*795d594fSAndroid Build Coastguard Worker   if (SelectCanUseCMOV(select)) {
2366*795d594fSAndroid Build Coastguard Worker     // If both the condition and the source types are integer, we can generate
2367*795d594fSAndroid Build Coastguard Worker     // a CMOV to implement Select.
2368*795d594fSAndroid Build Coastguard Worker 
2369*795d594fSAndroid Build Coastguard Worker     HInstruction* select_condition = select->GetCondition();
2370*795d594fSAndroid Build Coastguard Worker     Condition cond = kNotEqual;
2371*795d594fSAndroid Build Coastguard Worker 
2372*795d594fSAndroid Build Coastguard Worker     // Figure out how to test the 'condition'.
2373*795d594fSAndroid Build Coastguard Worker     if (select_condition->IsCondition()) {
2374*795d594fSAndroid Build Coastguard Worker       HCondition* condition = select_condition->AsCondition();
2375*795d594fSAndroid Build Coastguard Worker       if (!condition->IsEmittedAtUseSite()) {
2376*795d594fSAndroid Build Coastguard Worker         // This was a previously materialized condition.
2377*795d594fSAndroid Build Coastguard Worker         // Can we use the existing condition code?
2378*795d594fSAndroid Build Coastguard Worker         if (AreEflagsSetFrom(condition, select, codegen_->GetCompilerOptions())) {
2379*795d594fSAndroid Build Coastguard Worker           // Materialization was the previous instruction. Condition codes are right.
2380*795d594fSAndroid Build Coastguard Worker           cond = X86Condition(condition->GetCondition());
2381*795d594fSAndroid Build Coastguard Worker         } else {
2382*795d594fSAndroid Build Coastguard Worker           // No, we have to recreate the condition code.
2383*795d594fSAndroid Build Coastguard Worker           Register cond_reg = locations->InAt(2).AsRegister<Register>();
2384*795d594fSAndroid Build Coastguard Worker           __ testl(cond_reg, cond_reg);
2385*795d594fSAndroid Build Coastguard Worker         }
2386*795d594fSAndroid Build Coastguard Worker       } else {
2387*795d594fSAndroid Build Coastguard Worker         // We can't handle FP or long here.
2388*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(condition->InputAt(0)->GetType(), DataType::Type::kInt64);
2389*795d594fSAndroid Build Coastguard Worker         DCHECK(!DataType::IsFloatingPointType(condition->InputAt(0)->GetType()));
2390*795d594fSAndroid Build Coastguard Worker         LocationSummary* cond_locations = condition->GetLocations();
2391*795d594fSAndroid Build Coastguard Worker         codegen_->GenerateIntCompare(cond_locations->InAt(0), cond_locations->InAt(1));
2392*795d594fSAndroid Build Coastguard Worker         cond = X86Condition(condition->GetCondition());
2393*795d594fSAndroid Build Coastguard Worker       }
2394*795d594fSAndroid Build Coastguard Worker     } else {
2395*795d594fSAndroid Build Coastguard Worker       // Must be a Boolean condition, which needs to be compared to 0.
2396*795d594fSAndroid Build Coastguard Worker       Register cond_reg = locations->InAt(2).AsRegister<Register>();
2397*795d594fSAndroid Build Coastguard Worker       __ testl(cond_reg, cond_reg);
2398*795d594fSAndroid Build Coastguard Worker     }
2399*795d594fSAndroid Build Coastguard Worker 
2400*795d594fSAndroid Build Coastguard Worker     // If the condition is true, overwrite the output, which already contains false.
2401*795d594fSAndroid Build Coastguard Worker     Location false_loc = locations->InAt(0);
2402*795d594fSAndroid Build Coastguard Worker     Location true_loc = locations->InAt(1);
2403*795d594fSAndroid Build Coastguard Worker     if (select->GetType() == DataType::Type::kInt64) {
2404*795d594fSAndroid Build Coastguard Worker       // 64 bit conditional move.
2405*795d594fSAndroid Build Coastguard Worker       Register false_high = false_loc.AsRegisterPairHigh<Register>();
2406*795d594fSAndroid Build Coastguard Worker       Register false_low = false_loc.AsRegisterPairLow<Register>();
2407*795d594fSAndroid Build Coastguard Worker       if (true_loc.IsRegisterPair()) {
2408*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_high, true_loc.AsRegisterPairHigh<Register>());
2409*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_low, true_loc.AsRegisterPairLow<Register>());
2410*795d594fSAndroid Build Coastguard Worker       } else {
2411*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_high, Address(ESP, true_loc.GetHighStackIndex(kX86WordSize)));
2412*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_low, Address(ESP, true_loc.GetStackIndex()));
2413*795d594fSAndroid Build Coastguard Worker       }
2414*795d594fSAndroid Build Coastguard Worker     } else {
2415*795d594fSAndroid Build Coastguard Worker       // 32 bit conditional move.
2416*795d594fSAndroid Build Coastguard Worker       Register false_reg = false_loc.AsRegister<Register>();
2417*795d594fSAndroid Build Coastguard Worker       if (true_loc.IsRegister()) {
2418*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_reg, true_loc.AsRegister<Register>());
2419*795d594fSAndroid Build Coastguard Worker       } else {
2420*795d594fSAndroid Build Coastguard Worker         __ cmovl(cond, false_reg, Address(ESP, true_loc.GetStackIndex()));
2421*795d594fSAndroid Build Coastguard Worker       }
2422*795d594fSAndroid Build Coastguard Worker     }
2423*795d594fSAndroid Build Coastguard Worker   } else {
2424*795d594fSAndroid Build Coastguard Worker     NearLabel false_target;
2425*795d594fSAndroid Build Coastguard Worker     GenerateTestAndBranch<NearLabel>(
2426*795d594fSAndroid Build Coastguard Worker         select, /* condition_input_index= */ 2, /* true_target= */ nullptr, &false_target);
2427*795d594fSAndroid Build Coastguard Worker     codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
2428*795d594fSAndroid Build Coastguard Worker     __ Bind(&false_target);
2429*795d594fSAndroid Build Coastguard Worker   }
2430*795d594fSAndroid Build Coastguard Worker }
2431*795d594fSAndroid Build Coastguard Worker 
VisitNop(HNop * nop)2432*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNop(HNop* nop) {
2433*795d594fSAndroid Build Coastguard Worker   new (GetGraph()->GetAllocator()) LocationSummary(nop);
2434*795d594fSAndroid Build Coastguard Worker }
2435*795d594fSAndroid Build Coastguard Worker 
VisitNop(HNop *)2436*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNop(HNop*) {
2437*795d594fSAndroid Build Coastguard Worker   // The environment recording already happened in CodeGenerator::Compile.
2438*795d594fSAndroid Build Coastguard Worker }
2439*795d594fSAndroid Build Coastguard Worker 
IncreaseFrame(size_t adjustment)2440*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::IncreaseFrame(size_t adjustment) {
2441*795d594fSAndroid Build Coastguard Worker   __ subl(ESP, Immediate(adjustment));
2442*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(adjustment);
2443*795d594fSAndroid Build Coastguard Worker }
2444*795d594fSAndroid Build Coastguard Worker 
DecreaseFrame(size_t adjustment)2445*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::DecreaseFrame(size_t adjustment) {
2446*795d594fSAndroid Build Coastguard Worker   __ addl(ESP, Immediate(adjustment));
2447*795d594fSAndroid Build Coastguard Worker   __ cfi().AdjustCFAOffset(-adjustment);
2448*795d594fSAndroid Build Coastguard Worker }
2449*795d594fSAndroid Build Coastguard Worker 
GenerateNop()2450*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateNop() {
2451*795d594fSAndroid Build Coastguard Worker   __ nop();
2452*795d594fSAndroid Build Coastguard Worker }
2453*795d594fSAndroid Build Coastguard Worker 
HandleCondition(HCondition * cond)2454*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleCondition(HCondition* cond) {
2455*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2456*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(cond, LocationSummary::kNoCall);
2457*795d594fSAndroid Build Coastguard Worker   // Handle the long/FP comparisons made in instruction simplification.
2458*795d594fSAndroid Build Coastguard Worker   switch (cond->InputAt(0)->GetType()) {
2459*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
2460*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
2461*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
2462*795d594fSAndroid Build Coastguard Worker       if (!cond->IsEmittedAtUseSite()) {
2463*795d594fSAndroid Build Coastguard Worker         locations->SetOut(Location::RequiresRegister());
2464*795d594fSAndroid Build Coastguard Worker       }
2465*795d594fSAndroid Build Coastguard Worker       break;
2466*795d594fSAndroid Build Coastguard Worker     }
2467*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
2468*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
2469*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
2470*795d594fSAndroid Build Coastguard Worker       if (cond->InputAt(1)->IsX86LoadFromConstantTable()) {
2471*795d594fSAndroid Build Coastguard Worker         DCHECK(cond->InputAt(1)->IsEmittedAtUseSite());
2472*795d594fSAndroid Build Coastguard Worker       } else if (cond->InputAt(1)->IsConstant()) {
2473*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
2474*795d594fSAndroid Build Coastguard Worker       } else {
2475*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
2476*795d594fSAndroid Build Coastguard Worker       }
2477*795d594fSAndroid Build Coastguard Worker       if (!cond->IsEmittedAtUseSite()) {
2478*795d594fSAndroid Build Coastguard Worker         locations->SetOut(Location::RequiresRegister());
2479*795d594fSAndroid Build Coastguard Worker       }
2480*795d594fSAndroid Build Coastguard Worker       break;
2481*795d594fSAndroid Build Coastguard Worker     }
2482*795d594fSAndroid Build Coastguard Worker     default:
2483*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
2484*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
2485*795d594fSAndroid Build Coastguard Worker       if (!cond->IsEmittedAtUseSite()) {
2486*795d594fSAndroid Build Coastguard Worker         // We need a byte register.
2487*795d594fSAndroid Build Coastguard Worker         locations->SetOut(Location::RegisterLocation(ECX));
2488*795d594fSAndroid Build Coastguard Worker       }
2489*795d594fSAndroid Build Coastguard Worker       break;
2490*795d594fSAndroid Build Coastguard Worker   }
2491*795d594fSAndroid Build Coastguard Worker }
2492*795d594fSAndroid Build Coastguard Worker 
HandleCondition(HCondition * cond)2493*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleCondition(HCondition* cond) {
2494*795d594fSAndroid Build Coastguard Worker   if (cond->IsEmittedAtUseSite()) {
2495*795d594fSAndroid Build Coastguard Worker     return;
2496*795d594fSAndroid Build Coastguard Worker   }
2497*795d594fSAndroid Build Coastguard Worker 
2498*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = cond->GetLocations();
2499*795d594fSAndroid Build Coastguard Worker   Location lhs = locations->InAt(0);
2500*795d594fSAndroid Build Coastguard Worker   Location rhs = locations->InAt(1);
2501*795d594fSAndroid Build Coastguard Worker   Register reg = locations->Out().AsRegister<Register>();
2502*795d594fSAndroid Build Coastguard Worker   NearLabel true_label, false_label;
2503*795d594fSAndroid Build Coastguard Worker 
2504*795d594fSAndroid Build Coastguard Worker   switch (cond->InputAt(0)->GetType()) {
2505*795d594fSAndroid Build Coastguard Worker     default: {
2506*795d594fSAndroid Build Coastguard Worker       // Integer case.
2507*795d594fSAndroid Build Coastguard Worker 
2508*795d594fSAndroid Build Coastguard Worker       // Clear output register: setb only sets the low byte.
2509*795d594fSAndroid Build Coastguard Worker       __ xorl(reg, reg);
2510*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateIntCompare(lhs, rhs);
2511*795d594fSAndroid Build Coastguard Worker       __ setb(X86Condition(cond->GetCondition()), reg);
2512*795d594fSAndroid Build Coastguard Worker       return;
2513*795d594fSAndroid Build Coastguard Worker     }
2514*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
2515*795d594fSAndroid Build Coastguard Worker       GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2516*795d594fSAndroid Build Coastguard Worker       break;
2517*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
2518*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(lhs, rhs, cond, false);
2519*795d594fSAndroid Build Coastguard Worker       GenerateFPJumps(cond, &true_label, &false_label);
2520*795d594fSAndroid Build Coastguard Worker       break;
2521*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
2522*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(lhs, rhs, cond, true);
2523*795d594fSAndroid Build Coastguard Worker       GenerateFPJumps(cond, &true_label, &false_label);
2524*795d594fSAndroid Build Coastguard Worker       break;
2525*795d594fSAndroid Build Coastguard Worker   }
2526*795d594fSAndroid Build Coastguard Worker 
2527*795d594fSAndroid Build Coastguard Worker   // Convert the jumps into the result.
2528*795d594fSAndroid Build Coastguard Worker   NearLabel done_label;
2529*795d594fSAndroid Build Coastguard Worker 
2530*795d594fSAndroid Build Coastguard Worker   // False case: result = 0.
2531*795d594fSAndroid Build Coastguard Worker   __ Bind(&false_label);
2532*795d594fSAndroid Build Coastguard Worker   __ xorl(reg, reg);
2533*795d594fSAndroid Build Coastguard Worker   __ jmp(&done_label);
2534*795d594fSAndroid Build Coastguard Worker 
2535*795d594fSAndroid Build Coastguard Worker   // True case: result = 1.
2536*795d594fSAndroid Build Coastguard Worker   __ Bind(&true_label);
2537*795d594fSAndroid Build Coastguard Worker   __ movl(reg, Immediate(1));
2538*795d594fSAndroid Build Coastguard Worker   __ Bind(&done_label);
2539*795d594fSAndroid Build Coastguard Worker }
2540*795d594fSAndroid Build Coastguard Worker 
VisitEqual(HEqual * comp)2541*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitEqual(HEqual* comp) {
2542*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2543*795d594fSAndroid Build Coastguard Worker }
2544*795d594fSAndroid Build Coastguard Worker 
VisitEqual(HEqual * comp)2545*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
2546*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2547*795d594fSAndroid Build Coastguard Worker }
2548*795d594fSAndroid Build Coastguard Worker 
VisitNotEqual(HNotEqual * comp)2549*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
2550*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2551*795d594fSAndroid Build Coastguard Worker }
2552*795d594fSAndroid Build Coastguard Worker 
VisitNotEqual(HNotEqual * comp)2553*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
2554*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2555*795d594fSAndroid Build Coastguard Worker }
2556*795d594fSAndroid Build Coastguard Worker 
VisitLessThan(HLessThan * comp)2557*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
2558*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2559*795d594fSAndroid Build Coastguard Worker }
2560*795d594fSAndroid Build Coastguard Worker 
VisitLessThan(HLessThan * comp)2561*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
2562*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2563*795d594fSAndroid Build Coastguard Worker }
2564*795d594fSAndroid Build Coastguard Worker 
VisitLessThanOrEqual(HLessThanOrEqual * comp)2565*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
2566*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2567*795d594fSAndroid Build Coastguard Worker }
2568*795d594fSAndroid Build Coastguard Worker 
VisitLessThanOrEqual(HLessThanOrEqual * comp)2569*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
2570*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2571*795d594fSAndroid Build Coastguard Worker }
2572*795d594fSAndroid Build Coastguard Worker 
VisitGreaterThan(HGreaterThan * comp)2573*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
2574*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2575*795d594fSAndroid Build Coastguard Worker }
2576*795d594fSAndroid Build Coastguard Worker 
VisitGreaterThan(HGreaterThan * comp)2577*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
2578*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2579*795d594fSAndroid Build Coastguard Worker }
2580*795d594fSAndroid Build Coastguard Worker 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)2581*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
2582*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2583*795d594fSAndroid Build Coastguard Worker }
2584*795d594fSAndroid Build Coastguard Worker 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)2585*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
2586*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2587*795d594fSAndroid Build Coastguard Worker }
2588*795d594fSAndroid Build Coastguard Worker 
VisitBelow(HBelow * comp)2589*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBelow(HBelow* comp) {
2590*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2591*795d594fSAndroid Build Coastguard Worker }
2592*795d594fSAndroid Build Coastguard Worker 
VisitBelow(HBelow * comp)2593*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBelow(HBelow* comp) {
2594*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2595*795d594fSAndroid Build Coastguard Worker }
2596*795d594fSAndroid Build Coastguard Worker 
VisitBelowOrEqual(HBelowOrEqual * comp)2597*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
2598*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2599*795d594fSAndroid Build Coastguard Worker }
2600*795d594fSAndroid Build Coastguard Worker 
VisitBelowOrEqual(HBelowOrEqual * comp)2601*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
2602*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2603*795d594fSAndroid Build Coastguard Worker }
2604*795d594fSAndroid Build Coastguard Worker 
VisitAbove(HAbove * comp)2605*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitAbove(HAbove* comp) {
2606*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2607*795d594fSAndroid Build Coastguard Worker }
2608*795d594fSAndroid Build Coastguard Worker 
VisitAbove(HAbove * comp)2609*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitAbove(HAbove* comp) {
2610*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2611*795d594fSAndroid Build Coastguard Worker }
2612*795d594fSAndroid Build Coastguard Worker 
VisitAboveOrEqual(HAboveOrEqual * comp)2613*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
2614*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2615*795d594fSAndroid Build Coastguard Worker }
2616*795d594fSAndroid Build Coastguard Worker 
VisitAboveOrEqual(HAboveOrEqual * comp)2617*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
2618*795d594fSAndroid Build Coastguard Worker   HandleCondition(comp);
2619*795d594fSAndroid Build Coastguard Worker }
2620*795d594fSAndroid Build Coastguard Worker 
VisitIntConstant(HIntConstant * constant)2621*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
2622*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2623*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
2624*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::ConstantLocation(constant));
2625*795d594fSAndroid Build Coastguard Worker }
2626*795d594fSAndroid Build Coastguard Worker 
VisitIntConstant(HIntConstant * constant)2627*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitIntConstant([[maybe_unused]] HIntConstant* constant) {
2628*795d594fSAndroid Build Coastguard Worker   // Will be generated at use site.
2629*795d594fSAndroid Build Coastguard Worker }
2630*795d594fSAndroid Build Coastguard Worker 
VisitNullConstant(HNullConstant * constant)2631*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
2632*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2633*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
2634*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::ConstantLocation(constant));
2635*795d594fSAndroid Build Coastguard Worker }
2636*795d594fSAndroid Build Coastguard Worker 
VisitNullConstant(HNullConstant * constant)2637*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNullConstant([[maybe_unused]] HNullConstant* constant) {
2638*795d594fSAndroid Build Coastguard Worker   // Will be generated at use site.
2639*795d594fSAndroid Build Coastguard Worker }
2640*795d594fSAndroid Build Coastguard Worker 
VisitLongConstant(HLongConstant * constant)2641*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
2642*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2643*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
2644*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::ConstantLocation(constant));
2645*795d594fSAndroid Build Coastguard Worker }
2646*795d594fSAndroid Build Coastguard Worker 
VisitLongConstant(HLongConstant * constant)2647*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLongConstant([[maybe_unused]] HLongConstant* constant) {
2648*795d594fSAndroid Build Coastguard Worker   // Will be generated at use site.
2649*795d594fSAndroid Build Coastguard Worker }
2650*795d594fSAndroid Build Coastguard Worker 
VisitFloatConstant(HFloatConstant * constant)2651*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
2652*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2653*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
2654*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::ConstantLocation(constant));
2655*795d594fSAndroid Build Coastguard Worker }
2656*795d594fSAndroid Build Coastguard Worker 
VisitFloatConstant(HFloatConstant * constant)2657*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitFloatConstant([[maybe_unused]] HFloatConstant* constant) {
2658*795d594fSAndroid Build Coastguard Worker   // Will be generated at use site.
2659*795d594fSAndroid Build Coastguard Worker }
2660*795d594fSAndroid Build Coastguard Worker 
VisitDoubleConstant(HDoubleConstant * constant)2661*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
2662*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2663*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
2664*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::ConstantLocation(constant));
2665*795d594fSAndroid Build Coastguard Worker }
2666*795d594fSAndroid Build Coastguard Worker 
VisitDoubleConstant(HDoubleConstant * constant)2667*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitDoubleConstant([[maybe_unused]] HDoubleConstant* constant) {
2668*795d594fSAndroid Build Coastguard Worker   // Will be generated at use site.
2669*795d594fSAndroid Build Coastguard Worker }
2670*795d594fSAndroid Build Coastguard Worker 
VisitConstructorFence(HConstructorFence * constructor_fence)2671*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitConstructorFence(HConstructorFence* constructor_fence) {
2672*795d594fSAndroid Build Coastguard Worker   constructor_fence->SetLocations(nullptr);
2673*795d594fSAndroid Build Coastguard Worker }
2674*795d594fSAndroid Build Coastguard Worker 
VisitConstructorFence(HConstructorFence * constructor_fence)2675*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitConstructorFence(
2676*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HConstructorFence* constructor_fence) {
2677*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2678*795d594fSAndroid Build Coastguard Worker }
2679*795d594fSAndroid Build Coastguard Worker 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)2680*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2681*795d594fSAndroid Build Coastguard Worker   memory_barrier->SetLocations(nullptr);
2682*795d594fSAndroid Build Coastguard Worker }
2683*795d594fSAndroid Build Coastguard Worker 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)2684*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2685*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
2686*795d594fSAndroid Build Coastguard Worker }
2687*795d594fSAndroid Build Coastguard Worker 
VisitReturnVoid(HReturnVoid * ret)2688*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
2689*795d594fSAndroid Build Coastguard Worker   ret->SetLocations(nullptr);
2690*795d594fSAndroid Build Coastguard Worker }
2691*795d594fSAndroid Build Coastguard Worker 
VisitReturnVoid(HReturnVoid * ret)2692*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitReturnVoid([[maybe_unused]] HReturnVoid* ret) {
2693*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateFrameExit();
2694*795d594fSAndroid Build Coastguard Worker }
2695*795d594fSAndroid Build Coastguard Worker 
VisitReturn(HReturn * ret)2696*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitReturn(HReturn* ret) {
2697*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2698*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(ret, LocationSummary::kNoCall);
2699*795d594fSAndroid Build Coastguard Worker   SetInForReturnValue(ret, locations);
2700*795d594fSAndroid Build Coastguard Worker }
2701*795d594fSAndroid Build Coastguard Worker 
VisitReturn(HReturn * ret)2702*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
2703*795d594fSAndroid Build Coastguard Worker   switch (ret->InputAt(0)->GetType()) {
2704*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference:
2705*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
2706*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
2707*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
2708*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
2709*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
2710*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
2711*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
2712*795d594fSAndroid Build Coastguard Worker       break;
2713*795d594fSAndroid Build Coastguard Worker 
2714*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
2715*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
2716*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
2717*795d594fSAndroid Build Coastguard Worker       break;
2718*795d594fSAndroid Build Coastguard Worker 
2719*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
2720*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
2721*795d594fSAndroid Build Coastguard Worker       if (GetGraph()->IsCompilingOsr()) {
2722*795d594fSAndroid Build Coastguard Worker         // To simplify callers of an OSR method, we put the return value in both
2723*795d594fSAndroid Build Coastguard Worker         // floating point and core registers.
2724*795d594fSAndroid Build Coastguard Worker         __ movd(EAX, XMM0);
2725*795d594fSAndroid Build Coastguard Worker       }
2726*795d594fSAndroid Build Coastguard Worker       break;
2727*795d594fSAndroid Build Coastguard Worker 
2728*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
2729*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
2730*795d594fSAndroid Build Coastguard Worker       if (GetGraph()->IsCompilingOsr()) {
2731*795d594fSAndroid Build Coastguard Worker         // To simplify callers of an OSR method, we put the return value in both
2732*795d594fSAndroid Build Coastguard Worker         // floating point and core registers.
2733*795d594fSAndroid Build Coastguard Worker         __ movd(EAX, XMM0);
2734*795d594fSAndroid Build Coastguard Worker         // Use XMM1 as temporary register to not clobber XMM0.
2735*795d594fSAndroid Build Coastguard Worker         __ movaps(XMM1, XMM0);
2736*795d594fSAndroid Build Coastguard Worker         __ psrlq(XMM1, Immediate(32));
2737*795d594fSAndroid Build Coastguard Worker         __ movd(EDX, XMM1);
2738*795d594fSAndroid Build Coastguard Worker       }
2739*795d594fSAndroid Build Coastguard Worker       break;
2740*795d594fSAndroid Build Coastguard Worker 
2741*795d594fSAndroid Build Coastguard Worker     default:
2742*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
2743*795d594fSAndroid Build Coastguard Worker   }
2744*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateFrameExit();
2745*795d594fSAndroid Build Coastguard Worker }
2746*795d594fSAndroid Build Coastguard Worker 
VisitInvokeUnresolved(HInvokeUnresolved * invoke)2747*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2748*795d594fSAndroid Build Coastguard Worker   // The trampoline uses the same calling convention as dex calling conventions,
2749*795d594fSAndroid Build Coastguard Worker   // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2750*795d594fSAndroid Build Coastguard Worker   // the method_idx.
2751*795d594fSAndroid Build Coastguard Worker   HandleInvoke(invoke);
2752*795d594fSAndroid Build Coastguard Worker }
2753*795d594fSAndroid Build Coastguard Worker 
VisitInvokeUnresolved(HInvokeUnresolved * invoke)2754*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2755*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2756*795d594fSAndroid Build Coastguard Worker }
2757*795d594fSAndroid Build Coastguard Worker 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)2758*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
2759*795d594fSAndroid Build Coastguard Worker   // Explicit clinit checks triggered by static invokes must have been pruned by
2760*795d594fSAndroid Build Coastguard Worker   // art::PrepareForRegisterAllocation.
2761*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
2762*795d594fSAndroid Build Coastguard Worker 
2763*795d594fSAndroid Build Coastguard Worker   IntrinsicLocationsBuilderX86 intrinsic(codegen_);
2764*795d594fSAndroid Build Coastguard Worker   if (intrinsic.TryDispatch(invoke)) {
2765*795d594fSAndroid Build Coastguard Worker     if (invoke->GetLocations()->CanCall() &&
2766*795d594fSAndroid Build Coastguard Worker         invoke->HasPcRelativeMethodLoadKind() &&
2767*795d594fSAndroid Build Coastguard Worker         invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).IsInvalid()) {
2768*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
2769*795d594fSAndroid Build Coastguard Worker     }
2770*795d594fSAndroid Build Coastguard Worker     return;
2771*795d594fSAndroid Build Coastguard Worker   }
2772*795d594fSAndroid Build Coastguard Worker 
2773*795d594fSAndroid Build Coastguard Worker   if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
2774*795d594fSAndroid Build Coastguard Worker     CriticalNativeCallingConventionVisitorX86 calling_convention_visitor(
2775*795d594fSAndroid Build Coastguard Worker         /*for_register_allocation=*/ true);
2776*795d594fSAndroid Build Coastguard Worker     CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
2777*795d594fSAndroid Build Coastguard Worker   } else {
2778*795d594fSAndroid Build Coastguard Worker     HandleInvoke(invoke);
2779*795d594fSAndroid Build Coastguard Worker   }
2780*795d594fSAndroid Build Coastguard Worker 
2781*795d594fSAndroid Build Coastguard Worker   // For PC-relative load kinds the invoke has an extra input, the PC-relative address base.
2782*795d594fSAndroid Build Coastguard Worker   if (invoke->HasPcRelativeMethodLoadKind()) {
2783*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
2784*795d594fSAndroid Build Coastguard Worker   }
2785*795d594fSAndroid Build Coastguard Worker }
2786*795d594fSAndroid Build Coastguard Worker 
TryGenerateIntrinsicCode(HInvoke * invoke,CodeGeneratorX86 * codegen)2787*795d594fSAndroid Build Coastguard Worker static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
2788*795d594fSAndroid Build Coastguard Worker   if (invoke->GetLocations()->Intrinsified()) {
2789*795d594fSAndroid Build Coastguard Worker     IntrinsicCodeGeneratorX86 intrinsic(codegen);
2790*795d594fSAndroid Build Coastguard Worker     intrinsic.Dispatch(invoke);
2791*795d594fSAndroid Build Coastguard Worker     return true;
2792*795d594fSAndroid Build Coastguard Worker   }
2793*795d594fSAndroid Build Coastguard Worker   return false;
2794*795d594fSAndroid Build Coastguard Worker }
2795*795d594fSAndroid Build Coastguard Worker 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)2796*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
2797*795d594fSAndroid Build Coastguard Worker   // Explicit clinit checks triggered by static invokes must have been pruned by
2798*795d594fSAndroid Build Coastguard Worker   // art::PrepareForRegisterAllocation.
2799*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
2800*795d594fSAndroid Build Coastguard Worker 
2801*795d594fSAndroid Build Coastguard Worker   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2802*795d594fSAndroid Build Coastguard Worker     return;
2803*795d594fSAndroid Build Coastguard Worker   }
2804*795d594fSAndroid Build Coastguard Worker 
2805*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2806*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateStaticOrDirectCall(
2807*795d594fSAndroid Build Coastguard Worker       invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
2808*795d594fSAndroid Build Coastguard Worker }
2809*795d594fSAndroid Build Coastguard Worker 
VisitInvokeVirtual(HInvokeVirtual * invoke)2810*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
2811*795d594fSAndroid Build Coastguard Worker   IntrinsicLocationsBuilderX86 intrinsic(codegen_);
2812*795d594fSAndroid Build Coastguard Worker   if (intrinsic.TryDispatch(invoke)) {
2813*795d594fSAndroid Build Coastguard Worker     return;
2814*795d594fSAndroid Build Coastguard Worker   }
2815*795d594fSAndroid Build Coastguard Worker 
2816*795d594fSAndroid Build Coastguard Worker   HandleInvoke(invoke);
2817*795d594fSAndroid Build Coastguard Worker 
2818*795d594fSAndroid Build Coastguard Worker   if (ProfilingInfoBuilder::IsInlineCacheUseful(invoke, codegen_)) {
2819*795d594fSAndroid Build Coastguard Worker     // Add one temporary for inline cache update.
2820*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP));
2821*795d594fSAndroid Build Coastguard Worker   }
2822*795d594fSAndroid Build Coastguard Worker }
2823*795d594fSAndroid Build Coastguard Worker 
HandleInvoke(HInvoke * invoke)2824*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
2825*795d594fSAndroid Build Coastguard Worker   InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
2826*795d594fSAndroid Build Coastguard Worker   CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
2827*795d594fSAndroid Build Coastguard Worker }
2828*795d594fSAndroid Build Coastguard Worker 
VisitInvokeVirtual(HInvokeVirtual * invoke)2829*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
2830*795d594fSAndroid Build Coastguard Worker   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2831*795d594fSAndroid Build Coastguard Worker     return;
2832*795d594fSAndroid Build Coastguard Worker   }
2833*795d594fSAndroid Build Coastguard Worker 
2834*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
2835*795d594fSAndroid Build Coastguard Worker   DCHECK(!codegen_->IsLeafMethod());
2836*795d594fSAndroid Build Coastguard Worker }
2837*795d594fSAndroid Build Coastguard Worker 
VisitInvokeInterface(HInvokeInterface * invoke)2838*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
2839*795d594fSAndroid Build Coastguard Worker   // This call to HandleInvoke allocates a temporary (core) register
2840*795d594fSAndroid Build Coastguard Worker   // which is also used to transfer the hidden argument from FP to
2841*795d594fSAndroid Build Coastguard Worker   // core register.
2842*795d594fSAndroid Build Coastguard Worker   HandleInvoke(invoke);
2843*795d594fSAndroid Build Coastguard Worker   // Add the hidden argument.
2844*795d594fSAndroid Build Coastguard Worker   invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
2845*795d594fSAndroid Build Coastguard Worker 
2846*795d594fSAndroid Build Coastguard Worker   if (ProfilingInfoBuilder::IsInlineCacheUseful(invoke, codegen_)) {
2847*795d594fSAndroid Build Coastguard Worker     // Add one temporary for inline cache update.
2848*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP));
2849*795d594fSAndroid Build Coastguard Worker   }
2850*795d594fSAndroid Build Coastguard Worker 
2851*795d594fSAndroid Build Coastguard Worker   // For PC-relative load kinds the invoke has an extra input, the PC-relative address base.
2852*795d594fSAndroid Build Coastguard Worker   if (IsPcRelativeMethodLoadKind(invoke->GetHiddenArgumentLoadKind())) {
2853*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
2854*795d594fSAndroid Build Coastguard Worker   }
2855*795d594fSAndroid Build Coastguard Worker 
2856*795d594fSAndroid Build Coastguard Worker   if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
2857*795d594fSAndroid Build Coastguard Worker     invoke->GetLocations()->SetInAt(invoke->GetNumberOfArguments() - 1,
2858*795d594fSAndroid Build Coastguard Worker                                     Location::RequiresRegister());
2859*795d594fSAndroid Build Coastguard Worker   }
2860*795d594fSAndroid Build Coastguard Worker }
2861*795d594fSAndroid Build Coastguard Worker 
MaybeGenerateInlineCacheCheck(HInstruction * instruction,Register klass)2862*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass) {
2863*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EAX, klass);
2864*795d594fSAndroid Build Coastguard Worker   if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) {
2865*795d594fSAndroid Build Coastguard Worker     ProfilingInfo* info = GetGraph()->GetProfilingInfo();
2866*795d594fSAndroid Build Coastguard Worker     DCHECK(info != nullptr);
2867*795d594fSAndroid Build Coastguard Worker     InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(
2868*795d594fSAndroid Build Coastguard Worker         info, GetCompilerOptions(), instruction->AsInvoke());
2869*795d594fSAndroid Build Coastguard Worker     if (cache != nullptr) {
2870*795d594fSAndroid Build Coastguard Worker       uint32_t address = reinterpret_cast32<uint32_t>(cache);
2871*795d594fSAndroid Build Coastguard Worker       if (kIsDebugBuild) {
2872*795d594fSAndroid Build Coastguard Worker         uint32_t temp_index = instruction->GetLocations()->GetTempCount() - 1u;
2873*795d594fSAndroid Build Coastguard Worker         CHECK_EQ(EBP, instruction->GetLocations()->GetTemp(temp_index).AsRegister<Register>());
2874*795d594fSAndroid Build Coastguard Worker       }
2875*795d594fSAndroid Build Coastguard Worker       Register temp = EBP;
2876*795d594fSAndroid Build Coastguard Worker       NearLabel done;
2877*795d594fSAndroid Build Coastguard Worker       __ movl(temp, Immediate(address));
2878*795d594fSAndroid Build Coastguard Worker       // Fast path for a monomorphic cache.
2879*795d594fSAndroid Build Coastguard Worker       __ cmpl(klass, Address(temp, InlineCache::ClassesOffset().Int32Value()));
2880*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &done);
2881*795d594fSAndroid Build Coastguard Worker       GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(kQuickUpdateInlineCache).Int32Value());
2882*795d594fSAndroid Build Coastguard Worker       __ Bind(&done);
2883*795d594fSAndroid Build Coastguard Worker     } else {
2884*795d594fSAndroid Build Coastguard Worker       // This is unexpected, but we don't guarantee stable compilation across
2885*795d594fSAndroid Build Coastguard Worker       // JIT runs so just warn about it.
2886*795d594fSAndroid Build Coastguard Worker       ScopedObjectAccess soa(Thread::Current());
2887*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod();
2888*795d594fSAndroid Build Coastguard Worker     }
2889*795d594fSAndroid Build Coastguard Worker   }
2890*795d594fSAndroid Build Coastguard Worker }
2891*795d594fSAndroid Build Coastguard Worker 
VisitInvokeInterface(HInvokeInterface * invoke)2892*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
2893*795d594fSAndroid Build Coastguard Worker   // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
2894*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = invoke->GetLocations();
2895*795d594fSAndroid Build Coastguard Worker   Register temp = locations->GetTemp(0).AsRegister<Register>();
2896*795d594fSAndroid Build Coastguard Worker   XmmRegister hidden_reg = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
2897*795d594fSAndroid Build Coastguard Worker   Location receiver = locations->InAt(0);
2898*795d594fSAndroid Build Coastguard Worker   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2899*795d594fSAndroid Build Coastguard Worker 
2900*795d594fSAndroid Build Coastguard Worker   // Set the hidden argument. This is safe to do this here, as XMM7
2901*795d594fSAndroid Build Coastguard Worker   // won't be modified thereafter, before the `call` instruction.
2902*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(XMM7, hidden_reg);
2903*795d594fSAndroid Build Coastguard Worker   if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
2904*795d594fSAndroid Build Coastguard Worker     __ movd(hidden_reg, locations->InAt(invoke->GetNumberOfArguments() - 1).AsRegister<Register>());
2905*795d594fSAndroid Build Coastguard Worker   } else if (invoke->GetHiddenArgumentLoadKind() != MethodLoadKind::kRuntimeCall) {
2906*795d594fSAndroid Build Coastguard Worker     codegen_->LoadMethod(invoke->GetHiddenArgumentLoadKind(), locations->GetTemp(0), invoke);
2907*795d594fSAndroid Build Coastguard Worker     __ movd(hidden_reg, temp);
2908*795d594fSAndroid Build Coastguard Worker   }
2909*795d594fSAndroid Build Coastguard Worker 
2910*795d594fSAndroid Build Coastguard Worker   if (receiver.IsStackSlot()) {
2911*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(ESP, receiver.GetStackIndex()));
2912*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp = temp->klass_
2913*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(temp, class_offset));
2914*795d594fSAndroid Build Coastguard Worker   } else {
2915*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Class> */ temp = receiver->klass_
2916*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
2917*795d594fSAndroid Build Coastguard Worker   }
2918*795d594fSAndroid Build Coastguard Worker   codegen_->MaybeRecordImplicitNullCheck(invoke);
2919*795d594fSAndroid Build Coastguard Worker   // Instead of simply (possibly) unpoisoning `temp` here, we should
2920*795d594fSAndroid Build Coastguard Worker   // emit a read barrier for the previous class reference load.
2921*795d594fSAndroid Build Coastguard Worker   // However this is not required in practice, as this is an
2922*795d594fSAndroid Build Coastguard Worker   // intermediate/temporary reference and because the current
2923*795d594fSAndroid Build Coastguard Worker   // concurrent copying collector keeps the from-space memory
2924*795d594fSAndroid Build Coastguard Worker   // intact/accessible until the end of the marking phase (the
2925*795d594fSAndroid Build Coastguard Worker   // concurrent copying collector may not in the future).
2926*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(temp);
2927*795d594fSAndroid Build Coastguard Worker 
2928*795d594fSAndroid Build Coastguard Worker   codegen_->MaybeGenerateInlineCacheCheck(invoke, temp);
2929*795d594fSAndroid Build Coastguard Worker 
2930*795d594fSAndroid Build Coastguard Worker   // temp = temp->GetAddressOfIMT()
2931*795d594fSAndroid Build Coastguard Worker   __ movl(temp,
2932*795d594fSAndroid Build Coastguard Worker       Address(temp, mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
2933*795d594fSAndroid Build Coastguard Worker   // temp = temp->GetImtEntryAt(method_offset);
2934*795d594fSAndroid Build Coastguard Worker   uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
2935*795d594fSAndroid Build Coastguard Worker       invoke->GetImtIndex(), kX86PointerSize));
2936*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(temp, method_offset));
2937*795d594fSAndroid Build Coastguard Worker   if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRuntimeCall) {
2938*795d594fSAndroid Build Coastguard Worker     // We pass the method from the IMT in case of a conflict. This will ensure
2939*795d594fSAndroid Build Coastguard Worker     // we go into the runtime to resolve the actual method.
2940*795d594fSAndroid Build Coastguard Worker     __ movd(hidden_reg, temp);
2941*795d594fSAndroid Build Coastguard Worker   }
2942*795d594fSAndroid Build Coastguard Worker   // call temp->GetEntryPoint();
2943*795d594fSAndroid Build Coastguard Worker   __ call(Address(temp,
2944*795d594fSAndroid Build Coastguard Worker                   ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86PointerSize).Int32Value()));
2945*795d594fSAndroid Build Coastguard Worker 
2946*795d594fSAndroid Build Coastguard Worker   DCHECK(!codegen_->IsLeafMethod());
2947*795d594fSAndroid Build Coastguard Worker   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2948*795d594fSAndroid Build Coastguard Worker }
2949*795d594fSAndroid Build Coastguard Worker 
VisitInvokePolymorphic(HInvokePolymorphic * invoke)2950*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2951*795d594fSAndroid Build Coastguard Worker   IntrinsicLocationsBuilderX86 intrinsic(codegen_);
2952*795d594fSAndroid Build Coastguard Worker   if (intrinsic.TryDispatch(invoke)) {
2953*795d594fSAndroid Build Coastguard Worker     return;
2954*795d594fSAndroid Build Coastguard Worker   }
2955*795d594fSAndroid Build Coastguard Worker   HandleInvoke(invoke);
2956*795d594fSAndroid Build Coastguard Worker }
2957*795d594fSAndroid Build Coastguard Worker 
VisitInvokePolymorphic(HInvokePolymorphic * invoke)2958*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2959*795d594fSAndroid Build Coastguard Worker   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2960*795d594fSAndroid Build Coastguard Worker     return;
2961*795d594fSAndroid Build Coastguard Worker   }
2962*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateInvokePolymorphicCall(invoke);
2963*795d594fSAndroid Build Coastguard Worker }
2964*795d594fSAndroid Build Coastguard Worker 
VisitInvokeCustom(HInvokeCustom * invoke)2965*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInvokeCustom(HInvokeCustom* invoke) {
2966*795d594fSAndroid Build Coastguard Worker   HandleInvoke(invoke);
2967*795d594fSAndroid Build Coastguard Worker }
2968*795d594fSAndroid Build Coastguard Worker 
VisitInvokeCustom(HInvokeCustom * invoke)2969*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInvokeCustom(HInvokeCustom* invoke) {
2970*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateInvokeCustomCall(invoke);
2971*795d594fSAndroid Build Coastguard Worker }
2972*795d594fSAndroid Build Coastguard Worker 
VisitNeg(HNeg * neg)2973*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNeg(HNeg* neg) {
2974*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
2975*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
2976*795d594fSAndroid Build Coastguard Worker   switch (neg->GetResultType()) {
2977*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
2978*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
2979*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
2980*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
2981*795d594fSAndroid Build Coastguard Worker       break;
2982*795d594fSAndroid Build Coastguard Worker 
2983*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
2984*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
2985*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
2986*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
2987*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
2988*795d594fSAndroid Build Coastguard Worker       break;
2989*795d594fSAndroid Build Coastguard Worker 
2990*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
2991*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
2992*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
2993*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
2994*795d594fSAndroid Build Coastguard Worker       break;
2995*795d594fSAndroid Build Coastguard Worker 
2996*795d594fSAndroid Build Coastguard Worker     default:
2997*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2998*795d594fSAndroid Build Coastguard Worker   }
2999*795d594fSAndroid Build Coastguard Worker }
3000*795d594fSAndroid Build Coastguard Worker 
VisitNeg(HNeg * neg)3001*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
3002*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = neg->GetLocations();
3003*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3004*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
3005*795d594fSAndroid Build Coastguard Worker   switch (neg->GetResultType()) {
3006*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3007*795d594fSAndroid Build Coastguard Worker       DCHECK(in.IsRegister());
3008*795d594fSAndroid Build Coastguard Worker       DCHECK(in.Equals(out));
3009*795d594fSAndroid Build Coastguard Worker       __ negl(out.AsRegister<Register>());
3010*795d594fSAndroid Build Coastguard Worker       break;
3011*795d594fSAndroid Build Coastguard Worker 
3012*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
3013*795d594fSAndroid Build Coastguard Worker       DCHECK(in.IsRegisterPair());
3014*795d594fSAndroid Build Coastguard Worker       DCHECK(in.Equals(out));
3015*795d594fSAndroid Build Coastguard Worker       __ negl(out.AsRegisterPairLow<Register>());
3016*795d594fSAndroid Build Coastguard Worker       // Negation is similar to subtraction from zero.  The least
3017*795d594fSAndroid Build Coastguard Worker       // significant byte triggers a borrow when it is different from
3018*795d594fSAndroid Build Coastguard Worker       // zero; to take it into account, add 1 to the most significant
3019*795d594fSAndroid Build Coastguard Worker       // byte if the carry flag (CF) is set to 1 after the first NEGL
3020*795d594fSAndroid Build Coastguard Worker       // operation.
3021*795d594fSAndroid Build Coastguard Worker       __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
3022*795d594fSAndroid Build Coastguard Worker       __ negl(out.AsRegisterPairHigh<Register>());
3023*795d594fSAndroid Build Coastguard Worker       break;
3024*795d594fSAndroid Build Coastguard Worker 
3025*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
3026*795d594fSAndroid Build Coastguard Worker       DCHECK(in.Equals(out));
3027*795d594fSAndroid Build Coastguard Worker       Register constant = locations->GetTemp(0).AsRegister<Register>();
3028*795d594fSAndroid Build Coastguard Worker       XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3029*795d594fSAndroid Build Coastguard Worker       // Implement float negation with an exclusive or with value
3030*795d594fSAndroid Build Coastguard Worker       // 0x80000000 (mask for bit 31, representing the sign of a
3031*795d594fSAndroid Build Coastguard Worker       // single-precision floating-point number).
3032*795d594fSAndroid Build Coastguard Worker       __ movl(constant, Immediate(INT32_C(0x80000000)));
3033*795d594fSAndroid Build Coastguard Worker       __ movd(mask, constant);
3034*795d594fSAndroid Build Coastguard Worker       __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
3035*795d594fSAndroid Build Coastguard Worker       break;
3036*795d594fSAndroid Build Coastguard Worker     }
3037*795d594fSAndroid Build Coastguard Worker 
3038*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3039*795d594fSAndroid Build Coastguard Worker       DCHECK(in.Equals(out));
3040*795d594fSAndroid Build Coastguard Worker       XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3041*795d594fSAndroid Build Coastguard Worker       // Implement double negation with an exclusive or with value
3042*795d594fSAndroid Build Coastguard Worker       // 0x8000000000000000 (mask for bit 63, representing the sign of
3043*795d594fSAndroid Build Coastguard Worker       // a double-precision floating-point number).
3044*795d594fSAndroid Build Coastguard Worker       __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
3045*795d594fSAndroid Build Coastguard Worker       __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
3046*795d594fSAndroid Build Coastguard Worker       break;
3047*795d594fSAndroid Build Coastguard Worker     }
3048*795d594fSAndroid Build Coastguard Worker 
3049*795d594fSAndroid Build Coastguard Worker     default:
3050*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3051*795d594fSAndroid Build Coastguard Worker   }
3052*795d594fSAndroid Build Coastguard Worker }
3053*795d594fSAndroid Build Coastguard Worker 
VisitX86FPNeg(HX86FPNeg * neg)3054*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86FPNeg(HX86FPNeg* neg) {
3055*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3056*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
3057*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(neg->GetType()));
3058*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresFpuRegister());
3059*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
3060*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
3061*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresFpuRegister());
3062*795d594fSAndroid Build Coastguard Worker }
3063*795d594fSAndroid Build Coastguard Worker 
VisitX86FPNeg(HX86FPNeg * neg)3064*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86FPNeg(HX86FPNeg* neg) {
3065*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = neg->GetLocations();
3066*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3067*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->InAt(0).Equals(out));
3068*795d594fSAndroid Build Coastguard Worker 
3069*795d594fSAndroid Build Coastguard Worker   Register constant_area = locations->InAt(1).AsRegister<Register>();
3070*795d594fSAndroid Build Coastguard Worker   XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3071*795d594fSAndroid Build Coastguard Worker   if (neg->GetType() == DataType::Type::kFloat32) {
3072*795d594fSAndroid Build Coastguard Worker     __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x80000000),
3073*795d594fSAndroid Build Coastguard Worker                                                  neg->GetBaseMethodAddress(),
3074*795d594fSAndroid Build Coastguard Worker                                                  constant_area));
3075*795d594fSAndroid Build Coastguard Worker     __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
3076*795d594fSAndroid Build Coastguard Worker   } else {
3077*795d594fSAndroid Build Coastguard Worker     __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000),
3078*795d594fSAndroid Build Coastguard Worker                                                  neg->GetBaseMethodAddress(),
3079*795d594fSAndroid Build Coastguard Worker                                                  constant_area));
3080*795d594fSAndroid Build Coastguard Worker     __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
3081*795d594fSAndroid Build Coastguard Worker   }
3082*795d594fSAndroid Build Coastguard Worker }
3083*795d594fSAndroid Build Coastguard Worker 
VisitTypeConversion(HTypeConversion * conversion)3084*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
3085*795d594fSAndroid Build Coastguard Worker   DataType::Type result_type = conversion->GetResultType();
3086*795d594fSAndroid Build Coastguard Worker   DataType::Type input_type = conversion->GetInputType();
3087*795d594fSAndroid Build Coastguard Worker   DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
3088*795d594fSAndroid Build Coastguard Worker       << input_type << " -> " << result_type;
3089*795d594fSAndroid Build Coastguard Worker 
3090*795d594fSAndroid Build Coastguard Worker   // The float-to-long and double-to-long type conversions rely on a
3091*795d594fSAndroid Build Coastguard Worker   // call to the runtime.
3092*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind =
3093*795d594fSAndroid Build Coastguard Worker       ((input_type == DataType::Type::kFloat32 || input_type == DataType::Type::kFloat64)
3094*795d594fSAndroid Build Coastguard Worker        && result_type == DataType::Type::kInt64)
3095*795d594fSAndroid Build Coastguard Worker       ? LocationSummary::kCallOnMainOnly
3096*795d594fSAndroid Build Coastguard Worker       : LocationSummary::kNoCall;
3097*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3098*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(conversion, call_kind);
3099*795d594fSAndroid Build Coastguard Worker 
3100*795d594fSAndroid Build Coastguard Worker   switch (result_type) {
3101*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
3102*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
3103*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3104*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3105*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3106*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3107*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3108*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3109*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
3110*795d594fSAndroid Build Coastguard Worker           // Make the output overlap to please the register allocator. This greatly simplifies
3111*795d594fSAndroid Build Coastguard Worker           // the validation of the linear scan implementation
3112*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3113*795d594fSAndroid Build Coastguard Worker           break;
3114*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64: {
3115*795d594fSAndroid Build Coastguard Worker           HInstruction* input = conversion->InputAt(0);
3116*795d594fSAndroid Build Coastguard Worker           Location input_location = input->IsConstant()
3117*795d594fSAndroid Build Coastguard Worker               ? Location::ConstantLocation(input)
3118*795d594fSAndroid Build Coastguard Worker               : Location::RegisterPairLocation(EAX, EDX);
3119*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, input_location);
3120*795d594fSAndroid Build Coastguard Worker           // Make the output overlap to please the register allocator. This greatly simplifies
3121*795d594fSAndroid Build Coastguard Worker           // the validation of the linear scan implementation
3122*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3123*795d594fSAndroid Build Coastguard Worker           break;
3124*795d594fSAndroid Build Coastguard Worker         }
3125*795d594fSAndroid Build Coastguard Worker 
3126*795d594fSAndroid Build Coastguard Worker         default:
3127*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3128*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3129*795d594fSAndroid Build Coastguard Worker       }
3130*795d594fSAndroid Build Coastguard Worker       break;
3131*795d594fSAndroid Build Coastguard Worker 
3132*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
3133*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
3134*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsIntegralType(input_type)) << input_type;
3135*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::Any());
3136*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3137*795d594fSAndroid Build Coastguard Worker       break;
3138*795d594fSAndroid Build Coastguard Worker 
3139*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3140*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3141*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3142*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::Any());
3143*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3144*795d594fSAndroid Build Coastguard Worker           break;
3145*795d594fSAndroid Build Coastguard Worker 
3146*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
3147*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresFpuRegister());
3148*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresRegister());
3149*795d594fSAndroid Build Coastguard Worker           locations->AddTemp(Location::RequiresFpuRegister());
3150*795d594fSAndroid Build Coastguard Worker           break;
3151*795d594fSAndroid Build Coastguard Worker 
3152*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64:
3153*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresFpuRegister());
3154*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresRegister());
3155*795d594fSAndroid Build Coastguard Worker           locations->AddTemp(Location::RequiresFpuRegister());
3156*795d594fSAndroid Build Coastguard Worker           break;
3157*795d594fSAndroid Build Coastguard Worker 
3158*795d594fSAndroid Build Coastguard Worker         default:
3159*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3160*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3161*795d594fSAndroid Build Coastguard Worker       }
3162*795d594fSAndroid Build Coastguard Worker       break;
3163*795d594fSAndroid Build Coastguard Worker 
3164*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
3165*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3166*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3167*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3168*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3169*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3170*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3171*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3172*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RegisterLocation(EAX));
3173*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3174*795d594fSAndroid Build Coastguard Worker           break;
3175*795d594fSAndroid Build Coastguard Worker 
3176*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
3177*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64: {
3178*795d594fSAndroid Build Coastguard Worker           InvokeRuntimeCallingConvention calling_convention;
3179*795d594fSAndroid Build Coastguard Worker           XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
3180*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
3181*795d594fSAndroid Build Coastguard Worker 
3182*795d594fSAndroid Build Coastguard Worker           // The runtime helper puts the result in EAX, EDX.
3183*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3184*795d594fSAndroid Build Coastguard Worker         }
3185*795d594fSAndroid Build Coastguard Worker         break;
3186*795d594fSAndroid Build Coastguard Worker 
3187*795d594fSAndroid Build Coastguard Worker         default:
3188*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3189*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3190*795d594fSAndroid Build Coastguard Worker       }
3191*795d594fSAndroid Build Coastguard Worker       break;
3192*795d594fSAndroid Build Coastguard Worker 
3193*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
3194*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3195*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3196*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3197*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3198*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3199*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3200*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3201*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresRegister());
3202*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresFpuRegister());
3203*795d594fSAndroid Build Coastguard Worker           break;
3204*795d594fSAndroid Build Coastguard Worker 
3205*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3206*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::Any());
3207*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::Any());
3208*795d594fSAndroid Build Coastguard Worker           break;
3209*795d594fSAndroid Build Coastguard Worker 
3210*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64:
3211*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresFpuRegister());
3212*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3213*795d594fSAndroid Build Coastguard Worker           break;
3214*795d594fSAndroid Build Coastguard Worker 
3215*795d594fSAndroid Build Coastguard Worker         default:
3216*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3217*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3218*795d594fSAndroid Build Coastguard Worker       }
3219*795d594fSAndroid Build Coastguard Worker       break;
3220*795d594fSAndroid Build Coastguard Worker 
3221*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
3222*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3223*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3224*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3225*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3226*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3227*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3228*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3229*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresRegister());
3230*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresFpuRegister());
3231*795d594fSAndroid Build Coastguard Worker           break;
3232*795d594fSAndroid Build Coastguard Worker 
3233*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3234*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::Any());
3235*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::Any());
3236*795d594fSAndroid Build Coastguard Worker           break;
3237*795d594fSAndroid Build Coastguard Worker 
3238*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
3239*795d594fSAndroid Build Coastguard Worker           locations->SetInAt(0, Location::RequiresFpuRegister());
3240*795d594fSAndroid Build Coastguard Worker           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3241*795d594fSAndroid Build Coastguard Worker           break;
3242*795d594fSAndroid Build Coastguard Worker 
3243*795d594fSAndroid Build Coastguard Worker         default:
3244*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3245*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3246*795d594fSAndroid Build Coastguard Worker       }
3247*795d594fSAndroid Build Coastguard Worker       break;
3248*795d594fSAndroid Build Coastguard Worker 
3249*795d594fSAndroid Build Coastguard Worker     default:
3250*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type conversion from " << input_type
3251*795d594fSAndroid Build Coastguard Worker                  << " to " << result_type;
3252*795d594fSAndroid Build Coastguard Worker   }
3253*795d594fSAndroid Build Coastguard Worker }
3254*795d594fSAndroid Build Coastguard Worker 
VisitTypeConversion(HTypeConversion * conversion)3255*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
3256*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = conversion->GetLocations();
3257*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3258*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
3259*795d594fSAndroid Build Coastguard Worker   DataType::Type result_type = conversion->GetResultType();
3260*795d594fSAndroid Build Coastguard Worker   DataType::Type input_type = conversion->GetInputType();
3261*795d594fSAndroid Build Coastguard Worker   DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
3262*795d594fSAndroid Build Coastguard Worker       << input_type << " -> " << result_type;
3263*795d594fSAndroid Build Coastguard Worker   switch (result_type) {
3264*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
3265*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3266*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3267*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3268*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3269*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3270*795d594fSAndroid Build Coastguard Worker           if (in.IsRegister()) {
3271*795d594fSAndroid Build Coastguard Worker             __ movzxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
3272*795d594fSAndroid Build Coastguard Worker           } else {
3273*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsIntConstant());
3274*795d594fSAndroid Build Coastguard Worker             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3275*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
3276*795d594fSAndroid Build Coastguard Worker           }
3277*795d594fSAndroid Build Coastguard Worker           break;
3278*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3279*795d594fSAndroid Build Coastguard Worker           if (in.IsRegisterPair()) {
3280*795d594fSAndroid Build Coastguard Worker             __ movzxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
3281*795d594fSAndroid Build Coastguard Worker           } else {
3282*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsLongConstant());
3283*795d594fSAndroid Build Coastguard Worker             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3284*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
3285*795d594fSAndroid Build Coastguard Worker           }
3286*795d594fSAndroid Build Coastguard Worker           break;
3287*795d594fSAndroid Build Coastguard Worker 
3288*795d594fSAndroid Build Coastguard Worker         default:
3289*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3290*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3291*795d594fSAndroid Build Coastguard Worker       }
3292*795d594fSAndroid Build Coastguard Worker       break;
3293*795d594fSAndroid Build Coastguard Worker 
3294*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
3295*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3296*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3297*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3298*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3299*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3300*795d594fSAndroid Build Coastguard Worker           if (in.IsRegister()) {
3301*795d594fSAndroid Build Coastguard Worker             __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
3302*795d594fSAndroid Build Coastguard Worker           } else {
3303*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsIntConstant());
3304*795d594fSAndroid Build Coastguard Worker             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3305*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
3306*795d594fSAndroid Build Coastguard Worker           }
3307*795d594fSAndroid Build Coastguard Worker           break;
3308*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3309*795d594fSAndroid Build Coastguard Worker           if (in.IsRegisterPair()) {
3310*795d594fSAndroid Build Coastguard Worker             __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
3311*795d594fSAndroid Build Coastguard Worker           } else {
3312*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsLongConstant());
3313*795d594fSAndroid Build Coastguard Worker             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3314*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
3315*795d594fSAndroid Build Coastguard Worker           }
3316*795d594fSAndroid Build Coastguard Worker           break;
3317*795d594fSAndroid Build Coastguard Worker 
3318*795d594fSAndroid Build Coastguard Worker         default:
3319*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3320*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3321*795d594fSAndroid Build Coastguard Worker       }
3322*795d594fSAndroid Build Coastguard Worker       break;
3323*795d594fSAndroid Build Coastguard Worker 
3324*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
3325*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3326*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3327*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3328*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3329*795d594fSAndroid Build Coastguard Worker           if (in.IsRegister()) {
3330*795d594fSAndroid Build Coastguard Worker             __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
3331*795d594fSAndroid Build Coastguard Worker           } else if (in.IsStackSlot()) {
3332*795d594fSAndroid Build Coastguard Worker             __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3333*795d594fSAndroid Build Coastguard Worker           } else {
3334*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsIntConstant());
3335*795d594fSAndroid Build Coastguard Worker             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3336*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
3337*795d594fSAndroid Build Coastguard Worker           }
3338*795d594fSAndroid Build Coastguard Worker           break;
3339*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3340*795d594fSAndroid Build Coastguard Worker           if (in.IsRegisterPair()) {
3341*795d594fSAndroid Build Coastguard Worker             __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3342*795d594fSAndroid Build Coastguard Worker           } else if (in.IsDoubleStackSlot()) {
3343*795d594fSAndroid Build Coastguard Worker             __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3344*795d594fSAndroid Build Coastguard Worker           } else {
3345*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsLongConstant());
3346*795d594fSAndroid Build Coastguard Worker             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3347*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
3348*795d594fSAndroid Build Coastguard Worker           }
3349*795d594fSAndroid Build Coastguard Worker           break;
3350*795d594fSAndroid Build Coastguard Worker 
3351*795d594fSAndroid Build Coastguard Worker         default:
3352*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3353*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3354*795d594fSAndroid Build Coastguard Worker       }
3355*795d594fSAndroid Build Coastguard Worker       break;
3356*795d594fSAndroid Build Coastguard Worker 
3357*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
3358*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3359*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3360*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3361*795d594fSAndroid Build Coastguard Worker           if (in.IsRegister()) {
3362*795d594fSAndroid Build Coastguard Worker             __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
3363*795d594fSAndroid Build Coastguard Worker           } else if (in.IsStackSlot()) {
3364*795d594fSAndroid Build Coastguard Worker             __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3365*795d594fSAndroid Build Coastguard Worker           } else {
3366*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsIntConstant());
3367*795d594fSAndroid Build Coastguard Worker             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3368*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
3369*795d594fSAndroid Build Coastguard Worker           }
3370*795d594fSAndroid Build Coastguard Worker           break;
3371*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3372*795d594fSAndroid Build Coastguard Worker           if (in.IsRegisterPair()) {
3373*795d594fSAndroid Build Coastguard Worker             __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3374*795d594fSAndroid Build Coastguard Worker           } else if (in.IsDoubleStackSlot()) {
3375*795d594fSAndroid Build Coastguard Worker             __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3376*795d594fSAndroid Build Coastguard Worker           } else {
3377*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsLongConstant());
3378*795d594fSAndroid Build Coastguard Worker             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3379*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
3380*795d594fSAndroid Build Coastguard Worker           }
3381*795d594fSAndroid Build Coastguard Worker           break;
3382*795d594fSAndroid Build Coastguard Worker 
3383*795d594fSAndroid Build Coastguard Worker         default:
3384*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3385*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3386*795d594fSAndroid Build Coastguard Worker       }
3387*795d594fSAndroid Build Coastguard Worker       break;
3388*795d594fSAndroid Build Coastguard Worker 
3389*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3390*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3391*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
3392*795d594fSAndroid Build Coastguard Worker           if (in.IsRegisterPair()) {
3393*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3394*795d594fSAndroid Build Coastguard Worker           } else if (in.IsDoubleStackSlot()) {
3395*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3396*795d594fSAndroid Build Coastguard Worker           } else {
3397*795d594fSAndroid Build Coastguard Worker             DCHECK(in.IsConstant());
3398*795d594fSAndroid Build Coastguard Worker             DCHECK(in.GetConstant()->IsLongConstant());
3399*795d594fSAndroid Build Coastguard Worker             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3400*795d594fSAndroid Build Coastguard Worker             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
3401*795d594fSAndroid Build Coastguard Worker           }
3402*795d594fSAndroid Build Coastguard Worker           break;
3403*795d594fSAndroid Build Coastguard Worker 
3404*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32: {
3405*795d594fSAndroid Build Coastguard Worker           XmmRegister input = in.AsFpuRegister<XmmRegister>();
3406*795d594fSAndroid Build Coastguard Worker           Register output = out.AsRegister<Register>();
3407*795d594fSAndroid Build Coastguard Worker           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3408*795d594fSAndroid Build Coastguard Worker           NearLabel done, nan;
3409*795d594fSAndroid Build Coastguard Worker 
3410*795d594fSAndroid Build Coastguard Worker           __ movl(output, Immediate(kPrimIntMax));
3411*795d594fSAndroid Build Coastguard Worker           // temp = int-to-float(output)
3412*795d594fSAndroid Build Coastguard Worker           __ cvtsi2ss(temp, output);
3413*795d594fSAndroid Build Coastguard Worker           // if input >= temp goto done
3414*795d594fSAndroid Build Coastguard Worker           __ comiss(input, temp);
3415*795d594fSAndroid Build Coastguard Worker           __ j(kAboveEqual, &done);
3416*795d594fSAndroid Build Coastguard Worker           // if input == NaN goto nan
3417*795d594fSAndroid Build Coastguard Worker           __ j(kUnordered, &nan);
3418*795d594fSAndroid Build Coastguard Worker           // output = float-to-int-truncate(input)
3419*795d594fSAndroid Build Coastguard Worker           __ cvttss2si(output, input);
3420*795d594fSAndroid Build Coastguard Worker           __ jmp(&done);
3421*795d594fSAndroid Build Coastguard Worker           __ Bind(&nan);
3422*795d594fSAndroid Build Coastguard Worker           //  output = 0
3423*795d594fSAndroid Build Coastguard Worker           __ xorl(output, output);
3424*795d594fSAndroid Build Coastguard Worker           __ Bind(&done);
3425*795d594fSAndroid Build Coastguard Worker           break;
3426*795d594fSAndroid Build Coastguard Worker         }
3427*795d594fSAndroid Build Coastguard Worker 
3428*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64: {
3429*795d594fSAndroid Build Coastguard Worker           XmmRegister input = in.AsFpuRegister<XmmRegister>();
3430*795d594fSAndroid Build Coastguard Worker           Register output = out.AsRegister<Register>();
3431*795d594fSAndroid Build Coastguard Worker           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3432*795d594fSAndroid Build Coastguard Worker           NearLabel done, nan;
3433*795d594fSAndroid Build Coastguard Worker 
3434*795d594fSAndroid Build Coastguard Worker           __ movl(output, Immediate(kPrimIntMax));
3435*795d594fSAndroid Build Coastguard Worker           // temp = int-to-double(output)
3436*795d594fSAndroid Build Coastguard Worker           __ cvtsi2sd(temp, output);
3437*795d594fSAndroid Build Coastguard Worker           // if input >= temp goto done
3438*795d594fSAndroid Build Coastguard Worker           __ comisd(input, temp);
3439*795d594fSAndroid Build Coastguard Worker           __ j(kAboveEqual, &done);
3440*795d594fSAndroid Build Coastguard Worker           // if input == NaN goto nan
3441*795d594fSAndroid Build Coastguard Worker           __ j(kUnordered, &nan);
3442*795d594fSAndroid Build Coastguard Worker           // output = double-to-int-truncate(input)
3443*795d594fSAndroid Build Coastguard Worker           __ cvttsd2si(output, input);
3444*795d594fSAndroid Build Coastguard Worker           __ jmp(&done);
3445*795d594fSAndroid Build Coastguard Worker           __ Bind(&nan);
3446*795d594fSAndroid Build Coastguard Worker           //  output = 0
3447*795d594fSAndroid Build Coastguard Worker           __ xorl(output, output);
3448*795d594fSAndroid Build Coastguard Worker           __ Bind(&done);
3449*795d594fSAndroid Build Coastguard Worker           break;
3450*795d594fSAndroid Build Coastguard Worker         }
3451*795d594fSAndroid Build Coastguard Worker 
3452*795d594fSAndroid Build Coastguard Worker         default:
3453*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3454*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3455*795d594fSAndroid Build Coastguard Worker       }
3456*795d594fSAndroid Build Coastguard Worker       break;
3457*795d594fSAndroid Build Coastguard Worker 
3458*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
3459*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3460*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3461*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3462*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3463*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3464*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3465*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3466*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
3467*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
3468*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(in.AsRegister<Register>(), EAX);
3469*795d594fSAndroid Build Coastguard Worker           __ cdq();
3470*795d594fSAndroid Build Coastguard Worker           break;
3471*795d594fSAndroid Build Coastguard Worker 
3472*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
3473*795d594fSAndroid Build Coastguard Worker           codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
3474*795d594fSAndroid Build Coastguard Worker           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
3475*795d594fSAndroid Build Coastguard Worker           break;
3476*795d594fSAndroid Build Coastguard Worker 
3477*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64:
3478*795d594fSAndroid Build Coastguard Worker           codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
3479*795d594fSAndroid Build Coastguard Worker           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
3480*795d594fSAndroid Build Coastguard Worker           break;
3481*795d594fSAndroid Build Coastguard Worker 
3482*795d594fSAndroid Build Coastguard Worker         default:
3483*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3484*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3485*795d594fSAndroid Build Coastguard Worker       }
3486*795d594fSAndroid Build Coastguard Worker       break;
3487*795d594fSAndroid Build Coastguard Worker 
3488*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
3489*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3490*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3491*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3492*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3493*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3494*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3495*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3496*795d594fSAndroid Build Coastguard Worker           __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
3497*795d594fSAndroid Build Coastguard Worker           break;
3498*795d594fSAndroid Build Coastguard Worker 
3499*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64: {
3500*795d594fSAndroid Build Coastguard Worker           size_t adjustment = 0;
3501*795d594fSAndroid Build Coastguard Worker 
3502*795d594fSAndroid Build Coastguard Worker           // Create stack space for the call to
3503*795d594fSAndroid Build Coastguard Worker           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
3504*795d594fSAndroid Build Coastguard Worker           // TODO: enhance register allocator to ask for stack temporaries.
3505*795d594fSAndroid Build Coastguard Worker           if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
3506*795d594fSAndroid Build Coastguard Worker             adjustment = DataType::Size(DataType::Type::kInt64);
3507*795d594fSAndroid Build Coastguard Worker             codegen_->IncreaseFrame(adjustment);
3508*795d594fSAndroid Build Coastguard Worker           }
3509*795d594fSAndroid Build Coastguard Worker 
3510*795d594fSAndroid Build Coastguard Worker           // Load the value to the FP stack, using temporaries if needed.
3511*795d594fSAndroid Build Coastguard Worker           PushOntoFPStack(in, 0, adjustment, false, true);
3512*795d594fSAndroid Build Coastguard Worker 
3513*795d594fSAndroid Build Coastguard Worker           if (out.IsStackSlot()) {
3514*795d594fSAndroid Build Coastguard Worker             __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
3515*795d594fSAndroid Build Coastguard Worker           } else {
3516*795d594fSAndroid Build Coastguard Worker             __ fstps(Address(ESP, 0));
3517*795d594fSAndroid Build Coastguard Worker             Location stack_temp = Location::StackSlot(0);
3518*795d594fSAndroid Build Coastguard Worker             codegen_->Move32(out, stack_temp);
3519*795d594fSAndroid Build Coastguard Worker           }
3520*795d594fSAndroid Build Coastguard Worker 
3521*795d594fSAndroid Build Coastguard Worker           // Remove the temporary stack space we allocated.
3522*795d594fSAndroid Build Coastguard Worker           if (adjustment != 0) {
3523*795d594fSAndroid Build Coastguard Worker             codegen_->DecreaseFrame(adjustment);
3524*795d594fSAndroid Build Coastguard Worker           }
3525*795d594fSAndroid Build Coastguard Worker           break;
3526*795d594fSAndroid Build Coastguard Worker         }
3527*795d594fSAndroid Build Coastguard Worker 
3528*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64:
3529*795d594fSAndroid Build Coastguard Worker           __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3530*795d594fSAndroid Build Coastguard Worker           break;
3531*795d594fSAndroid Build Coastguard Worker 
3532*795d594fSAndroid Build Coastguard Worker         default:
3533*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3534*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3535*795d594fSAndroid Build Coastguard Worker       }
3536*795d594fSAndroid Build Coastguard Worker       break;
3537*795d594fSAndroid Build Coastguard Worker 
3538*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
3539*795d594fSAndroid Build Coastguard Worker       switch (input_type) {
3540*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
3541*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint8:
3542*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
3543*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
3544*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
3545*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
3546*795d594fSAndroid Build Coastguard Worker           __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
3547*795d594fSAndroid Build Coastguard Worker           break;
3548*795d594fSAndroid Build Coastguard Worker 
3549*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64: {
3550*795d594fSAndroid Build Coastguard Worker           size_t adjustment = 0;
3551*795d594fSAndroid Build Coastguard Worker 
3552*795d594fSAndroid Build Coastguard Worker           // Create stack space for the call to
3553*795d594fSAndroid Build Coastguard Worker           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
3554*795d594fSAndroid Build Coastguard Worker           // TODO: enhance register allocator to ask for stack temporaries.
3555*795d594fSAndroid Build Coastguard Worker           if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
3556*795d594fSAndroid Build Coastguard Worker             adjustment = DataType::Size(DataType::Type::kInt64);
3557*795d594fSAndroid Build Coastguard Worker             codegen_->IncreaseFrame(adjustment);
3558*795d594fSAndroid Build Coastguard Worker           }
3559*795d594fSAndroid Build Coastguard Worker 
3560*795d594fSAndroid Build Coastguard Worker           // Load the value to the FP stack, using temporaries if needed.
3561*795d594fSAndroid Build Coastguard Worker           PushOntoFPStack(in, 0, adjustment, false, true);
3562*795d594fSAndroid Build Coastguard Worker 
3563*795d594fSAndroid Build Coastguard Worker           if (out.IsDoubleStackSlot()) {
3564*795d594fSAndroid Build Coastguard Worker             __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
3565*795d594fSAndroid Build Coastguard Worker           } else {
3566*795d594fSAndroid Build Coastguard Worker             __ fstpl(Address(ESP, 0));
3567*795d594fSAndroid Build Coastguard Worker             Location stack_temp = Location::DoubleStackSlot(0);
3568*795d594fSAndroid Build Coastguard Worker             codegen_->Move64(out, stack_temp);
3569*795d594fSAndroid Build Coastguard Worker           }
3570*795d594fSAndroid Build Coastguard Worker 
3571*795d594fSAndroid Build Coastguard Worker           // Remove the temporary stack space we allocated.
3572*795d594fSAndroid Build Coastguard Worker           if (adjustment != 0) {
3573*795d594fSAndroid Build Coastguard Worker             codegen_->DecreaseFrame(adjustment);
3574*795d594fSAndroid Build Coastguard Worker           }
3575*795d594fSAndroid Build Coastguard Worker           break;
3576*795d594fSAndroid Build Coastguard Worker         }
3577*795d594fSAndroid Build Coastguard Worker 
3578*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
3579*795d594fSAndroid Build Coastguard Worker           __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3580*795d594fSAndroid Build Coastguard Worker           break;
3581*795d594fSAndroid Build Coastguard Worker 
3582*795d594fSAndroid Build Coastguard Worker         default:
3583*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected type conversion from " << input_type
3584*795d594fSAndroid Build Coastguard Worker                      << " to " << result_type;
3585*795d594fSAndroid Build Coastguard Worker       }
3586*795d594fSAndroid Build Coastguard Worker       break;
3587*795d594fSAndroid Build Coastguard Worker 
3588*795d594fSAndroid Build Coastguard Worker     default:
3589*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type conversion from " << input_type
3590*795d594fSAndroid Build Coastguard Worker                  << " to " << result_type;
3591*795d594fSAndroid Build Coastguard Worker   }
3592*795d594fSAndroid Build Coastguard Worker }
3593*795d594fSAndroid Build Coastguard Worker 
VisitAdd(HAdd * add)3594*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitAdd(HAdd* add) {
3595*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3596*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(add, LocationSummary::kNoCall);
3597*795d594fSAndroid Build Coastguard Worker   switch (add->GetResultType()) {
3598*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
3599*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
3600*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3601*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3602*795d594fSAndroid Build Coastguard Worker       break;
3603*795d594fSAndroid Build Coastguard Worker     }
3604*795d594fSAndroid Build Coastguard Worker 
3605*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3606*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
3607*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
3608*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3609*795d594fSAndroid Build Coastguard Worker       break;
3610*795d594fSAndroid Build Coastguard Worker     }
3611*795d594fSAndroid Build Coastguard Worker 
3612*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
3613*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3614*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
3615*795d594fSAndroid Build Coastguard Worker       if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3616*795d594fSAndroid Build Coastguard Worker         DCHECK(add->InputAt(1)->IsEmittedAtUseSite());
3617*795d594fSAndroid Build Coastguard Worker       } else if (add->InputAt(1)->IsConstant()) {
3618*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
3619*795d594fSAndroid Build Coastguard Worker       } else {
3620*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
3621*795d594fSAndroid Build Coastguard Worker       }
3622*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3623*795d594fSAndroid Build Coastguard Worker       break;
3624*795d594fSAndroid Build Coastguard Worker     }
3625*795d594fSAndroid Build Coastguard Worker 
3626*795d594fSAndroid Build Coastguard Worker     default:
3627*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
3628*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
3629*795d594fSAndroid Build Coastguard Worker   }
3630*795d594fSAndroid Build Coastguard Worker }
3631*795d594fSAndroid Build Coastguard Worker 
VisitAdd(HAdd * add)3632*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
3633*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = add->GetLocations();
3634*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
3635*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
3636*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3637*795d594fSAndroid Build Coastguard Worker 
3638*795d594fSAndroid Build Coastguard Worker   switch (add->GetResultType()) {
3639*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
3640*795d594fSAndroid Build Coastguard Worker       if (second.IsRegister()) {
3641*795d594fSAndroid Build Coastguard Worker         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3642*795d594fSAndroid Build Coastguard Worker           __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
3643*795d594fSAndroid Build Coastguard Worker         } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3644*795d594fSAndroid Build Coastguard Worker           __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
3645*795d594fSAndroid Build Coastguard Worker         } else {
3646*795d594fSAndroid Build Coastguard Worker           __ leal(out.AsRegister<Register>(), Address(
3647*795d594fSAndroid Build Coastguard Worker               first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
3648*795d594fSAndroid Build Coastguard Worker           }
3649*795d594fSAndroid Build Coastguard Worker       } else if (second.IsConstant()) {
3650*795d594fSAndroid Build Coastguard Worker         int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
3651*795d594fSAndroid Build Coastguard Worker         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3652*795d594fSAndroid Build Coastguard Worker           __ addl(out.AsRegister<Register>(), Immediate(value));
3653*795d594fSAndroid Build Coastguard Worker         } else {
3654*795d594fSAndroid Build Coastguard Worker           __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
3655*795d594fSAndroid Build Coastguard Worker         }
3656*795d594fSAndroid Build Coastguard Worker       } else {
3657*795d594fSAndroid Build Coastguard Worker         DCHECK(first.Equals(locations->Out()));
3658*795d594fSAndroid Build Coastguard Worker         __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
3659*795d594fSAndroid Build Coastguard Worker       }
3660*795d594fSAndroid Build Coastguard Worker       break;
3661*795d594fSAndroid Build Coastguard Worker     }
3662*795d594fSAndroid Build Coastguard Worker 
3663*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3664*795d594fSAndroid Build Coastguard Worker       if (second.IsRegisterPair()) {
3665*795d594fSAndroid Build Coastguard Worker         __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3666*795d594fSAndroid Build Coastguard Worker         __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
3667*795d594fSAndroid Build Coastguard Worker       } else if (second.IsDoubleStackSlot()) {
3668*795d594fSAndroid Build Coastguard Worker         __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3669*795d594fSAndroid Build Coastguard Worker         __ adcl(first.AsRegisterPairHigh<Register>(),
3670*795d594fSAndroid Build Coastguard Worker                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
3671*795d594fSAndroid Build Coastguard Worker       } else {
3672*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsConstant()) << second;
3673*795d594fSAndroid Build Coastguard Worker         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3674*795d594fSAndroid Build Coastguard Worker         __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
3675*795d594fSAndroid Build Coastguard Worker         __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
3676*795d594fSAndroid Build Coastguard Worker       }
3677*795d594fSAndroid Build Coastguard Worker       break;
3678*795d594fSAndroid Build Coastguard Worker     }
3679*795d594fSAndroid Build Coastguard Worker 
3680*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
3681*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3682*795d594fSAndroid Build Coastguard Worker         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3683*795d594fSAndroid Build Coastguard Worker       } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3684*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
3685*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
3686*795d594fSAndroid Build Coastguard Worker         __ addss(first.AsFpuRegister<XmmRegister>(),
3687*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralFloatAddress(
3688*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsFloatConstant()->GetValue(),
3689*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
3690*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3691*795d594fSAndroid Build Coastguard Worker       } else {
3692*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsStackSlot());
3693*795d594fSAndroid Build Coastguard Worker         __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3694*795d594fSAndroid Build Coastguard Worker       }
3695*795d594fSAndroid Build Coastguard Worker       break;
3696*795d594fSAndroid Build Coastguard Worker     }
3697*795d594fSAndroid Build Coastguard Worker 
3698*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3699*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3700*795d594fSAndroid Build Coastguard Worker         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3701*795d594fSAndroid Build Coastguard Worker       } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3702*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
3703*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
3704*795d594fSAndroid Build Coastguard Worker         __ addsd(first.AsFpuRegister<XmmRegister>(),
3705*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralDoubleAddress(
3706*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3707*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
3708*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3709*795d594fSAndroid Build Coastguard Worker       } else {
3710*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsDoubleStackSlot());
3711*795d594fSAndroid Build Coastguard Worker         __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3712*795d594fSAndroid Build Coastguard Worker       }
3713*795d594fSAndroid Build Coastguard Worker       break;
3714*795d594fSAndroid Build Coastguard Worker     }
3715*795d594fSAndroid Build Coastguard Worker 
3716*795d594fSAndroid Build Coastguard Worker     default:
3717*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
3718*795d594fSAndroid Build Coastguard Worker   }
3719*795d594fSAndroid Build Coastguard Worker }
3720*795d594fSAndroid Build Coastguard Worker 
VisitSub(HSub * sub)3721*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitSub(HSub* sub) {
3722*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3723*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(sub, LocationSummary::kNoCall);
3724*795d594fSAndroid Build Coastguard Worker   switch (sub->GetResultType()) {
3725*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3726*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3727*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
3728*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
3729*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3730*795d594fSAndroid Build Coastguard Worker       break;
3731*795d594fSAndroid Build Coastguard Worker     }
3732*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
3733*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3734*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
3735*795d594fSAndroid Build Coastguard Worker       if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3736*795d594fSAndroid Build Coastguard Worker         DCHECK(sub->InputAt(1)->IsEmittedAtUseSite());
3737*795d594fSAndroid Build Coastguard Worker       } else if (sub->InputAt(1)->IsConstant()) {
3738*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
3739*795d594fSAndroid Build Coastguard Worker       } else {
3740*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
3741*795d594fSAndroid Build Coastguard Worker       }
3742*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3743*795d594fSAndroid Build Coastguard Worker       break;
3744*795d594fSAndroid Build Coastguard Worker     }
3745*795d594fSAndroid Build Coastguard Worker 
3746*795d594fSAndroid Build Coastguard Worker     default:
3747*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
3748*795d594fSAndroid Build Coastguard Worker   }
3749*795d594fSAndroid Build Coastguard Worker }
3750*795d594fSAndroid Build Coastguard Worker 
VisitSub(HSub * sub)3751*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
3752*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = sub->GetLocations();
3753*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
3754*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
3755*795d594fSAndroid Build Coastguard Worker   DCHECK(first.Equals(locations->Out()));
3756*795d594fSAndroid Build Coastguard Worker   switch (sub->GetResultType()) {
3757*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
3758*795d594fSAndroid Build Coastguard Worker       if (second.IsRegister()) {
3759*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
3760*795d594fSAndroid Build Coastguard Worker       } else if (second.IsConstant()) {
3761*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegister<Register>(),
3762*795d594fSAndroid Build Coastguard Worker                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
3763*795d594fSAndroid Build Coastguard Worker       } else {
3764*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
3765*795d594fSAndroid Build Coastguard Worker       }
3766*795d594fSAndroid Build Coastguard Worker       break;
3767*795d594fSAndroid Build Coastguard Worker     }
3768*795d594fSAndroid Build Coastguard Worker 
3769*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3770*795d594fSAndroid Build Coastguard Worker       if (second.IsRegisterPair()) {
3771*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3772*795d594fSAndroid Build Coastguard Worker         __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
3773*795d594fSAndroid Build Coastguard Worker       } else if (second.IsDoubleStackSlot()) {
3774*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3775*795d594fSAndroid Build Coastguard Worker         __ sbbl(first.AsRegisterPairHigh<Register>(),
3776*795d594fSAndroid Build Coastguard Worker                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
3777*795d594fSAndroid Build Coastguard Worker       } else {
3778*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsConstant()) << second;
3779*795d594fSAndroid Build Coastguard Worker         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3780*795d594fSAndroid Build Coastguard Worker         __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
3781*795d594fSAndroid Build Coastguard Worker         __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
3782*795d594fSAndroid Build Coastguard Worker       }
3783*795d594fSAndroid Build Coastguard Worker       break;
3784*795d594fSAndroid Build Coastguard Worker     }
3785*795d594fSAndroid Build Coastguard Worker 
3786*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
3787*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3788*795d594fSAndroid Build Coastguard Worker         __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3789*795d594fSAndroid Build Coastguard Worker       } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3790*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
3791*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
3792*795d594fSAndroid Build Coastguard Worker         __ subss(first.AsFpuRegister<XmmRegister>(),
3793*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralFloatAddress(
3794*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsFloatConstant()->GetValue(),
3795*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
3796*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3797*795d594fSAndroid Build Coastguard Worker       } else {
3798*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsStackSlot());
3799*795d594fSAndroid Build Coastguard Worker         __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3800*795d594fSAndroid Build Coastguard Worker       }
3801*795d594fSAndroid Build Coastguard Worker       break;
3802*795d594fSAndroid Build Coastguard Worker     }
3803*795d594fSAndroid Build Coastguard Worker 
3804*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3805*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3806*795d594fSAndroid Build Coastguard Worker         __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3807*795d594fSAndroid Build Coastguard Worker       } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3808*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
3809*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
3810*795d594fSAndroid Build Coastguard Worker         __ subsd(first.AsFpuRegister<XmmRegister>(),
3811*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralDoubleAddress(
3812*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3813*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
3814*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3815*795d594fSAndroid Build Coastguard Worker       } else {
3816*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsDoubleStackSlot());
3817*795d594fSAndroid Build Coastguard Worker         __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3818*795d594fSAndroid Build Coastguard Worker       }
3819*795d594fSAndroid Build Coastguard Worker       break;
3820*795d594fSAndroid Build Coastguard Worker     }
3821*795d594fSAndroid Build Coastguard Worker 
3822*795d594fSAndroid Build Coastguard Worker     default:
3823*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
3824*795d594fSAndroid Build Coastguard Worker   }
3825*795d594fSAndroid Build Coastguard Worker }
3826*795d594fSAndroid Build Coastguard Worker 
VisitMul(HMul * mul)3827*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMul(HMul* mul) {
3828*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
3829*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
3830*795d594fSAndroid Build Coastguard Worker   switch (mul->GetResultType()) {
3831*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3832*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
3833*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
3834*795d594fSAndroid Build Coastguard Worker       if (mul->InputAt(1)->IsIntConstant()) {
3835*795d594fSAndroid Build Coastguard Worker         // Can use 3 operand multiply.
3836*795d594fSAndroid Build Coastguard Worker         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3837*795d594fSAndroid Build Coastguard Worker       } else {
3838*795d594fSAndroid Build Coastguard Worker         locations->SetOut(Location::SameAsFirstInput());
3839*795d594fSAndroid Build Coastguard Worker       }
3840*795d594fSAndroid Build Coastguard Worker       break;
3841*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3842*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
3843*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
3844*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3845*795d594fSAndroid Build Coastguard Worker       // Needed for imul on 32bits with 64bits output.
3846*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
3847*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EDX));
3848*795d594fSAndroid Build Coastguard Worker       break;
3849*795d594fSAndroid Build Coastguard Worker     }
3850*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
3851*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3852*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
3853*795d594fSAndroid Build Coastguard Worker       if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3854*795d594fSAndroid Build Coastguard Worker         DCHECK(mul->InputAt(1)->IsEmittedAtUseSite());
3855*795d594fSAndroid Build Coastguard Worker       } else if (mul->InputAt(1)->IsConstant()) {
3856*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
3857*795d594fSAndroid Build Coastguard Worker       } else {
3858*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
3859*795d594fSAndroid Build Coastguard Worker       }
3860*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
3861*795d594fSAndroid Build Coastguard Worker       break;
3862*795d594fSAndroid Build Coastguard Worker     }
3863*795d594fSAndroid Build Coastguard Worker 
3864*795d594fSAndroid Build Coastguard Worker     default:
3865*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
3866*795d594fSAndroid Build Coastguard Worker   }
3867*795d594fSAndroid Build Coastguard Worker }
3868*795d594fSAndroid Build Coastguard Worker 
VisitMul(HMul * mul)3869*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
3870*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = mul->GetLocations();
3871*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
3872*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
3873*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
3874*795d594fSAndroid Build Coastguard Worker 
3875*795d594fSAndroid Build Coastguard Worker   switch (mul->GetResultType()) {
3876*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
3877*795d594fSAndroid Build Coastguard Worker       // The constant may have ended up in a register, so test explicitly to avoid
3878*795d594fSAndroid Build Coastguard Worker       // problems where the output may not be the same as the first operand.
3879*795d594fSAndroid Build Coastguard Worker       if (mul->InputAt(1)->IsIntConstant()) {
3880*795d594fSAndroid Build Coastguard Worker         Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3881*795d594fSAndroid Build Coastguard Worker         __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
3882*795d594fSAndroid Build Coastguard Worker       } else if (second.IsRegister()) {
3883*795d594fSAndroid Build Coastguard Worker         DCHECK(first.Equals(out));
3884*795d594fSAndroid Build Coastguard Worker         __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
3885*795d594fSAndroid Build Coastguard Worker       } else {
3886*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsStackSlot());
3887*795d594fSAndroid Build Coastguard Worker         DCHECK(first.Equals(out));
3888*795d594fSAndroid Build Coastguard Worker         __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
3889*795d594fSAndroid Build Coastguard Worker       }
3890*795d594fSAndroid Build Coastguard Worker       break;
3891*795d594fSAndroid Build Coastguard Worker 
3892*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
3893*795d594fSAndroid Build Coastguard Worker       Register in1_hi = first.AsRegisterPairHigh<Register>();
3894*795d594fSAndroid Build Coastguard Worker       Register in1_lo = first.AsRegisterPairLow<Register>();
3895*795d594fSAndroid Build Coastguard Worker       Register eax = locations->GetTemp(0).AsRegister<Register>();
3896*795d594fSAndroid Build Coastguard Worker       Register edx = locations->GetTemp(1).AsRegister<Register>();
3897*795d594fSAndroid Build Coastguard Worker 
3898*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(EAX, eax);
3899*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(EDX, edx);
3900*795d594fSAndroid Build Coastguard Worker 
3901*795d594fSAndroid Build Coastguard Worker       // input: in1 - 64 bits, in2 - 64 bits.
3902*795d594fSAndroid Build Coastguard Worker       // output: in1
3903*795d594fSAndroid Build Coastguard Worker       // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
3904*795d594fSAndroid Build Coastguard Worker       // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
3905*795d594fSAndroid Build Coastguard Worker       // parts: in1.lo = (in1.lo * in2.lo)[31:0]
3906*795d594fSAndroid Build Coastguard Worker       if (second.IsConstant()) {
3907*795d594fSAndroid Build Coastguard Worker         DCHECK(second.GetConstant()->IsLongConstant());
3908*795d594fSAndroid Build Coastguard Worker 
3909*795d594fSAndroid Build Coastguard Worker         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3910*795d594fSAndroid Build Coastguard Worker         int32_t low_value = Low32Bits(value);
3911*795d594fSAndroid Build Coastguard Worker         int32_t high_value = High32Bits(value);
3912*795d594fSAndroid Build Coastguard Worker         Immediate low(low_value);
3913*795d594fSAndroid Build Coastguard Worker         Immediate high(high_value);
3914*795d594fSAndroid Build Coastguard Worker 
3915*795d594fSAndroid Build Coastguard Worker         __ movl(eax, high);
3916*795d594fSAndroid Build Coastguard Worker         // eax <- in1.lo * in2.hi
3917*795d594fSAndroid Build Coastguard Worker         __ imull(eax, in1_lo);
3918*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.hi * in2.lo
3919*795d594fSAndroid Build Coastguard Worker         __ imull(in1_hi, low);
3920*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3921*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, eax);
3922*795d594fSAndroid Build Coastguard Worker         // move in2_lo to eax to prepare for double precision
3923*795d594fSAndroid Build Coastguard Worker         __ movl(eax, low);
3924*795d594fSAndroid Build Coastguard Worker         // edx:eax <- in1.lo * in2.lo
3925*795d594fSAndroid Build Coastguard Worker         __ mull(in1_lo);
3926*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3927*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, edx);
3928*795d594fSAndroid Build Coastguard Worker         // in1.lo <- (in1.lo * in2.lo)[31:0];
3929*795d594fSAndroid Build Coastguard Worker         __ movl(in1_lo, eax);
3930*795d594fSAndroid Build Coastguard Worker       } else if (second.IsRegisterPair()) {
3931*795d594fSAndroid Build Coastguard Worker         Register in2_hi = second.AsRegisterPairHigh<Register>();
3932*795d594fSAndroid Build Coastguard Worker         Register in2_lo = second.AsRegisterPairLow<Register>();
3933*795d594fSAndroid Build Coastguard Worker 
3934*795d594fSAndroid Build Coastguard Worker         __ movl(eax, in2_hi);
3935*795d594fSAndroid Build Coastguard Worker         // eax <- in1.lo * in2.hi
3936*795d594fSAndroid Build Coastguard Worker         __ imull(eax, in1_lo);
3937*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.hi * in2.lo
3938*795d594fSAndroid Build Coastguard Worker         __ imull(in1_hi, in2_lo);
3939*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3940*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, eax);
3941*795d594fSAndroid Build Coastguard Worker         // move in1_lo to eax to prepare for double precision
3942*795d594fSAndroid Build Coastguard Worker         __ movl(eax, in1_lo);
3943*795d594fSAndroid Build Coastguard Worker         // edx:eax <- in1.lo * in2.lo
3944*795d594fSAndroid Build Coastguard Worker         __ mull(in2_lo);
3945*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3946*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, edx);
3947*795d594fSAndroid Build Coastguard Worker         // in1.lo <- (in1.lo * in2.lo)[31:0];
3948*795d594fSAndroid Build Coastguard Worker         __ movl(in1_lo, eax);
3949*795d594fSAndroid Build Coastguard Worker       } else {
3950*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsDoubleStackSlot()) << second;
3951*795d594fSAndroid Build Coastguard Worker         Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
3952*795d594fSAndroid Build Coastguard Worker         Address in2_lo(ESP, second.GetStackIndex());
3953*795d594fSAndroid Build Coastguard Worker 
3954*795d594fSAndroid Build Coastguard Worker         __ movl(eax, in2_hi);
3955*795d594fSAndroid Build Coastguard Worker         // eax <- in1.lo * in2.hi
3956*795d594fSAndroid Build Coastguard Worker         __ imull(eax, in1_lo);
3957*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.hi * in2.lo
3958*795d594fSAndroid Build Coastguard Worker         __ imull(in1_hi, in2_lo);
3959*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3960*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, eax);
3961*795d594fSAndroid Build Coastguard Worker         // move in1_lo to eax to prepare for double precision
3962*795d594fSAndroid Build Coastguard Worker         __ movl(eax, in1_lo);
3963*795d594fSAndroid Build Coastguard Worker         // edx:eax <- in1.lo * in2.lo
3964*795d594fSAndroid Build Coastguard Worker         __ mull(in2_lo);
3965*795d594fSAndroid Build Coastguard Worker         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3966*795d594fSAndroid Build Coastguard Worker         __ addl(in1_hi, edx);
3967*795d594fSAndroid Build Coastguard Worker         // in1.lo <- (in1.lo * in2.lo)[31:0];
3968*795d594fSAndroid Build Coastguard Worker         __ movl(in1_lo, eax);
3969*795d594fSAndroid Build Coastguard Worker       }
3970*795d594fSAndroid Build Coastguard Worker 
3971*795d594fSAndroid Build Coastguard Worker       break;
3972*795d594fSAndroid Build Coastguard Worker     }
3973*795d594fSAndroid Build Coastguard Worker 
3974*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
3975*795d594fSAndroid Build Coastguard Worker       DCHECK(first.Equals(locations->Out()));
3976*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3977*795d594fSAndroid Build Coastguard Worker         __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3978*795d594fSAndroid Build Coastguard Worker       } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3979*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
3980*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
3981*795d594fSAndroid Build Coastguard Worker         __ mulss(first.AsFpuRegister<XmmRegister>(),
3982*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralFloatAddress(
3983*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsFloatConstant()->GetValue(),
3984*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
3985*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3986*795d594fSAndroid Build Coastguard Worker       } else {
3987*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsStackSlot());
3988*795d594fSAndroid Build Coastguard Worker         __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3989*795d594fSAndroid Build Coastguard Worker       }
3990*795d594fSAndroid Build Coastguard Worker       break;
3991*795d594fSAndroid Build Coastguard Worker     }
3992*795d594fSAndroid Build Coastguard Worker 
3993*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
3994*795d594fSAndroid Build Coastguard Worker       DCHECK(first.Equals(locations->Out()));
3995*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
3996*795d594fSAndroid Build Coastguard Worker         __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3997*795d594fSAndroid Build Coastguard Worker       } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3998*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
3999*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
4000*795d594fSAndroid Build Coastguard Worker         __ mulsd(first.AsFpuRegister<XmmRegister>(),
4001*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralDoubleAddress(
4002*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsDoubleConstant()->GetValue(),
4003*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
4004*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
4005*795d594fSAndroid Build Coastguard Worker       } else {
4006*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsDoubleStackSlot());
4007*795d594fSAndroid Build Coastguard Worker         __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
4008*795d594fSAndroid Build Coastguard Worker       }
4009*795d594fSAndroid Build Coastguard Worker       break;
4010*795d594fSAndroid Build Coastguard Worker     }
4011*795d594fSAndroid Build Coastguard Worker 
4012*795d594fSAndroid Build Coastguard Worker     default:
4013*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
4014*795d594fSAndroid Build Coastguard Worker   }
4015*795d594fSAndroid Build Coastguard Worker }
4016*795d594fSAndroid Build Coastguard Worker 
PushOntoFPStack(Location source,uint32_t temp_offset,uint32_t stack_adjustment,bool is_fp,bool is_wide)4017*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
4018*795d594fSAndroid Build Coastguard Worker                                                   uint32_t temp_offset,
4019*795d594fSAndroid Build Coastguard Worker                                                   uint32_t stack_adjustment,
4020*795d594fSAndroid Build Coastguard Worker                                                   bool is_fp,
4021*795d594fSAndroid Build Coastguard Worker                                                   bool is_wide) {
4022*795d594fSAndroid Build Coastguard Worker   if (source.IsStackSlot()) {
4023*795d594fSAndroid Build Coastguard Worker     DCHECK(!is_wide);
4024*795d594fSAndroid Build Coastguard Worker     if (is_fp) {
4025*795d594fSAndroid Build Coastguard Worker       __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
4026*795d594fSAndroid Build Coastguard Worker     } else {
4027*795d594fSAndroid Build Coastguard Worker       __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
4028*795d594fSAndroid Build Coastguard Worker     }
4029*795d594fSAndroid Build Coastguard Worker   } else if (source.IsDoubleStackSlot()) {
4030*795d594fSAndroid Build Coastguard Worker     DCHECK(is_wide);
4031*795d594fSAndroid Build Coastguard Worker     if (is_fp) {
4032*795d594fSAndroid Build Coastguard Worker       __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
4033*795d594fSAndroid Build Coastguard Worker     } else {
4034*795d594fSAndroid Build Coastguard Worker       __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
4035*795d594fSAndroid Build Coastguard Worker     }
4036*795d594fSAndroid Build Coastguard Worker   } else {
4037*795d594fSAndroid Build Coastguard Worker     // Write the value to the temporary location on the stack and load to FP stack.
4038*795d594fSAndroid Build Coastguard Worker     if (!is_wide) {
4039*795d594fSAndroid Build Coastguard Worker       Location stack_temp = Location::StackSlot(temp_offset);
4040*795d594fSAndroid Build Coastguard Worker       codegen_->Move32(stack_temp, source);
4041*795d594fSAndroid Build Coastguard Worker       if (is_fp) {
4042*795d594fSAndroid Build Coastguard Worker         __ flds(Address(ESP, temp_offset));
4043*795d594fSAndroid Build Coastguard Worker       } else {
4044*795d594fSAndroid Build Coastguard Worker         __ filds(Address(ESP, temp_offset));
4045*795d594fSAndroid Build Coastguard Worker       }
4046*795d594fSAndroid Build Coastguard Worker     } else {
4047*795d594fSAndroid Build Coastguard Worker       Location stack_temp = Location::DoubleStackSlot(temp_offset);
4048*795d594fSAndroid Build Coastguard Worker       codegen_->Move64(stack_temp, source);
4049*795d594fSAndroid Build Coastguard Worker       if (is_fp) {
4050*795d594fSAndroid Build Coastguard Worker         __ fldl(Address(ESP, temp_offset));
4051*795d594fSAndroid Build Coastguard Worker       } else {
4052*795d594fSAndroid Build Coastguard Worker         __ fildl(Address(ESP, temp_offset));
4053*795d594fSAndroid Build Coastguard Worker       }
4054*795d594fSAndroid Build Coastguard Worker     }
4055*795d594fSAndroid Build Coastguard Worker   }
4056*795d594fSAndroid Build Coastguard Worker }
4057*795d594fSAndroid Build Coastguard Worker 
GenerateRemFP(HRem * rem)4058*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
4059*795d594fSAndroid Build Coastguard Worker   DataType::Type type = rem->GetResultType();
4060*795d594fSAndroid Build Coastguard Worker   bool is_float = type == DataType::Type::kFloat32;
4061*795d594fSAndroid Build Coastguard Worker   size_t elem_size = DataType::Size(type);
4062*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = rem->GetLocations();
4063*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
4064*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
4065*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
4066*795d594fSAndroid Build Coastguard Worker 
4067*795d594fSAndroid Build Coastguard Worker   // Create stack space for 2 elements.
4068*795d594fSAndroid Build Coastguard Worker   // TODO: enhance register allocator to ask for stack temporaries.
4069*795d594fSAndroid Build Coastguard Worker   codegen_->IncreaseFrame(2 * elem_size);
4070*795d594fSAndroid Build Coastguard Worker 
4071*795d594fSAndroid Build Coastguard Worker   // Load the values to the FP stack in reverse order, using temporaries if needed.
4072*795d594fSAndroid Build Coastguard Worker   const bool is_wide = !is_float;
4073*795d594fSAndroid Build Coastguard Worker   PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp= */ true, is_wide);
4074*795d594fSAndroid Build Coastguard Worker   PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp= */ true, is_wide);
4075*795d594fSAndroid Build Coastguard Worker 
4076*795d594fSAndroid Build Coastguard Worker   // Loop doing FPREM until we stabilize.
4077*795d594fSAndroid Build Coastguard Worker   NearLabel retry;
4078*795d594fSAndroid Build Coastguard Worker   __ Bind(&retry);
4079*795d594fSAndroid Build Coastguard Worker   __ fprem();
4080*795d594fSAndroid Build Coastguard Worker 
4081*795d594fSAndroid Build Coastguard Worker   // Move FP status to AX.
4082*795d594fSAndroid Build Coastguard Worker   __ fstsw();
4083*795d594fSAndroid Build Coastguard Worker 
4084*795d594fSAndroid Build Coastguard Worker   // And see if the argument reduction is complete. This is signaled by the
4085*795d594fSAndroid Build Coastguard Worker   // C2 FPU flag bit set to 0.
4086*795d594fSAndroid Build Coastguard Worker   __ andl(EAX, Immediate(kC2ConditionMask));
4087*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &retry);
4088*795d594fSAndroid Build Coastguard Worker 
4089*795d594fSAndroid Build Coastguard Worker   // We have settled on the final value. Retrieve it into an XMM register.
4090*795d594fSAndroid Build Coastguard Worker   // Store FP top of stack to real stack.
4091*795d594fSAndroid Build Coastguard Worker   if (is_float) {
4092*795d594fSAndroid Build Coastguard Worker     __ fsts(Address(ESP, 0));
4093*795d594fSAndroid Build Coastguard Worker   } else {
4094*795d594fSAndroid Build Coastguard Worker     __ fstl(Address(ESP, 0));
4095*795d594fSAndroid Build Coastguard Worker   }
4096*795d594fSAndroid Build Coastguard Worker 
4097*795d594fSAndroid Build Coastguard Worker   // Pop the 2 items from the FP stack.
4098*795d594fSAndroid Build Coastguard Worker   __ fucompp();
4099*795d594fSAndroid Build Coastguard Worker 
4100*795d594fSAndroid Build Coastguard Worker   // Load the value from the stack into an XMM register.
4101*795d594fSAndroid Build Coastguard Worker   DCHECK(out.IsFpuRegister()) << out;
4102*795d594fSAndroid Build Coastguard Worker   if (is_float) {
4103*795d594fSAndroid Build Coastguard Worker     __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
4104*795d594fSAndroid Build Coastguard Worker   } else {
4105*795d594fSAndroid Build Coastguard Worker     __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
4106*795d594fSAndroid Build Coastguard Worker   }
4107*795d594fSAndroid Build Coastguard Worker 
4108*795d594fSAndroid Build Coastguard Worker   // And remove the temporary stack space we allocated.
4109*795d594fSAndroid Build Coastguard Worker   codegen_->DecreaseFrame(2 * elem_size);
4110*795d594fSAndroid Build Coastguard Worker }
4111*795d594fSAndroid Build Coastguard Worker 
4112*795d594fSAndroid Build Coastguard Worker 
DivRemOneOrMinusOne(HBinaryOperation * instruction)4113*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4114*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsDiv() || instruction->IsRem());
4115*795d594fSAndroid Build Coastguard Worker 
4116*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4117*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->InAt(1).IsConstant());
4118*795d594fSAndroid Build Coastguard Worker   DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
4119*795d594fSAndroid Build Coastguard Worker 
4120*795d594fSAndroid Build Coastguard Worker   Register out_register = locations->Out().AsRegister<Register>();
4121*795d594fSAndroid Build Coastguard Worker   Register input_register = locations->InAt(0).AsRegister<Register>();
4122*795d594fSAndroid Build Coastguard Worker   int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
4123*795d594fSAndroid Build Coastguard Worker 
4124*795d594fSAndroid Build Coastguard Worker   DCHECK(imm == 1 || imm == -1);
4125*795d594fSAndroid Build Coastguard Worker 
4126*795d594fSAndroid Build Coastguard Worker   if (instruction->IsRem()) {
4127*795d594fSAndroid Build Coastguard Worker     __ xorl(out_register, out_register);
4128*795d594fSAndroid Build Coastguard Worker   } else {
4129*795d594fSAndroid Build Coastguard Worker     __ movl(out_register, input_register);
4130*795d594fSAndroid Build Coastguard Worker     if (imm == -1) {
4131*795d594fSAndroid Build Coastguard Worker       __ negl(out_register);
4132*795d594fSAndroid Build Coastguard Worker     }
4133*795d594fSAndroid Build Coastguard Worker   }
4134*795d594fSAndroid Build Coastguard Worker }
4135*795d594fSAndroid Build Coastguard Worker 
RemByPowerOfTwo(HRem * instruction)4136*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::RemByPowerOfTwo(HRem* instruction) {
4137*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4138*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
4139*795d594fSAndroid Build Coastguard Worker 
4140*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
4141*795d594fSAndroid Build Coastguard Worker   Register numerator = locations->InAt(0).AsRegister<Register>();
4142*795d594fSAndroid Build Coastguard Worker 
4143*795d594fSAndroid Build Coastguard Worker   int32_t imm = Int64FromConstant(second.GetConstant());
4144*795d594fSAndroid Build Coastguard Worker   DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
4145*795d594fSAndroid Build Coastguard Worker   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
4146*795d594fSAndroid Build Coastguard Worker 
4147*795d594fSAndroid Build Coastguard Worker   Register tmp = locations->GetTemp(0).AsRegister<Register>();
4148*795d594fSAndroid Build Coastguard Worker   NearLabel done;
4149*795d594fSAndroid Build Coastguard Worker   __ movl(out, numerator);
4150*795d594fSAndroid Build Coastguard Worker   __ andl(out, Immediate(abs_imm-1));
4151*795d594fSAndroid Build Coastguard Worker   __ j(Condition::kZero, &done);
4152*795d594fSAndroid Build Coastguard Worker   __ leal(tmp, Address(out, static_cast<int32_t>(~(abs_imm-1))));
4153*795d594fSAndroid Build Coastguard Worker   __ testl(numerator, numerator);
4154*795d594fSAndroid Build Coastguard Worker   __ cmovl(Condition::kLess, out, tmp);
4155*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
4156*795d594fSAndroid Build Coastguard Worker }
4157*795d594fSAndroid Build Coastguard Worker 
DivByPowerOfTwo(HDiv * instruction)4158*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
4159*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4160*795d594fSAndroid Build Coastguard Worker 
4161*795d594fSAndroid Build Coastguard Worker   Register out_register = locations->Out().AsRegister<Register>();
4162*795d594fSAndroid Build Coastguard Worker   Register input_register = locations->InAt(0).AsRegister<Register>();
4163*795d594fSAndroid Build Coastguard Worker   int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
4164*795d594fSAndroid Build Coastguard Worker   DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
4165*795d594fSAndroid Build Coastguard Worker   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
4166*795d594fSAndroid Build Coastguard Worker 
4167*795d594fSAndroid Build Coastguard Worker   Register num = locations->GetTemp(0).AsRegister<Register>();
4168*795d594fSAndroid Build Coastguard Worker 
4169*795d594fSAndroid Build Coastguard Worker   __ leal(num, Address(input_register, abs_imm - 1));
4170*795d594fSAndroid Build Coastguard Worker   __ testl(input_register, input_register);
4171*795d594fSAndroid Build Coastguard Worker   __ cmovl(kGreaterEqual, num, input_register);
4172*795d594fSAndroid Build Coastguard Worker   int shift = CTZ(imm);
4173*795d594fSAndroid Build Coastguard Worker   __ sarl(num, Immediate(shift));
4174*795d594fSAndroid Build Coastguard Worker 
4175*795d594fSAndroid Build Coastguard Worker   if (imm < 0) {
4176*795d594fSAndroid Build Coastguard Worker     __ negl(num);
4177*795d594fSAndroid Build Coastguard Worker   }
4178*795d594fSAndroid Build Coastguard Worker 
4179*795d594fSAndroid Build Coastguard Worker   __ movl(out_register, num);
4180*795d594fSAndroid Build Coastguard Worker }
4181*795d594fSAndroid Build Coastguard Worker 
GenerateDivRemWithAnyConstant(HBinaryOperation * instruction)4182*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4183*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsDiv() || instruction->IsRem());
4184*795d594fSAndroid Build Coastguard Worker 
4185*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4186*795d594fSAndroid Build Coastguard Worker   int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
4187*795d594fSAndroid Build Coastguard Worker 
4188*795d594fSAndroid Build Coastguard Worker   Register eax = locations->InAt(0).AsRegister<Register>();
4189*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
4190*795d594fSAndroid Build Coastguard Worker   Register num;
4191*795d594fSAndroid Build Coastguard Worker   Register edx;
4192*795d594fSAndroid Build Coastguard Worker 
4193*795d594fSAndroid Build Coastguard Worker   if (instruction->IsDiv()) {
4194*795d594fSAndroid Build Coastguard Worker     edx = locations->GetTemp(0).AsRegister<Register>();
4195*795d594fSAndroid Build Coastguard Worker     num = locations->GetTemp(1).AsRegister<Register>();
4196*795d594fSAndroid Build Coastguard Worker   } else {
4197*795d594fSAndroid Build Coastguard Worker     edx = locations->Out().AsRegister<Register>();
4198*795d594fSAndroid Build Coastguard Worker     num = locations->GetTemp(0).AsRegister<Register>();
4199*795d594fSAndroid Build Coastguard Worker   }
4200*795d594fSAndroid Build Coastguard Worker 
4201*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EAX, eax);
4202*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(EDX, edx);
4203*795d594fSAndroid Build Coastguard Worker   if (instruction->IsDiv()) {
4204*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(EAX, out);
4205*795d594fSAndroid Build Coastguard Worker   } else {
4206*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(EDX, out);
4207*795d594fSAndroid Build Coastguard Worker   }
4208*795d594fSAndroid Build Coastguard Worker 
4209*795d594fSAndroid Build Coastguard Worker   int64_t magic;
4210*795d594fSAndroid Build Coastguard Worker   int shift;
4211*795d594fSAndroid Build Coastguard Worker   CalculateMagicAndShiftForDivRem(imm, /* is_long= */ false, &magic, &shift);
4212*795d594fSAndroid Build Coastguard Worker 
4213*795d594fSAndroid Build Coastguard Worker   // Save the numerator.
4214*795d594fSAndroid Build Coastguard Worker   __ movl(num, eax);
4215*795d594fSAndroid Build Coastguard Worker 
4216*795d594fSAndroid Build Coastguard Worker   // EAX = magic
4217*795d594fSAndroid Build Coastguard Worker   __ movl(eax, Immediate(magic));
4218*795d594fSAndroid Build Coastguard Worker 
4219*795d594fSAndroid Build Coastguard Worker   // EDX:EAX = magic * numerator
4220*795d594fSAndroid Build Coastguard Worker   __ imull(num);
4221*795d594fSAndroid Build Coastguard Worker 
4222*795d594fSAndroid Build Coastguard Worker   if (imm > 0 && magic < 0) {
4223*795d594fSAndroid Build Coastguard Worker     // EDX += num
4224*795d594fSAndroid Build Coastguard Worker     __ addl(edx, num);
4225*795d594fSAndroid Build Coastguard Worker   } else if (imm < 0 && magic > 0) {
4226*795d594fSAndroid Build Coastguard Worker     __ subl(edx, num);
4227*795d594fSAndroid Build Coastguard Worker   }
4228*795d594fSAndroid Build Coastguard Worker 
4229*795d594fSAndroid Build Coastguard Worker   // Shift if needed.
4230*795d594fSAndroid Build Coastguard Worker   if (shift != 0) {
4231*795d594fSAndroid Build Coastguard Worker     __ sarl(edx, Immediate(shift));
4232*795d594fSAndroid Build Coastguard Worker   }
4233*795d594fSAndroid Build Coastguard Worker 
4234*795d594fSAndroid Build Coastguard Worker   // EDX += 1 if EDX < 0
4235*795d594fSAndroid Build Coastguard Worker   __ movl(eax, edx);
4236*795d594fSAndroid Build Coastguard Worker   __ shrl(edx, Immediate(31));
4237*795d594fSAndroid Build Coastguard Worker   __ addl(edx, eax);
4238*795d594fSAndroid Build Coastguard Worker 
4239*795d594fSAndroid Build Coastguard Worker   if (instruction->IsRem()) {
4240*795d594fSAndroid Build Coastguard Worker     __ movl(eax, num);
4241*795d594fSAndroid Build Coastguard Worker     __ imull(edx, Immediate(imm));
4242*795d594fSAndroid Build Coastguard Worker     __ subl(eax, edx);
4243*795d594fSAndroid Build Coastguard Worker     __ movl(edx, eax);
4244*795d594fSAndroid Build Coastguard Worker   } else {
4245*795d594fSAndroid Build Coastguard Worker     __ movl(eax, edx);
4246*795d594fSAndroid Build Coastguard Worker   }
4247*795d594fSAndroid Build Coastguard Worker }
4248*795d594fSAndroid Build Coastguard Worker 
GenerateDivRemIntegral(HBinaryOperation * instruction)4249*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
4250*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsDiv() || instruction->IsRem());
4251*795d594fSAndroid Build Coastguard Worker 
4252*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4253*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
4254*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
4255*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
4256*795d594fSAndroid Build Coastguard Worker   bool is_div = instruction->IsDiv();
4257*795d594fSAndroid Build Coastguard Worker 
4258*795d594fSAndroid Build Coastguard Worker   switch (instruction->GetResultType()) {
4259*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4260*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(EAX, first.AsRegister<Register>());
4261*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
4262*795d594fSAndroid Build Coastguard Worker 
4263*795d594fSAndroid Build Coastguard Worker       if (second.IsConstant()) {
4264*795d594fSAndroid Build Coastguard Worker         int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4265*795d594fSAndroid Build Coastguard Worker 
4266*795d594fSAndroid Build Coastguard Worker         if (imm == 0) {
4267*795d594fSAndroid Build Coastguard Worker           // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
4268*795d594fSAndroid Build Coastguard Worker         } else if (imm == 1 || imm == -1) {
4269*795d594fSAndroid Build Coastguard Worker           DivRemOneOrMinusOne(instruction);
4270*795d594fSAndroid Build Coastguard Worker         } else if (IsPowerOfTwo(AbsOrMin(imm))) {
4271*795d594fSAndroid Build Coastguard Worker           if (is_div) {
4272*795d594fSAndroid Build Coastguard Worker             DivByPowerOfTwo(instruction->AsDiv());
4273*795d594fSAndroid Build Coastguard Worker           } else {
4274*795d594fSAndroid Build Coastguard Worker             RemByPowerOfTwo(instruction->AsRem());
4275*795d594fSAndroid Build Coastguard Worker           }
4276*795d594fSAndroid Build Coastguard Worker         } else {
4277*795d594fSAndroid Build Coastguard Worker           DCHECK(imm <= -2 || imm >= 2);
4278*795d594fSAndroid Build Coastguard Worker           GenerateDivRemWithAnyConstant(instruction);
4279*795d594fSAndroid Build Coastguard Worker         }
4280*795d594fSAndroid Build Coastguard Worker       } else {
4281*795d594fSAndroid Build Coastguard Worker         SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) DivRemMinusOneSlowPathX86(
4282*795d594fSAndroid Build Coastguard Worker             instruction, out.AsRegister<Register>(), is_div);
4283*795d594fSAndroid Build Coastguard Worker         codegen_->AddSlowPath(slow_path);
4284*795d594fSAndroid Build Coastguard Worker 
4285*795d594fSAndroid Build Coastguard Worker         Register second_reg = second.AsRegister<Register>();
4286*795d594fSAndroid Build Coastguard Worker         // 0x80000000/-1 triggers an arithmetic exception!
4287*795d594fSAndroid Build Coastguard Worker         // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
4288*795d594fSAndroid Build Coastguard Worker         // it's safe to just use negl instead of more complex comparisons.
4289*795d594fSAndroid Build Coastguard Worker 
4290*795d594fSAndroid Build Coastguard Worker         __ cmpl(second_reg, Immediate(-1));
4291*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, slow_path->GetEntryLabel());
4292*795d594fSAndroid Build Coastguard Worker 
4293*795d594fSAndroid Build Coastguard Worker         // edx:eax <- sign-extended of eax
4294*795d594fSAndroid Build Coastguard Worker         __ cdq();
4295*795d594fSAndroid Build Coastguard Worker         // eax = quotient, edx = remainder
4296*795d594fSAndroid Build Coastguard Worker         __ idivl(second_reg);
4297*795d594fSAndroid Build Coastguard Worker         __ Bind(slow_path->GetExitLabel());
4298*795d594fSAndroid Build Coastguard Worker       }
4299*795d594fSAndroid Build Coastguard Worker       break;
4300*795d594fSAndroid Build Coastguard Worker     }
4301*795d594fSAndroid Build Coastguard Worker 
4302*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4303*795d594fSAndroid Build Coastguard Worker       InvokeRuntimeCallingConvention calling_convention;
4304*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4305*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4306*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4307*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4308*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
4309*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
4310*795d594fSAndroid Build Coastguard Worker 
4311*795d594fSAndroid Build Coastguard Worker       if (is_div) {
4312*795d594fSAndroid Build Coastguard Worker         codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
4313*795d594fSAndroid Build Coastguard Worker         CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
4314*795d594fSAndroid Build Coastguard Worker       } else {
4315*795d594fSAndroid Build Coastguard Worker         codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
4316*795d594fSAndroid Build Coastguard Worker         CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
4317*795d594fSAndroid Build Coastguard Worker       }
4318*795d594fSAndroid Build Coastguard Worker       break;
4319*795d594fSAndroid Build Coastguard Worker     }
4320*795d594fSAndroid Build Coastguard Worker 
4321*795d594fSAndroid Build Coastguard Worker     default:
4322*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
4323*795d594fSAndroid Build Coastguard Worker   }
4324*795d594fSAndroid Build Coastguard Worker }
4325*795d594fSAndroid Build Coastguard Worker 
VisitDiv(HDiv * div)4326*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitDiv(HDiv* div) {
4327*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = (div->GetResultType() == DataType::Type::kInt64)
4328*795d594fSAndroid Build Coastguard Worker       ? LocationSummary::kCallOnMainOnly
4329*795d594fSAndroid Build Coastguard Worker       : LocationSummary::kNoCall;
4330*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(div, call_kind);
4331*795d594fSAndroid Build Coastguard Worker 
4332*795d594fSAndroid Build Coastguard Worker   switch (div->GetResultType()) {
4333*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4334*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterLocation(EAX));
4335*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
4336*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4337*795d594fSAndroid Build Coastguard Worker       // Intel uses edx:eax as the dividend.
4338*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EDX));
4339*795d594fSAndroid Build Coastguard Worker       // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
4340*795d594fSAndroid Build Coastguard Worker       // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
4341*795d594fSAndroid Build Coastguard Worker       // output and request another temp.
4342*795d594fSAndroid Build Coastguard Worker       if (div->InputAt(1)->IsIntConstant()) {
4343*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresRegister());
4344*795d594fSAndroid Build Coastguard Worker       }
4345*795d594fSAndroid Build Coastguard Worker       break;
4346*795d594fSAndroid Build Coastguard Worker     }
4347*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4348*795d594fSAndroid Build Coastguard Worker       InvokeRuntimeCallingConvention calling_convention;
4349*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterPairLocation(
4350*795d594fSAndroid Build Coastguard Worker           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4351*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RegisterPairLocation(
4352*795d594fSAndroid Build Coastguard Worker           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4353*795d594fSAndroid Build Coastguard Worker       // Runtime helper puts the result in EAX, EDX.
4354*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
4355*795d594fSAndroid Build Coastguard Worker       break;
4356*795d594fSAndroid Build Coastguard Worker     }
4357*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4358*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
4359*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
4360*795d594fSAndroid Build Coastguard Worker       if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4361*795d594fSAndroid Build Coastguard Worker         DCHECK(div->InputAt(1)->IsEmittedAtUseSite());
4362*795d594fSAndroid Build Coastguard Worker       } else if (div->InputAt(1)->IsConstant()) {
4363*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
4364*795d594fSAndroid Build Coastguard Worker       } else {
4365*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
4366*795d594fSAndroid Build Coastguard Worker       }
4367*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4368*795d594fSAndroid Build Coastguard Worker       break;
4369*795d594fSAndroid Build Coastguard Worker     }
4370*795d594fSAndroid Build Coastguard Worker 
4371*795d594fSAndroid Build Coastguard Worker     default:
4372*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4373*795d594fSAndroid Build Coastguard Worker   }
4374*795d594fSAndroid Build Coastguard Worker }
4375*795d594fSAndroid Build Coastguard Worker 
VisitDiv(HDiv * div)4376*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
4377*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = div->GetLocations();
4378*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
4379*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
4380*795d594fSAndroid Build Coastguard Worker 
4381*795d594fSAndroid Build Coastguard Worker   switch (div->GetResultType()) {
4382*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4383*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4384*795d594fSAndroid Build Coastguard Worker       GenerateDivRemIntegral(div);
4385*795d594fSAndroid Build Coastguard Worker       break;
4386*795d594fSAndroid Build Coastguard Worker     }
4387*795d594fSAndroid Build Coastguard Worker 
4388*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
4389*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
4390*795d594fSAndroid Build Coastguard Worker         __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
4391*795d594fSAndroid Build Coastguard Worker       } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4392*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
4393*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
4394*795d594fSAndroid Build Coastguard Worker         __ divss(first.AsFpuRegister<XmmRegister>(),
4395*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralFloatAddress(
4396*795d594fSAndroid Build Coastguard Worker                    const_area->GetConstant()->AsFloatConstant()->GetValue(),
4397*795d594fSAndroid Build Coastguard Worker                    const_area->GetBaseMethodAddress(),
4398*795d594fSAndroid Build Coastguard Worker                    const_area->GetLocations()->InAt(0).AsRegister<Register>()));
4399*795d594fSAndroid Build Coastguard Worker       } else {
4400*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsStackSlot());
4401*795d594fSAndroid Build Coastguard Worker         __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
4402*795d594fSAndroid Build Coastguard Worker       }
4403*795d594fSAndroid Build Coastguard Worker       break;
4404*795d594fSAndroid Build Coastguard Worker     }
4405*795d594fSAndroid Build Coastguard Worker 
4406*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
4407*795d594fSAndroid Build Coastguard Worker       if (second.IsFpuRegister()) {
4408*795d594fSAndroid Build Coastguard Worker         __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
4409*795d594fSAndroid Build Coastguard Worker       } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4410*795d594fSAndroid Build Coastguard Worker         HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
4411*795d594fSAndroid Build Coastguard Worker         DCHECK(const_area->IsEmittedAtUseSite());
4412*795d594fSAndroid Build Coastguard Worker         __ divsd(first.AsFpuRegister<XmmRegister>(),
4413*795d594fSAndroid Build Coastguard Worker                  codegen_->LiteralDoubleAddress(
4414*795d594fSAndroid Build Coastguard Worker                      const_area->GetConstant()->AsDoubleConstant()->GetValue(),
4415*795d594fSAndroid Build Coastguard Worker                      const_area->GetBaseMethodAddress(),
4416*795d594fSAndroid Build Coastguard Worker                      const_area->GetLocations()->InAt(0).AsRegister<Register>()));
4417*795d594fSAndroid Build Coastguard Worker       } else {
4418*795d594fSAndroid Build Coastguard Worker         DCHECK(second.IsDoubleStackSlot());
4419*795d594fSAndroid Build Coastguard Worker         __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
4420*795d594fSAndroid Build Coastguard Worker       }
4421*795d594fSAndroid Build Coastguard Worker       break;
4422*795d594fSAndroid Build Coastguard Worker     }
4423*795d594fSAndroid Build Coastguard Worker 
4424*795d594fSAndroid Build Coastguard Worker     default:
4425*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4426*795d594fSAndroid Build Coastguard Worker   }
4427*795d594fSAndroid Build Coastguard Worker }
4428*795d594fSAndroid Build Coastguard Worker 
VisitRem(HRem * rem)4429*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitRem(HRem* rem) {
4430*795d594fSAndroid Build Coastguard Worker   DataType::Type type = rem->GetResultType();
4431*795d594fSAndroid Build Coastguard Worker 
4432*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = (rem->GetResultType() == DataType::Type::kInt64)
4433*795d594fSAndroid Build Coastguard Worker       ? LocationSummary::kCallOnMainOnly
4434*795d594fSAndroid Build Coastguard Worker       : LocationSummary::kNoCall;
4435*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind);
4436*795d594fSAndroid Build Coastguard Worker 
4437*795d594fSAndroid Build Coastguard Worker   switch (type) {
4438*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4439*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterLocation(EAX));
4440*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
4441*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterLocation(EDX));
4442*795d594fSAndroid Build Coastguard Worker       // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
4443*795d594fSAndroid Build Coastguard Worker       // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
4444*795d594fSAndroid Build Coastguard Worker       // output and request another temp.
4445*795d594fSAndroid Build Coastguard Worker       if (rem->InputAt(1)->IsIntConstant()) {
4446*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresRegister());
4447*795d594fSAndroid Build Coastguard Worker       }
4448*795d594fSAndroid Build Coastguard Worker       break;
4449*795d594fSAndroid Build Coastguard Worker     }
4450*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4451*795d594fSAndroid Build Coastguard Worker       InvokeRuntimeCallingConvention calling_convention;
4452*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterPairLocation(
4453*795d594fSAndroid Build Coastguard Worker           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4454*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RegisterPairLocation(
4455*795d594fSAndroid Build Coastguard Worker           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4456*795d594fSAndroid Build Coastguard Worker       // Runtime helper puts the result in EAX, EDX.
4457*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
4458*795d594fSAndroid Build Coastguard Worker       break;
4459*795d594fSAndroid Build Coastguard Worker     }
4460*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
4461*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
4462*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::Any());
4463*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
4464*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
4465*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EAX));
4466*795d594fSAndroid Build Coastguard Worker       break;
4467*795d594fSAndroid Build Coastguard Worker     }
4468*795d594fSAndroid Build Coastguard Worker 
4469*795d594fSAndroid Build Coastguard Worker     default:
4470*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected rem type " << type;
4471*795d594fSAndroid Build Coastguard Worker   }
4472*795d594fSAndroid Build Coastguard Worker }
4473*795d594fSAndroid Build Coastguard Worker 
VisitRem(HRem * rem)4474*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
4475*795d594fSAndroid Build Coastguard Worker   DataType::Type type = rem->GetResultType();
4476*795d594fSAndroid Build Coastguard Worker   switch (type) {
4477*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4478*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4479*795d594fSAndroid Build Coastguard Worker       GenerateDivRemIntegral(rem);
4480*795d594fSAndroid Build Coastguard Worker       break;
4481*795d594fSAndroid Build Coastguard Worker     }
4482*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4483*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
4484*795d594fSAndroid Build Coastguard Worker       GenerateRemFP(rem);
4485*795d594fSAndroid Build Coastguard Worker       break;
4486*795d594fSAndroid Build Coastguard Worker     }
4487*795d594fSAndroid Build Coastguard Worker     default:
4488*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected rem type " << type;
4489*795d594fSAndroid Build Coastguard Worker   }
4490*795d594fSAndroid Build Coastguard Worker }
4491*795d594fSAndroid Build Coastguard Worker 
CreateMinMaxLocations(ArenaAllocator * allocator,HBinaryOperation * minmax)4492*795d594fSAndroid Build Coastguard Worker static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) {
4493*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(minmax);
4494*795d594fSAndroid Build Coastguard Worker   switch (minmax->GetResultType()) {
4495*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4496*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
4497*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RequiresRegister());
4498*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4499*795d594fSAndroid Build Coastguard Worker       break;
4500*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
4501*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
4502*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RequiresRegister());
4503*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4504*795d594fSAndroid Build Coastguard Worker       // Register to use to perform a long subtract to set cc.
4505*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4506*795d594fSAndroid Build Coastguard Worker       break;
4507*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4508*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
4509*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RequiresFpuRegister());
4510*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4511*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4512*795d594fSAndroid Build Coastguard Worker       break;
4513*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
4514*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
4515*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RequiresFpuRegister());
4516*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4517*795d594fSAndroid Build Coastguard Worker       break;
4518*795d594fSAndroid Build Coastguard Worker     default:
4519*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType();
4520*795d594fSAndroid Build Coastguard Worker   }
4521*795d594fSAndroid Build Coastguard Worker }
4522*795d594fSAndroid Build Coastguard Worker 
GenerateMinMaxInt(LocationSummary * locations,bool is_min,DataType::Type type)4523*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateMinMaxInt(LocationSummary* locations,
4524*795d594fSAndroid Build Coastguard Worker                                                     bool is_min,
4525*795d594fSAndroid Build Coastguard Worker                                                     DataType::Type type) {
4526*795d594fSAndroid Build Coastguard Worker   Location op1_loc = locations->InAt(0);
4527*795d594fSAndroid Build Coastguard Worker   Location op2_loc = locations->InAt(1);
4528*795d594fSAndroid Build Coastguard Worker 
4529*795d594fSAndroid Build Coastguard Worker   // Shortcut for same input locations.
4530*795d594fSAndroid Build Coastguard Worker   if (op1_loc.Equals(op2_loc)) {
4531*795d594fSAndroid Build Coastguard Worker     // Can return immediately, as op1_loc == out_loc.
4532*795d594fSAndroid Build Coastguard Worker     // Note: if we ever support separate registers, e.g., output into memory, we need to check for
4533*795d594fSAndroid Build Coastguard Worker     //       a copy here.
4534*795d594fSAndroid Build Coastguard Worker     DCHECK(locations->Out().Equals(op1_loc));
4535*795d594fSAndroid Build Coastguard Worker     return;
4536*795d594fSAndroid Build Coastguard Worker   }
4537*795d594fSAndroid Build Coastguard Worker 
4538*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
4539*795d594fSAndroid Build Coastguard Worker     // Need to perform a subtract to get the sign right.
4540*795d594fSAndroid Build Coastguard Worker     // op1 is already in the same location as the output.
4541*795d594fSAndroid Build Coastguard Worker     Location output = locations->Out();
4542*795d594fSAndroid Build Coastguard Worker     Register output_lo = output.AsRegisterPairLow<Register>();
4543*795d594fSAndroid Build Coastguard Worker     Register output_hi = output.AsRegisterPairHigh<Register>();
4544*795d594fSAndroid Build Coastguard Worker 
4545*795d594fSAndroid Build Coastguard Worker     Register op2_lo = op2_loc.AsRegisterPairLow<Register>();
4546*795d594fSAndroid Build Coastguard Worker     Register op2_hi = op2_loc.AsRegisterPairHigh<Register>();
4547*795d594fSAndroid Build Coastguard Worker 
4548*795d594fSAndroid Build Coastguard Worker     // The comparison is performed by subtracting the second operand from
4549*795d594fSAndroid Build Coastguard Worker     // the first operand and then setting the status flags in the same
4550*795d594fSAndroid Build Coastguard Worker     // manner as the SUB instruction."
4551*795d594fSAndroid Build Coastguard Worker     __ cmpl(output_lo, op2_lo);
4552*795d594fSAndroid Build Coastguard Worker 
4553*795d594fSAndroid Build Coastguard Worker     // Now use a temp and the borrow to finish the subtraction of op2_hi.
4554*795d594fSAndroid Build Coastguard Worker     Register temp = locations->GetTemp(0).AsRegister<Register>();
4555*795d594fSAndroid Build Coastguard Worker     __ movl(temp, output_hi);
4556*795d594fSAndroid Build Coastguard Worker     __ sbbl(temp, op2_hi);
4557*795d594fSAndroid Build Coastguard Worker 
4558*795d594fSAndroid Build Coastguard Worker     // Now the condition code is correct.
4559*795d594fSAndroid Build Coastguard Worker     Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess;
4560*795d594fSAndroid Build Coastguard Worker     __ cmovl(cond, output_lo, op2_lo);
4561*795d594fSAndroid Build Coastguard Worker     __ cmovl(cond, output_hi, op2_hi);
4562*795d594fSAndroid Build Coastguard Worker   } else {
4563*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kInt32);
4564*795d594fSAndroid Build Coastguard Worker     Register out = locations->Out().AsRegister<Register>();
4565*795d594fSAndroid Build Coastguard Worker     Register op2 = op2_loc.AsRegister<Register>();
4566*795d594fSAndroid Build Coastguard Worker 
4567*795d594fSAndroid Build Coastguard Worker     //  (out := op1)
4568*795d594fSAndroid Build Coastguard Worker     //  out <=? op2
4569*795d594fSAndroid Build Coastguard Worker     //  if out is min jmp done
4570*795d594fSAndroid Build Coastguard Worker     //  out := op2
4571*795d594fSAndroid Build Coastguard Worker     // done:
4572*795d594fSAndroid Build Coastguard Worker 
4573*795d594fSAndroid Build Coastguard Worker     __ cmpl(out, op2);
4574*795d594fSAndroid Build Coastguard Worker     Condition cond = is_min ? Condition::kGreater : Condition::kLess;
4575*795d594fSAndroid Build Coastguard Worker     __ cmovl(cond, out, op2);
4576*795d594fSAndroid Build Coastguard Worker   }
4577*795d594fSAndroid Build Coastguard Worker }
4578*795d594fSAndroid Build Coastguard Worker 
GenerateMinMaxFP(LocationSummary * locations,bool is_min,DataType::Type type)4579*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateMinMaxFP(LocationSummary* locations,
4580*795d594fSAndroid Build Coastguard Worker                                                    bool is_min,
4581*795d594fSAndroid Build Coastguard Worker                                                    DataType::Type type) {
4582*795d594fSAndroid Build Coastguard Worker   Location op1_loc = locations->InAt(0);
4583*795d594fSAndroid Build Coastguard Worker   Location op2_loc = locations->InAt(1);
4584*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
4585*795d594fSAndroid Build Coastguard Worker   XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
4586*795d594fSAndroid Build Coastguard Worker 
4587*795d594fSAndroid Build Coastguard Worker   // Shortcut for same input locations.
4588*795d594fSAndroid Build Coastguard Worker   if (op1_loc.Equals(op2_loc)) {
4589*795d594fSAndroid Build Coastguard Worker     DCHECK(out_loc.Equals(op1_loc));
4590*795d594fSAndroid Build Coastguard Worker     return;
4591*795d594fSAndroid Build Coastguard Worker   }
4592*795d594fSAndroid Build Coastguard Worker 
4593*795d594fSAndroid Build Coastguard Worker   //  (out := op1)
4594*795d594fSAndroid Build Coastguard Worker   //  out <=? op2
4595*795d594fSAndroid Build Coastguard Worker   //  if Nan jmp Nan_label
4596*795d594fSAndroid Build Coastguard Worker   //  if out is min jmp done
4597*795d594fSAndroid Build Coastguard Worker   //  if op2 is min jmp op2_label
4598*795d594fSAndroid Build Coastguard Worker   //  handle -0/+0
4599*795d594fSAndroid Build Coastguard Worker   //  jmp done
4600*795d594fSAndroid Build Coastguard Worker   // Nan_label:
4601*795d594fSAndroid Build Coastguard Worker   //  out := NaN
4602*795d594fSAndroid Build Coastguard Worker   // op2_label:
4603*795d594fSAndroid Build Coastguard Worker   //  out := op2
4604*795d594fSAndroid Build Coastguard Worker   // done:
4605*795d594fSAndroid Build Coastguard Worker   //
4606*795d594fSAndroid Build Coastguard Worker   // This removes one jmp, but needs to copy one input (op1) to out.
4607*795d594fSAndroid Build Coastguard Worker   //
4608*795d594fSAndroid Build Coastguard Worker   // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
4609*795d594fSAndroid Build Coastguard Worker 
4610*795d594fSAndroid Build Coastguard Worker   XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
4611*795d594fSAndroid Build Coastguard Worker 
4612*795d594fSAndroid Build Coastguard Worker   NearLabel nan, done, op2_label;
4613*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kFloat64) {
4614*795d594fSAndroid Build Coastguard Worker     __ ucomisd(out, op2);
4615*795d594fSAndroid Build Coastguard Worker   } else {
4616*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kFloat32);
4617*795d594fSAndroid Build Coastguard Worker     __ ucomiss(out, op2);
4618*795d594fSAndroid Build Coastguard Worker   }
4619*795d594fSAndroid Build Coastguard Worker 
4620*795d594fSAndroid Build Coastguard Worker   __ j(Condition::kParityEven, &nan);
4621*795d594fSAndroid Build Coastguard Worker 
4622*795d594fSAndroid Build Coastguard Worker   __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
4623*795d594fSAndroid Build Coastguard Worker   __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
4624*795d594fSAndroid Build Coastguard Worker 
4625*795d594fSAndroid Build Coastguard Worker   // Handle 0.0/-0.0.
4626*795d594fSAndroid Build Coastguard Worker   if (is_min) {
4627*795d594fSAndroid Build Coastguard Worker     if (type == DataType::Type::kFloat64) {
4628*795d594fSAndroid Build Coastguard Worker       __ orpd(out, op2);
4629*795d594fSAndroid Build Coastguard Worker     } else {
4630*795d594fSAndroid Build Coastguard Worker       __ orps(out, op2);
4631*795d594fSAndroid Build Coastguard Worker     }
4632*795d594fSAndroid Build Coastguard Worker   } else {
4633*795d594fSAndroid Build Coastguard Worker     if (type == DataType::Type::kFloat64) {
4634*795d594fSAndroid Build Coastguard Worker       __ andpd(out, op2);
4635*795d594fSAndroid Build Coastguard Worker     } else {
4636*795d594fSAndroid Build Coastguard Worker       __ andps(out, op2);
4637*795d594fSAndroid Build Coastguard Worker     }
4638*795d594fSAndroid Build Coastguard Worker   }
4639*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
4640*795d594fSAndroid Build Coastguard Worker 
4641*795d594fSAndroid Build Coastguard Worker   // NaN handling.
4642*795d594fSAndroid Build Coastguard Worker   __ Bind(&nan);
4643*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kFloat64) {
4644*795d594fSAndroid Build Coastguard Worker     // TODO: Use a constant from the constant table (requires extra input).
4645*795d594fSAndroid Build Coastguard Worker     __ LoadLongConstant(out, kDoubleNaN);
4646*795d594fSAndroid Build Coastguard Worker   } else {
4647*795d594fSAndroid Build Coastguard Worker     Register constant = locations->GetTemp(0).AsRegister<Register>();
4648*795d594fSAndroid Build Coastguard Worker     __ movl(constant, Immediate(kFloatNaN));
4649*795d594fSAndroid Build Coastguard Worker     __ movd(out, constant);
4650*795d594fSAndroid Build Coastguard Worker   }
4651*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
4652*795d594fSAndroid Build Coastguard Worker 
4653*795d594fSAndroid Build Coastguard Worker   // out := op2;
4654*795d594fSAndroid Build Coastguard Worker   __ Bind(&op2_label);
4655*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kFloat64) {
4656*795d594fSAndroid Build Coastguard Worker     __ movsd(out, op2);
4657*795d594fSAndroid Build Coastguard Worker   } else {
4658*795d594fSAndroid Build Coastguard Worker     __ movss(out, op2);
4659*795d594fSAndroid Build Coastguard Worker   }
4660*795d594fSAndroid Build Coastguard Worker 
4661*795d594fSAndroid Build Coastguard Worker   // Done.
4662*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
4663*795d594fSAndroid Build Coastguard Worker }
4664*795d594fSAndroid Build Coastguard Worker 
GenerateMinMax(HBinaryOperation * minmax,bool is_min)4665*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateMinMax(HBinaryOperation* minmax, bool is_min) {
4666*795d594fSAndroid Build Coastguard Worker   DataType::Type type = minmax->GetResultType();
4667*795d594fSAndroid Build Coastguard Worker   switch (type) {
4668*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4669*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
4670*795d594fSAndroid Build Coastguard Worker       GenerateMinMaxInt(minmax->GetLocations(), is_min, type);
4671*795d594fSAndroid Build Coastguard Worker       break;
4672*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4673*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
4674*795d594fSAndroid Build Coastguard Worker       GenerateMinMaxFP(minmax->GetLocations(), is_min, type);
4675*795d594fSAndroid Build Coastguard Worker       break;
4676*795d594fSAndroid Build Coastguard Worker     default:
4677*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HMinMax " << type;
4678*795d594fSAndroid Build Coastguard Worker   }
4679*795d594fSAndroid Build Coastguard Worker }
4680*795d594fSAndroid Build Coastguard Worker 
VisitMin(HMin * min)4681*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMin(HMin* min) {
4682*795d594fSAndroid Build Coastguard Worker   CreateMinMaxLocations(GetGraph()->GetAllocator(), min);
4683*795d594fSAndroid Build Coastguard Worker }
4684*795d594fSAndroid Build Coastguard Worker 
VisitMin(HMin * min)4685*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMin(HMin* min) {
4686*795d594fSAndroid Build Coastguard Worker   GenerateMinMax(min, /*is_min*/ true);
4687*795d594fSAndroid Build Coastguard Worker }
4688*795d594fSAndroid Build Coastguard Worker 
VisitMax(HMax * max)4689*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMax(HMax* max) {
4690*795d594fSAndroid Build Coastguard Worker   CreateMinMaxLocations(GetGraph()->GetAllocator(), max);
4691*795d594fSAndroid Build Coastguard Worker }
4692*795d594fSAndroid Build Coastguard Worker 
VisitMax(HMax * max)4693*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMax(HMax* max) {
4694*795d594fSAndroid Build Coastguard Worker   GenerateMinMax(max, /*is_min*/ false);
4695*795d594fSAndroid Build Coastguard Worker }
4696*795d594fSAndroid Build Coastguard Worker 
VisitAbs(HAbs * abs)4697*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitAbs(HAbs* abs) {
4698*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs);
4699*795d594fSAndroid Build Coastguard Worker   switch (abs->GetResultType()) {
4700*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4701*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterLocation(EAX));
4702*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4703*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(EDX));
4704*795d594fSAndroid Build Coastguard Worker       break;
4705*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
4706*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
4707*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4708*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4709*795d594fSAndroid Build Coastguard Worker       break;
4710*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
4711*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
4712*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4713*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
4714*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
4715*795d594fSAndroid Build Coastguard Worker       break;
4716*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
4717*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
4718*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4719*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresFpuRegister());
4720*795d594fSAndroid Build Coastguard Worker       break;
4721*795d594fSAndroid Build Coastguard Worker     default:
4722*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4723*795d594fSAndroid Build Coastguard Worker   }
4724*795d594fSAndroid Build Coastguard Worker }
4725*795d594fSAndroid Build Coastguard Worker 
VisitAbs(HAbs * abs)4726*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitAbs(HAbs* abs) {
4727*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = abs->GetLocations();
4728*795d594fSAndroid Build Coastguard Worker   switch (abs->GetResultType()) {
4729*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4730*795d594fSAndroid Build Coastguard Worker       Register out = locations->Out().AsRegister<Register>();
4731*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(out, EAX);
4732*795d594fSAndroid Build Coastguard Worker       Register temp = locations->GetTemp(0).AsRegister<Register>();
4733*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(temp, EDX);
4734*795d594fSAndroid Build Coastguard Worker       // Sign extend EAX into EDX.
4735*795d594fSAndroid Build Coastguard Worker       __ cdq();
4736*795d594fSAndroid Build Coastguard Worker       // XOR EAX with sign.
4737*795d594fSAndroid Build Coastguard Worker       __ xorl(EAX, EDX);
4738*795d594fSAndroid Build Coastguard Worker       // Subtract out sign to correct.
4739*795d594fSAndroid Build Coastguard Worker       __ subl(EAX, EDX);
4740*795d594fSAndroid Build Coastguard Worker       // The result is in EAX.
4741*795d594fSAndroid Build Coastguard Worker       break;
4742*795d594fSAndroid Build Coastguard Worker     }
4743*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4744*795d594fSAndroid Build Coastguard Worker       Location input = locations->InAt(0);
4745*795d594fSAndroid Build Coastguard Worker       Register input_lo = input.AsRegisterPairLow<Register>();
4746*795d594fSAndroid Build Coastguard Worker       Register input_hi = input.AsRegisterPairHigh<Register>();
4747*795d594fSAndroid Build Coastguard Worker       Location output = locations->Out();
4748*795d594fSAndroid Build Coastguard Worker       Register output_lo = output.AsRegisterPairLow<Register>();
4749*795d594fSAndroid Build Coastguard Worker       Register output_hi = output.AsRegisterPairHigh<Register>();
4750*795d594fSAndroid Build Coastguard Worker       Register temp = locations->GetTemp(0).AsRegister<Register>();
4751*795d594fSAndroid Build Coastguard Worker       // Compute the sign into the temporary.
4752*795d594fSAndroid Build Coastguard Worker       __ movl(temp, input_hi);
4753*795d594fSAndroid Build Coastguard Worker       __ sarl(temp, Immediate(31));
4754*795d594fSAndroid Build Coastguard Worker       // Store the sign into the output.
4755*795d594fSAndroid Build Coastguard Worker       __ movl(output_lo, temp);
4756*795d594fSAndroid Build Coastguard Worker       __ movl(output_hi, temp);
4757*795d594fSAndroid Build Coastguard Worker       // XOR the input to the output.
4758*795d594fSAndroid Build Coastguard Worker       __ xorl(output_lo, input_lo);
4759*795d594fSAndroid Build Coastguard Worker       __ xorl(output_hi, input_hi);
4760*795d594fSAndroid Build Coastguard Worker       // Subtract the sign.
4761*795d594fSAndroid Build Coastguard Worker       __ subl(output_lo, temp);
4762*795d594fSAndroid Build Coastguard Worker       __ sbbl(output_hi, temp);
4763*795d594fSAndroid Build Coastguard Worker       break;
4764*795d594fSAndroid Build Coastguard Worker     }
4765*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
4766*795d594fSAndroid Build Coastguard Worker       XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4767*795d594fSAndroid Build Coastguard Worker       XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4768*795d594fSAndroid Build Coastguard Worker       Register constant = locations->GetTemp(1).AsRegister<Register>();
4769*795d594fSAndroid Build Coastguard Worker       __ movl(constant, Immediate(INT32_C(0x7FFFFFFF)));
4770*795d594fSAndroid Build Coastguard Worker       __ movd(temp, constant);
4771*795d594fSAndroid Build Coastguard Worker       __ andps(out, temp);
4772*795d594fSAndroid Build Coastguard Worker       break;
4773*795d594fSAndroid Build Coastguard Worker     }
4774*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
4775*795d594fSAndroid Build Coastguard Worker       XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4776*795d594fSAndroid Build Coastguard Worker       XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4777*795d594fSAndroid Build Coastguard Worker       // TODO: Use a constant from the constant table (requires extra input).
4778*795d594fSAndroid Build Coastguard Worker       __ LoadLongConstant(temp, INT64_C(0x7FFFFFFFFFFFFFFF));
4779*795d594fSAndroid Build Coastguard Worker       __ andpd(out, temp);
4780*795d594fSAndroid Build Coastguard Worker       break;
4781*795d594fSAndroid Build Coastguard Worker     }
4782*795d594fSAndroid Build Coastguard Worker     default:
4783*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4784*795d594fSAndroid Build Coastguard Worker   }
4785*795d594fSAndroid Build Coastguard Worker }
4786*795d594fSAndroid Build Coastguard Worker 
VisitDivZeroCheck(HDivZeroCheck * instruction)4787*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
4788*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4789*795d594fSAndroid Build Coastguard Worker   switch (instruction->GetType()) {
4790*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
4791*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
4792*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
4793*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
4794*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
4795*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4796*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::Any());
4797*795d594fSAndroid Build Coastguard Worker       break;
4798*795d594fSAndroid Build Coastguard Worker     }
4799*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4800*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
4801*795d594fSAndroid Build Coastguard Worker       if (!instruction->IsConstant()) {
4802*795d594fSAndroid Build Coastguard Worker         locations->AddTemp(Location::RequiresRegister());
4803*795d594fSAndroid Build Coastguard Worker       }
4804*795d594fSAndroid Build Coastguard Worker       break;
4805*795d594fSAndroid Build Coastguard Worker     }
4806*795d594fSAndroid Build Coastguard Worker     default:
4807*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4808*795d594fSAndroid Build Coastguard Worker   }
4809*795d594fSAndroid Build Coastguard Worker }
4810*795d594fSAndroid Build Coastguard Worker 
VisitDivZeroCheck(HDivZeroCheck * instruction)4811*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
4812*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path =
4813*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathX86(instruction);
4814*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
4815*795d594fSAndroid Build Coastguard Worker 
4816*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
4817*795d594fSAndroid Build Coastguard Worker   Location value = locations->InAt(0);
4818*795d594fSAndroid Build Coastguard Worker 
4819*795d594fSAndroid Build Coastguard Worker   switch (instruction->GetType()) {
4820*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
4821*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
4822*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
4823*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
4824*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
4825*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4826*795d594fSAndroid Build Coastguard Worker       if (value.IsRegister()) {
4827*795d594fSAndroid Build Coastguard Worker         __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
4828*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, slow_path->GetEntryLabel());
4829*795d594fSAndroid Build Coastguard Worker       } else if (value.IsStackSlot()) {
4830*795d594fSAndroid Build Coastguard Worker         __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
4831*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, slow_path->GetEntryLabel());
4832*795d594fSAndroid Build Coastguard Worker       } else {
4833*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant()) << value;
4834*795d594fSAndroid Build Coastguard Worker         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4835*795d594fSAndroid Build Coastguard Worker           __ jmp(slow_path->GetEntryLabel());
4836*795d594fSAndroid Build Coastguard Worker         }
4837*795d594fSAndroid Build Coastguard Worker       }
4838*795d594fSAndroid Build Coastguard Worker       break;
4839*795d594fSAndroid Build Coastguard Worker     }
4840*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4841*795d594fSAndroid Build Coastguard Worker       if (value.IsRegisterPair()) {
4842*795d594fSAndroid Build Coastguard Worker         Register temp = locations->GetTemp(0).AsRegister<Register>();
4843*795d594fSAndroid Build Coastguard Worker         __ movl(temp, value.AsRegisterPairLow<Register>());
4844*795d594fSAndroid Build Coastguard Worker         __ orl(temp, value.AsRegisterPairHigh<Register>());
4845*795d594fSAndroid Build Coastguard Worker         __ j(kEqual, slow_path->GetEntryLabel());
4846*795d594fSAndroid Build Coastguard Worker       } else {
4847*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant()) << value;
4848*795d594fSAndroid Build Coastguard Worker         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4849*795d594fSAndroid Build Coastguard Worker           __ jmp(slow_path->GetEntryLabel());
4850*795d594fSAndroid Build Coastguard Worker         }
4851*795d594fSAndroid Build Coastguard Worker       }
4852*795d594fSAndroid Build Coastguard Worker       break;
4853*795d594fSAndroid Build Coastguard Worker     }
4854*795d594fSAndroid Build Coastguard Worker     default:
4855*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
4856*795d594fSAndroid Build Coastguard Worker   }
4857*795d594fSAndroid Build Coastguard Worker }
4858*795d594fSAndroid Build Coastguard Worker 
HandleShift(HBinaryOperation * op)4859*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
4860*795d594fSAndroid Build Coastguard Worker   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4861*795d594fSAndroid Build Coastguard Worker 
4862*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
4863*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(op, LocationSummary::kNoCall);
4864*795d594fSAndroid Build Coastguard Worker 
4865*795d594fSAndroid Build Coastguard Worker   switch (op->GetResultType()) {
4866*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
4867*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4868*795d594fSAndroid Build Coastguard Worker       // Can't have Location::Any() and output SameAsFirstInput()
4869*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
4870*795d594fSAndroid Build Coastguard Worker       // The shift count needs to be in CL or a constant.
4871*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
4872*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
4873*795d594fSAndroid Build Coastguard Worker       break;
4874*795d594fSAndroid Build Coastguard Worker     }
4875*795d594fSAndroid Build Coastguard Worker     default:
4876*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected op type " << op->GetResultType();
4877*795d594fSAndroid Build Coastguard Worker   }
4878*795d594fSAndroid Build Coastguard Worker }
4879*795d594fSAndroid Build Coastguard Worker 
HandleShift(HBinaryOperation * op)4880*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
4881*795d594fSAndroid Build Coastguard Worker   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4882*795d594fSAndroid Build Coastguard Worker 
4883*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = op->GetLocations();
4884*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
4885*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
4886*795d594fSAndroid Build Coastguard Worker   DCHECK(first.Equals(locations->Out()));
4887*795d594fSAndroid Build Coastguard Worker 
4888*795d594fSAndroid Build Coastguard Worker   switch (op->GetResultType()) {
4889*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
4890*795d594fSAndroid Build Coastguard Worker       DCHECK(first.IsRegister());
4891*795d594fSAndroid Build Coastguard Worker       Register first_reg = first.AsRegister<Register>();
4892*795d594fSAndroid Build Coastguard Worker       if (second.IsRegister()) {
4893*795d594fSAndroid Build Coastguard Worker         Register second_reg = second.AsRegister<Register>();
4894*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(ECX, second_reg);
4895*795d594fSAndroid Build Coastguard Worker         if (op->IsShl()) {
4896*795d594fSAndroid Build Coastguard Worker           __ shll(first_reg, second_reg);
4897*795d594fSAndroid Build Coastguard Worker         } else if (op->IsShr()) {
4898*795d594fSAndroid Build Coastguard Worker           __ sarl(first_reg, second_reg);
4899*795d594fSAndroid Build Coastguard Worker         } else {
4900*795d594fSAndroid Build Coastguard Worker           __ shrl(first_reg, second_reg);
4901*795d594fSAndroid Build Coastguard Worker         }
4902*795d594fSAndroid Build Coastguard Worker       } else {
4903*795d594fSAndroid Build Coastguard Worker         int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance;
4904*795d594fSAndroid Build Coastguard Worker         if (shift == 0) {
4905*795d594fSAndroid Build Coastguard Worker           return;
4906*795d594fSAndroid Build Coastguard Worker         }
4907*795d594fSAndroid Build Coastguard Worker         Immediate imm(shift);
4908*795d594fSAndroid Build Coastguard Worker         if (op->IsShl()) {
4909*795d594fSAndroid Build Coastguard Worker           __ shll(first_reg, imm);
4910*795d594fSAndroid Build Coastguard Worker         } else if (op->IsShr()) {
4911*795d594fSAndroid Build Coastguard Worker           __ sarl(first_reg, imm);
4912*795d594fSAndroid Build Coastguard Worker         } else {
4913*795d594fSAndroid Build Coastguard Worker           __ shrl(first_reg, imm);
4914*795d594fSAndroid Build Coastguard Worker         }
4915*795d594fSAndroid Build Coastguard Worker       }
4916*795d594fSAndroid Build Coastguard Worker       break;
4917*795d594fSAndroid Build Coastguard Worker     }
4918*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
4919*795d594fSAndroid Build Coastguard Worker       if (second.IsRegister()) {
4920*795d594fSAndroid Build Coastguard Worker         Register second_reg = second.AsRegister<Register>();
4921*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(ECX, second_reg);
4922*795d594fSAndroid Build Coastguard Worker         if (op->IsShl()) {
4923*795d594fSAndroid Build Coastguard Worker           GenerateShlLong(first, second_reg);
4924*795d594fSAndroid Build Coastguard Worker         } else if (op->IsShr()) {
4925*795d594fSAndroid Build Coastguard Worker           GenerateShrLong(first, second_reg);
4926*795d594fSAndroid Build Coastguard Worker         } else {
4927*795d594fSAndroid Build Coastguard Worker           GenerateUShrLong(first, second_reg);
4928*795d594fSAndroid Build Coastguard Worker         }
4929*795d594fSAndroid Build Coastguard Worker       } else {
4930*795d594fSAndroid Build Coastguard Worker         // Shift by a constant.
4931*795d594fSAndroid Build Coastguard Worker         int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance;
4932*795d594fSAndroid Build Coastguard Worker         // Nothing to do if the shift is 0, as the input is already the output.
4933*795d594fSAndroid Build Coastguard Worker         if (shift != 0) {
4934*795d594fSAndroid Build Coastguard Worker           if (op->IsShl()) {
4935*795d594fSAndroid Build Coastguard Worker             GenerateShlLong(first, shift);
4936*795d594fSAndroid Build Coastguard Worker           } else if (op->IsShr()) {
4937*795d594fSAndroid Build Coastguard Worker             GenerateShrLong(first, shift);
4938*795d594fSAndroid Build Coastguard Worker           } else {
4939*795d594fSAndroid Build Coastguard Worker             GenerateUShrLong(first, shift);
4940*795d594fSAndroid Build Coastguard Worker           }
4941*795d594fSAndroid Build Coastguard Worker         }
4942*795d594fSAndroid Build Coastguard Worker       }
4943*795d594fSAndroid Build Coastguard Worker       break;
4944*795d594fSAndroid Build Coastguard Worker     }
4945*795d594fSAndroid Build Coastguard Worker     default:
4946*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected op type " << op->GetResultType();
4947*795d594fSAndroid Build Coastguard Worker   }
4948*795d594fSAndroid Build Coastguard Worker }
4949*795d594fSAndroid Build Coastguard Worker 
GenerateShlLong(const Location & loc,int shift)4950*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
4951*795d594fSAndroid Build Coastguard Worker   Register low = loc.AsRegisterPairLow<Register>();
4952*795d594fSAndroid Build Coastguard Worker   Register high = loc.AsRegisterPairHigh<Register>();
4953*795d594fSAndroid Build Coastguard Worker   if (shift == 1) {
4954*795d594fSAndroid Build Coastguard Worker     // This is just an addition.
4955*795d594fSAndroid Build Coastguard Worker     __ addl(low, low);
4956*795d594fSAndroid Build Coastguard Worker     __ adcl(high, high);
4957*795d594fSAndroid Build Coastguard Worker   } else if (shift == 32) {
4958*795d594fSAndroid Build Coastguard Worker     // Shift by 32 is easy. High gets low, and low gets 0.
4959*795d594fSAndroid Build Coastguard Worker     codegen_->EmitParallelMoves(
4960*795d594fSAndroid Build Coastguard Worker         loc.ToLow(),
4961*795d594fSAndroid Build Coastguard Worker         loc.ToHigh(),
4962*795d594fSAndroid Build Coastguard Worker         DataType::Type::kInt32,
4963*795d594fSAndroid Build Coastguard Worker         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
4964*795d594fSAndroid Build Coastguard Worker         loc.ToLow(),
4965*795d594fSAndroid Build Coastguard Worker         DataType::Type::kInt32);
4966*795d594fSAndroid Build Coastguard Worker   } else if (shift > 32) {
4967*795d594fSAndroid Build Coastguard Worker     // Low part becomes 0.  High part is low part << (shift-32).
4968*795d594fSAndroid Build Coastguard Worker     __ movl(high, low);
4969*795d594fSAndroid Build Coastguard Worker     __ shll(high, Immediate(shift - 32));
4970*795d594fSAndroid Build Coastguard Worker     __ xorl(low, low);
4971*795d594fSAndroid Build Coastguard Worker   } else {
4972*795d594fSAndroid Build Coastguard Worker     // Between 1 and 31.
4973*795d594fSAndroid Build Coastguard Worker     __ shld(high, low, Immediate(shift));
4974*795d594fSAndroid Build Coastguard Worker     __ shll(low, Immediate(shift));
4975*795d594fSAndroid Build Coastguard Worker   }
4976*795d594fSAndroid Build Coastguard Worker }
4977*795d594fSAndroid Build Coastguard Worker 
GenerateShlLong(const Location & loc,Register shifter)4978*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
4979*795d594fSAndroid Build Coastguard Worker   NearLabel done;
4980*795d594fSAndroid Build Coastguard Worker   __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
4981*795d594fSAndroid Build Coastguard Worker   __ shll(loc.AsRegisterPairLow<Register>(), shifter);
4982*795d594fSAndroid Build Coastguard Worker   __ testl(shifter, Immediate(32));
4983*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
4984*795d594fSAndroid Build Coastguard Worker   __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
4985*795d594fSAndroid Build Coastguard Worker   __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
4986*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
4987*795d594fSAndroid Build Coastguard Worker }
4988*795d594fSAndroid Build Coastguard Worker 
GenerateShrLong(const Location & loc,int shift)4989*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
4990*795d594fSAndroid Build Coastguard Worker   Register low = loc.AsRegisterPairLow<Register>();
4991*795d594fSAndroid Build Coastguard Worker   Register high = loc.AsRegisterPairHigh<Register>();
4992*795d594fSAndroid Build Coastguard Worker   if (shift == 32) {
4993*795d594fSAndroid Build Coastguard Worker     // Need to copy the sign.
4994*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(low, high);
4995*795d594fSAndroid Build Coastguard Worker     __ movl(low, high);
4996*795d594fSAndroid Build Coastguard Worker     __ sarl(high, Immediate(31));
4997*795d594fSAndroid Build Coastguard Worker   } else if (shift > 32) {
4998*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(low, high);
4999*795d594fSAndroid Build Coastguard Worker     // High part becomes sign. Low part is shifted by shift - 32.
5000*795d594fSAndroid Build Coastguard Worker     __ movl(low, high);
5001*795d594fSAndroid Build Coastguard Worker     __ sarl(high, Immediate(31));
5002*795d594fSAndroid Build Coastguard Worker     __ sarl(low, Immediate(shift - 32));
5003*795d594fSAndroid Build Coastguard Worker   } else {
5004*795d594fSAndroid Build Coastguard Worker     // Between 1 and 31.
5005*795d594fSAndroid Build Coastguard Worker     __ shrd(low, high, Immediate(shift));
5006*795d594fSAndroid Build Coastguard Worker     __ sarl(high, Immediate(shift));
5007*795d594fSAndroid Build Coastguard Worker   }
5008*795d594fSAndroid Build Coastguard Worker }
5009*795d594fSAndroid Build Coastguard Worker 
GenerateShrLong(const Location & loc,Register shifter)5010*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
5011*795d594fSAndroid Build Coastguard Worker   NearLabel done;
5012*795d594fSAndroid Build Coastguard Worker   __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
5013*795d594fSAndroid Build Coastguard Worker   __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
5014*795d594fSAndroid Build Coastguard Worker   __ testl(shifter, Immediate(32));
5015*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
5016*795d594fSAndroid Build Coastguard Worker   __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
5017*795d594fSAndroid Build Coastguard Worker   __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
5018*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
5019*795d594fSAndroid Build Coastguard Worker }
5020*795d594fSAndroid Build Coastguard Worker 
GenerateUShrLong(const Location & loc,int shift)5021*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
5022*795d594fSAndroid Build Coastguard Worker   Register low = loc.AsRegisterPairLow<Register>();
5023*795d594fSAndroid Build Coastguard Worker   Register high = loc.AsRegisterPairHigh<Register>();
5024*795d594fSAndroid Build Coastguard Worker   if (shift == 32) {
5025*795d594fSAndroid Build Coastguard Worker     // Shift by 32 is easy. Low gets high, and high gets 0.
5026*795d594fSAndroid Build Coastguard Worker     codegen_->EmitParallelMoves(
5027*795d594fSAndroid Build Coastguard Worker         loc.ToHigh(),
5028*795d594fSAndroid Build Coastguard Worker         loc.ToLow(),
5029*795d594fSAndroid Build Coastguard Worker         DataType::Type::kInt32,
5030*795d594fSAndroid Build Coastguard Worker         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
5031*795d594fSAndroid Build Coastguard Worker         loc.ToHigh(),
5032*795d594fSAndroid Build Coastguard Worker         DataType::Type::kInt32);
5033*795d594fSAndroid Build Coastguard Worker   } else if (shift > 32) {
5034*795d594fSAndroid Build Coastguard Worker     // Low part is high >> (shift - 32). High part becomes 0.
5035*795d594fSAndroid Build Coastguard Worker     __ movl(low, high);
5036*795d594fSAndroid Build Coastguard Worker     __ shrl(low, Immediate(shift - 32));
5037*795d594fSAndroid Build Coastguard Worker     __ xorl(high, high);
5038*795d594fSAndroid Build Coastguard Worker   } else {
5039*795d594fSAndroid Build Coastguard Worker     // Between 1 and 31.
5040*795d594fSAndroid Build Coastguard Worker     __ shrd(low, high, Immediate(shift));
5041*795d594fSAndroid Build Coastguard Worker     __ shrl(high, Immediate(shift));
5042*795d594fSAndroid Build Coastguard Worker   }
5043*795d594fSAndroid Build Coastguard Worker }
5044*795d594fSAndroid Build Coastguard Worker 
GenerateUShrLong(const Location & loc,Register shifter)5045*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
5046*795d594fSAndroid Build Coastguard Worker   NearLabel done;
5047*795d594fSAndroid Build Coastguard Worker   __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
5048*795d594fSAndroid Build Coastguard Worker   __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
5049*795d594fSAndroid Build Coastguard Worker   __ testl(shifter, Immediate(32));
5050*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
5051*795d594fSAndroid Build Coastguard Worker   __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
5052*795d594fSAndroid Build Coastguard Worker   __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
5053*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
5054*795d594fSAndroid Build Coastguard Worker }
5055*795d594fSAndroid Build Coastguard Worker 
VisitRol(HRol * rol)5056*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitRol(HRol* rol) {
5057*795d594fSAndroid Build Coastguard Worker   HandleRotate(rol);
5058*795d594fSAndroid Build Coastguard Worker }
5059*795d594fSAndroid Build Coastguard Worker 
VisitRor(HRor * ror)5060*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitRor(HRor* ror) {
5061*795d594fSAndroid Build Coastguard Worker   HandleRotate(ror);
5062*795d594fSAndroid Build Coastguard Worker }
5063*795d594fSAndroid Build Coastguard Worker 
HandleRotate(HBinaryOperation * rotate)5064*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleRotate(HBinaryOperation* rotate) {
5065*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5066*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(rotate, LocationSummary::kNoCall);
5067*795d594fSAndroid Build Coastguard Worker 
5068*795d594fSAndroid Build Coastguard Worker   switch (rotate->GetResultType()) {
5069*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
5070*795d594fSAndroid Build Coastguard Worker       // Add the temporary needed.
5071*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
5072*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
5073*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
5074*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
5075*795d594fSAndroid Build Coastguard Worker       // The shift count needs to be in CL (unless it is a constant).
5076*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, rotate->InputAt(1)));
5077*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::SameAsFirstInput());
5078*795d594fSAndroid Build Coastguard Worker       break;
5079*795d594fSAndroid Build Coastguard Worker     default:
5080*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected operation type " << rotate->GetResultType();
5081*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
5082*795d594fSAndroid Build Coastguard Worker   }
5083*795d594fSAndroid Build Coastguard Worker }
5084*795d594fSAndroid Build Coastguard Worker 
VisitRol(HRol * rol)5085*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitRol(HRol* rol) {
5086*795d594fSAndroid Build Coastguard Worker   HandleRotate(rol);
5087*795d594fSAndroid Build Coastguard Worker }
5088*795d594fSAndroid Build Coastguard Worker 
VisitRor(HRor * ror)5089*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitRor(HRor* ror) {
5090*795d594fSAndroid Build Coastguard Worker   HandleRotate(ror);
5091*795d594fSAndroid Build Coastguard Worker }
5092*795d594fSAndroid Build Coastguard Worker 
HandleRotate(HBinaryOperation * rotate)5093*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleRotate(HBinaryOperation* rotate) {
5094*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = rotate->GetLocations();
5095*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
5096*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
5097*795d594fSAndroid Build Coastguard Worker 
5098*795d594fSAndroid Build Coastguard Worker   if (rotate->GetResultType() == DataType::Type::kInt32) {
5099*795d594fSAndroid Build Coastguard Worker     Register first_reg = first.AsRegister<Register>();
5100*795d594fSAndroid Build Coastguard Worker     if (second.IsRegister()) {
5101*795d594fSAndroid Build Coastguard Worker       Register second_reg = second.AsRegister<Register>();
5102*795d594fSAndroid Build Coastguard Worker       if (rotate->IsRol()) {
5103*795d594fSAndroid Build Coastguard Worker         __ roll(first_reg, second_reg);
5104*795d594fSAndroid Build Coastguard Worker       } else {
5105*795d594fSAndroid Build Coastguard Worker         DCHECK(rotate->IsRor());
5106*795d594fSAndroid Build Coastguard Worker         __ rorl(first_reg, second_reg);
5107*795d594fSAndroid Build Coastguard Worker       }
5108*795d594fSAndroid Build Coastguard Worker     } else {
5109*795d594fSAndroid Build Coastguard Worker       Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
5110*795d594fSAndroid Build Coastguard Worker       if (rotate->IsRol()) {
5111*795d594fSAndroid Build Coastguard Worker         __ roll(first_reg, imm);
5112*795d594fSAndroid Build Coastguard Worker       } else {
5113*795d594fSAndroid Build Coastguard Worker         DCHECK(rotate->IsRor());
5114*795d594fSAndroid Build Coastguard Worker         __ rorl(first_reg, imm);
5115*795d594fSAndroid Build Coastguard Worker       }
5116*795d594fSAndroid Build Coastguard Worker     }
5117*795d594fSAndroid Build Coastguard Worker     return;
5118*795d594fSAndroid Build Coastguard Worker   }
5119*795d594fSAndroid Build Coastguard Worker 
5120*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(rotate->GetResultType(), DataType::Type::kInt64);
5121*795d594fSAndroid Build Coastguard Worker   Register first_reg_lo = first.AsRegisterPairLow<Register>();
5122*795d594fSAndroid Build Coastguard Worker   Register first_reg_hi = first.AsRegisterPairHigh<Register>();
5123*795d594fSAndroid Build Coastguard Worker   Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5124*795d594fSAndroid Build Coastguard Worker   if (second.IsRegister()) {
5125*795d594fSAndroid Build Coastguard Worker     Register second_reg = second.AsRegister<Register>();
5126*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(second_reg, ECX);
5127*795d594fSAndroid Build Coastguard Worker 
5128*795d594fSAndroid Build Coastguard Worker     __ movl(temp_reg, first_reg_hi);
5129*795d594fSAndroid Build Coastguard Worker     if (rotate->IsRol()) {
5130*795d594fSAndroid Build Coastguard Worker       __ shld(first_reg_hi, first_reg_lo, second_reg);
5131*795d594fSAndroid Build Coastguard Worker       __ shld(first_reg_lo, temp_reg, second_reg);
5132*795d594fSAndroid Build Coastguard Worker     } else {
5133*795d594fSAndroid Build Coastguard Worker       __ shrd(first_reg_hi, first_reg_lo, second_reg);
5134*795d594fSAndroid Build Coastguard Worker       __ shrd(first_reg_lo, temp_reg, second_reg);
5135*795d594fSAndroid Build Coastguard Worker     }
5136*795d594fSAndroid Build Coastguard Worker     __ movl(temp_reg, first_reg_hi);
5137*795d594fSAndroid Build Coastguard Worker     __ testl(second_reg, Immediate(32));
5138*795d594fSAndroid Build Coastguard Worker     __ cmovl(kNotEqual, first_reg_hi, first_reg_lo);
5139*795d594fSAndroid Build Coastguard Worker     __ cmovl(kNotEqual, first_reg_lo, temp_reg);
5140*795d594fSAndroid Build Coastguard Worker   } else {
5141*795d594fSAndroid Build Coastguard Worker     int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
5142*795d594fSAndroid Build Coastguard Worker     if (rotate->IsRol()) {
5143*795d594fSAndroid Build Coastguard Worker       value = -value;
5144*795d594fSAndroid Build Coastguard Worker     }
5145*795d594fSAndroid Build Coastguard Worker     int32_t shift_amt = value & kMaxLongShiftDistance;
5146*795d594fSAndroid Build Coastguard Worker 
5147*795d594fSAndroid Build Coastguard Worker     if (shift_amt == 0) {
5148*795d594fSAndroid Build Coastguard Worker       // Already fine.
5149*795d594fSAndroid Build Coastguard Worker       return;
5150*795d594fSAndroid Build Coastguard Worker     }
5151*795d594fSAndroid Build Coastguard Worker     if (shift_amt == 32) {
5152*795d594fSAndroid Build Coastguard Worker       // Just swap.
5153*795d594fSAndroid Build Coastguard Worker       __ movl(temp_reg, first_reg_lo);
5154*795d594fSAndroid Build Coastguard Worker       __ movl(first_reg_lo, first_reg_hi);
5155*795d594fSAndroid Build Coastguard Worker       __ movl(first_reg_hi, temp_reg);
5156*795d594fSAndroid Build Coastguard Worker       return;
5157*795d594fSAndroid Build Coastguard Worker     }
5158*795d594fSAndroid Build Coastguard Worker 
5159*795d594fSAndroid Build Coastguard Worker     Immediate imm(shift_amt);
5160*795d594fSAndroid Build Coastguard Worker     // Save the constents of the low value.
5161*795d594fSAndroid Build Coastguard Worker     __ movl(temp_reg, first_reg_lo);
5162*795d594fSAndroid Build Coastguard Worker 
5163*795d594fSAndroid Build Coastguard Worker     // Shift right into low, feeding bits from high.
5164*795d594fSAndroid Build Coastguard Worker     __ shrd(first_reg_lo, first_reg_hi, imm);
5165*795d594fSAndroid Build Coastguard Worker 
5166*795d594fSAndroid Build Coastguard Worker     // Shift right into high, feeding bits from the original low.
5167*795d594fSAndroid Build Coastguard Worker     __ shrd(first_reg_hi, temp_reg, imm);
5168*795d594fSAndroid Build Coastguard Worker 
5169*795d594fSAndroid Build Coastguard Worker     // Swap if needed.
5170*795d594fSAndroid Build Coastguard Worker     if (shift_amt > 32) {
5171*795d594fSAndroid Build Coastguard Worker       __ movl(temp_reg, first_reg_lo);
5172*795d594fSAndroid Build Coastguard Worker       __ movl(first_reg_lo, first_reg_hi);
5173*795d594fSAndroid Build Coastguard Worker       __ movl(first_reg_hi, temp_reg);
5174*795d594fSAndroid Build Coastguard Worker     }
5175*795d594fSAndroid Build Coastguard Worker   }
5176*795d594fSAndroid Build Coastguard Worker }
5177*795d594fSAndroid Build Coastguard Worker 
VisitShl(HShl * shl)5178*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitShl(HShl* shl) {
5179*795d594fSAndroid Build Coastguard Worker   HandleShift(shl);
5180*795d594fSAndroid Build Coastguard Worker }
5181*795d594fSAndroid Build Coastguard Worker 
VisitShl(HShl * shl)5182*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
5183*795d594fSAndroid Build Coastguard Worker   HandleShift(shl);
5184*795d594fSAndroid Build Coastguard Worker }
5185*795d594fSAndroid Build Coastguard Worker 
VisitShr(HShr * shr)5186*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitShr(HShr* shr) {
5187*795d594fSAndroid Build Coastguard Worker   HandleShift(shr);
5188*795d594fSAndroid Build Coastguard Worker }
5189*795d594fSAndroid Build Coastguard Worker 
VisitShr(HShr * shr)5190*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
5191*795d594fSAndroid Build Coastguard Worker   HandleShift(shr);
5192*795d594fSAndroid Build Coastguard Worker }
5193*795d594fSAndroid Build Coastguard Worker 
VisitUShr(HUShr * ushr)5194*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
5195*795d594fSAndroid Build Coastguard Worker   HandleShift(ushr);
5196*795d594fSAndroid Build Coastguard Worker }
5197*795d594fSAndroid Build Coastguard Worker 
VisitUShr(HUShr * ushr)5198*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
5199*795d594fSAndroid Build Coastguard Worker   HandleShift(ushr);
5200*795d594fSAndroid Build Coastguard Worker }
5201*795d594fSAndroid Build Coastguard Worker 
VisitNewInstance(HNewInstance * instruction)5202*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
5203*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
5204*795d594fSAndroid Build Coastguard Worker       instruction, LocationSummary::kCallOnMainOnly);
5205*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
5206*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
5207*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5208*795d594fSAndroid Build Coastguard Worker }
5209*795d594fSAndroid Build Coastguard Worker 
VisitNewInstance(HNewInstance * instruction)5210*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
5211*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
5212*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
5213*795d594fSAndroid Build Coastguard Worker   DCHECK(!codegen_->IsLeafMethod());
5214*795d594fSAndroid Build Coastguard Worker }
5215*795d594fSAndroid Build Coastguard Worker 
VisitNewArray(HNewArray * instruction)5216*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
5217*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
5218*795d594fSAndroid Build Coastguard Worker       instruction, LocationSummary::kCallOnMainOnly);
5219*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(EAX));
5220*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
5221*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5222*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5223*795d594fSAndroid Build Coastguard Worker }
5224*795d594fSAndroid Build Coastguard Worker 
VisitNewArray(HNewArray * instruction)5225*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
5226*795d594fSAndroid Build Coastguard Worker   // Note: if heap poisoning is enabled, the entry point takes care of poisoning the reference.
5227*795d594fSAndroid Build Coastguard Worker   QuickEntrypointEnum entrypoint = CodeGenerator::GetArrayAllocationEntrypoint(instruction);
5228*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
5229*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
5230*795d594fSAndroid Build Coastguard Worker   DCHECK(!codegen_->IsLeafMethod());
5231*795d594fSAndroid Build Coastguard Worker }
5232*795d594fSAndroid Build Coastguard Worker 
VisitParameterValue(HParameterValue * instruction)5233*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
5234*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5235*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
5236*795d594fSAndroid Build Coastguard Worker   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5237*795d594fSAndroid Build Coastguard Worker   if (location.IsStackSlot()) {
5238*795d594fSAndroid Build Coastguard Worker     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5239*795d594fSAndroid Build Coastguard Worker   } else if (location.IsDoubleStackSlot()) {
5240*795d594fSAndroid Build Coastguard Worker     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5241*795d594fSAndroid Build Coastguard Worker   }
5242*795d594fSAndroid Build Coastguard Worker   locations->SetOut(location);
5243*795d594fSAndroid Build Coastguard Worker }
5244*795d594fSAndroid Build Coastguard Worker 
VisitParameterValue(HParameterValue * instruction)5245*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitParameterValue(
5246*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HParameterValue* instruction) {}
5247*795d594fSAndroid Build Coastguard Worker 
VisitCurrentMethod(HCurrentMethod * instruction)5248*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
5249*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5250*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
5251*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5252*795d594fSAndroid Build Coastguard Worker }
5253*795d594fSAndroid Build Coastguard Worker 
VisitCurrentMethod(HCurrentMethod * instruction)5254*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitCurrentMethod([[maybe_unused]] HCurrentMethod* instruction) {
5255*795d594fSAndroid Build Coastguard Worker }
5256*795d594fSAndroid Build Coastguard Worker 
VisitClassTableGet(HClassTableGet * instruction)5257*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitClassTableGet(HClassTableGet* instruction) {
5258*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5259*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
5260*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
5261*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
5262*795d594fSAndroid Build Coastguard Worker }
5263*795d594fSAndroid Build Coastguard Worker 
VisitClassTableGet(HClassTableGet * instruction)5264*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitClassTableGet(HClassTableGet* instruction) {
5265*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
5266*795d594fSAndroid Build Coastguard Worker   if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
5267*795d594fSAndroid Build Coastguard Worker     uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5268*795d594fSAndroid Build Coastguard Worker         instruction->GetIndex(), kX86PointerSize).SizeValue();
5269*795d594fSAndroid Build Coastguard Worker     __ movl(locations->Out().AsRegister<Register>(),
5270*795d594fSAndroid Build Coastguard Worker             Address(locations->InAt(0).AsRegister<Register>(), method_offset));
5271*795d594fSAndroid Build Coastguard Worker   } else {
5272*795d594fSAndroid Build Coastguard Worker     uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
5273*795d594fSAndroid Build Coastguard Worker         instruction->GetIndex(), kX86PointerSize));
5274*795d594fSAndroid Build Coastguard Worker     __ movl(locations->Out().AsRegister<Register>(),
5275*795d594fSAndroid Build Coastguard Worker             Address(locations->InAt(0).AsRegister<Register>(),
5276*795d594fSAndroid Build Coastguard Worker                     mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
5277*795d594fSAndroid Build Coastguard Worker     // temp = temp->GetImtEntryAt(method_offset);
5278*795d594fSAndroid Build Coastguard Worker     __ movl(locations->Out().AsRegister<Register>(),
5279*795d594fSAndroid Build Coastguard Worker             Address(locations->Out().AsRegister<Register>(), method_offset));
5280*795d594fSAndroid Build Coastguard Worker   }
5281*795d594fSAndroid Build Coastguard Worker }
5282*795d594fSAndroid Build Coastguard Worker 
VisitNot(HNot * not_)5283*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNot(HNot* not_) {
5284*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5285*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(not_, LocationSummary::kNoCall);
5286*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
5287*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
5288*795d594fSAndroid Build Coastguard Worker }
5289*795d594fSAndroid Build Coastguard Worker 
VisitNot(HNot * not_)5290*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
5291*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = not_->GetLocations();
5292*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
5293*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
5294*795d594fSAndroid Build Coastguard Worker   DCHECK(in.Equals(out));
5295*795d594fSAndroid Build Coastguard Worker   switch (not_->GetResultType()) {
5296*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
5297*795d594fSAndroid Build Coastguard Worker       __ notl(out.AsRegister<Register>());
5298*795d594fSAndroid Build Coastguard Worker       break;
5299*795d594fSAndroid Build Coastguard Worker 
5300*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
5301*795d594fSAndroid Build Coastguard Worker       __ notl(out.AsRegisterPairLow<Register>());
5302*795d594fSAndroid Build Coastguard Worker       __ notl(out.AsRegisterPairHigh<Register>());
5303*795d594fSAndroid Build Coastguard Worker       break;
5304*795d594fSAndroid Build Coastguard Worker 
5305*795d594fSAndroid Build Coastguard Worker     default:
5306*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
5307*795d594fSAndroid Build Coastguard Worker   }
5308*795d594fSAndroid Build Coastguard Worker }
5309*795d594fSAndroid Build Coastguard Worker 
VisitBooleanNot(HBooleanNot * bool_not)5310*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
5311*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5312*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(bool_not, LocationSummary::kNoCall);
5313*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
5314*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
5315*795d594fSAndroid Build Coastguard Worker }
5316*795d594fSAndroid Build Coastguard Worker 
VisitBooleanNot(HBooleanNot * bool_not)5317*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
5318*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = bool_not->GetLocations();
5319*795d594fSAndroid Build Coastguard Worker   Location in = locations->InAt(0);
5320*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
5321*795d594fSAndroid Build Coastguard Worker   DCHECK(in.Equals(out));
5322*795d594fSAndroid Build Coastguard Worker   __ xorl(out.AsRegister<Register>(), Immediate(1));
5323*795d594fSAndroid Build Coastguard Worker }
5324*795d594fSAndroid Build Coastguard Worker 
VisitCompare(HCompare * compare)5325*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitCompare(HCompare* compare) {
5326*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5327*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
5328*795d594fSAndroid Build Coastguard Worker   switch (compare->GetComparisonType()) {
5329*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
5330*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
5331*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
5332*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
5333*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
5334*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
5335*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
5336*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64:
5337*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64: {
5338*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresRegister());
5339*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::Any());
5340*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5341*795d594fSAndroid Build Coastguard Worker       break;
5342*795d594fSAndroid Build Coastguard Worker     }
5343*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
5344*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
5345*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(0, Location::RequiresFpuRegister());
5346*795d594fSAndroid Build Coastguard Worker       if (compare->InputAt(1)->IsX86LoadFromConstantTable()) {
5347*795d594fSAndroid Build Coastguard Worker         DCHECK(compare->InputAt(1)->IsEmittedAtUseSite());
5348*795d594fSAndroid Build Coastguard Worker       } else if (compare->InputAt(1)->IsConstant()) {
5349*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::RequiresFpuRegister());
5350*795d594fSAndroid Build Coastguard Worker       } else {
5351*795d594fSAndroid Build Coastguard Worker         locations->SetInAt(1, Location::Any());
5352*795d594fSAndroid Build Coastguard Worker       }
5353*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister());
5354*795d594fSAndroid Build Coastguard Worker       break;
5355*795d594fSAndroid Build Coastguard Worker     }
5356*795d594fSAndroid Build Coastguard Worker     default:
5357*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
5358*795d594fSAndroid Build Coastguard Worker   }
5359*795d594fSAndroid Build Coastguard Worker }
5360*795d594fSAndroid Build Coastguard Worker 
VisitCompare(HCompare * compare)5361*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
5362*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = compare->GetLocations();
5363*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
5364*795d594fSAndroid Build Coastguard Worker   Location left = locations->InAt(0);
5365*795d594fSAndroid Build Coastguard Worker   Location right = locations->InAt(1);
5366*795d594fSAndroid Build Coastguard Worker 
5367*795d594fSAndroid Build Coastguard Worker   NearLabel less, greater, done;
5368*795d594fSAndroid Build Coastguard Worker   Condition less_cond = kLess;
5369*795d594fSAndroid Build Coastguard Worker   Condition greater_cond = kGreater;
5370*795d594fSAndroid Build Coastguard Worker 
5371*795d594fSAndroid Build Coastguard Worker   switch (compare->GetComparisonType()) {
5372*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
5373*795d594fSAndroid Build Coastguard Worker       less_cond = kBelow;
5374*795d594fSAndroid Build Coastguard Worker       // greater_cond - is not needed below
5375*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
5376*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
5377*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
5378*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8:
5379*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
5380*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16:
5381*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
5382*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateIntCompare(left, right);
5383*795d594fSAndroid Build Coastguard Worker       break;
5384*795d594fSAndroid Build Coastguard Worker     }
5385*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
5386*795d594fSAndroid Build Coastguard Worker       less_cond = kBelow;
5387*795d594fSAndroid Build Coastguard Worker       greater_cond = kAbove;
5388*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
5389*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
5390*795d594fSAndroid Build Coastguard Worker       Register left_low = left.AsRegisterPairLow<Register>();
5391*795d594fSAndroid Build Coastguard Worker       Register left_high = left.AsRegisterPairHigh<Register>();
5392*795d594fSAndroid Build Coastguard Worker       int32_t val_low = 0;
5393*795d594fSAndroid Build Coastguard Worker       int32_t val_high = 0;
5394*795d594fSAndroid Build Coastguard Worker       bool right_is_const = false;
5395*795d594fSAndroid Build Coastguard Worker 
5396*795d594fSAndroid Build Coastguard Worker       if (right.IsConstant()) {
5397*795d594fSAndroid Build Coastguard Worker         DCHECK(right.GetConstant()->IsLongConstant());
5398*795d594fSAndroid Build Coastguard Worker         right_is_const = true;
5399*795d594fSAndroid Build Coastguard Worker         int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
5400*795d594fSAndroid Build Coastguard Worker         val_low = Low32Bits(val);
5401*795d594fSAndroid Build Coastguard Worker         val_high = High32Bits(val);
5402*795d594fSAndroid Build Coastguard Worker       }
5403*795d594fSAndroid Build Coastguard Worker 
5404*795d594fSAndroid Build Coastguard Worker       if (right.IsRegisterPair()) {
5405*795d594fSAndroid Build Coastguard Worker         __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
5406*795d594fSAndroid Build Coastguard Worker       } else if (right.IsDoubleStackSlot()) {
5407*795d594fSAndroid Build Coastguard Worker         __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
5408*795d594fSAndroid Build Coastguard Worker       } else {
5409*795d594fSAndroid Build Coastguard Worker         DCHECK(right_is_const) << right;
5410*795d594fSAndroid Build Coastguard Worker         codegen_->Compare32BitValue(left_high, val_high);
5411*795d594fSAndroid Build Coastguard Worker       }
5412*795d594fSAndroid Build Coastguard Worker       __ j(less_cond, &less);        // High part compare.
5413*795d594fSAndroid Build Coastguard Worker       __ j(greater_cond, &greater);  // High part compare.
5414*795d594fSAndroid Build Coastguard Worker       if (right.IsRegisterPair()) {
5415*795d594fSAndroid Build Coastguard Worker         __ cmpl(left_low, right.AsRegisterPairLow<Register>());
5416*795d594fSAndroid Build Coastguard Worker       } else if (right.IsDoubleStackSlot()) {
5417*795d594fSAndroid Build Coastguard Worker         __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
5418*795d594fSAndroid Build Coastguard Worker       } else {
5419*795d594fSAndroid Build Coastguard Worker         DCHECK(right_is_const) << right;
5420*795d594fSAndroid Build Coastguard Worker         codegen_->Compare32BitValue(left_low, val_low);
5421*795d594fSAndroid Build Coastguard Worker       }
5422*795d594fSAndroid Build Coastguard Worker       less_cond = kBelow;  // for CF (unsigned).
5423*795d594fSAndroid Build Coastguard Worker       // greater_cond - is not needed below
5424*795d594fSAndroid Build Coastguard Worker       break;
5425*795d594fSAndroid Build Coastguard Worker     }
5426*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
5427*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(left, right, compare, false);
5428*795d594fSAndroid Build Coastguard Worker       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
5429*795d594fSAndroid Build Coastguard Worker       less_cond = kBelow;  // for CF (floats).
5430*795d594fSAndroid Build Coastguard Worker       break;
5431*795d594fSAndroid Build Coastguard Worker     }
5432*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
5433*795d594fSAndroid Build Coastguard Worker       GenerateFPCompare(left, right, compare, true);
5434*795d594fSAndroid Build Coastguard Worker       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
5435*795d594fSAndroid Build Coastguard Worker       less_cond = kBelow;  // for CF (floats).
5436*795d594fSAndroid Build Coastguard Worker       break;
5437*795d594fSAndroid Build Coastguard Worker     }
5438*795d594fSAndroid Build Coastguard Worker     default:
5439*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
5440*795d594fSAndroid Build Coastguard Worker   }
5441*795d594fSAndroid Build Coastguard Worker 
5442*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(0));
5443*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
5444*795d594fSAndroid Build Coastguard Worker   __ j(less_cond, &less);
5445*795d594fSAndroid Build Coastguard Worker 
5446*795d594fSAndroid Build Coastguard Worker   __ Bind(&greater);
5447*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(1));
5448*795d594fSAndroid Build Coastguard Worker   __ jmp(&done);
5449*795d594fSAndroid Build Coastguard Worker 
5450*795d594fSAndroid Build Coastguard Worker   __ Bind(&less);
5451*795d594fSAndroid Build Coastguard Worker   __ movl(out, Immediate(-1));
5452*795d594fSAndroid Build Coastguard Worker 
5453*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
5454*795d594fSAndroid Build Coastguard Worker }
5455*795d594fSAndroid Build Coastguard Worker 
VisitPhi(HPhi * instruction)5456*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
5457*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
5458*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
5459*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
5460*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(i, Location::Any());
5461*795d594fSAndroid Build Coastguard Worker   }
5462*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::Any());
5463*795d594fSAndroid Build Coastguard Worker }
5464*795d594fSAndroid Build Coastguard Worker 
VisitPhi(HPhi * instruction)5465*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitPhi([[maybe_unused]] HPhi* instruction) {
5466*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
5467*795d594fSAndroid Build Coastguard Worker }
5468*795d594fSAndroid Build Coastguard Worker 
GenerateMemoryBarrier(MemBarrierKind kind)5469*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
5470*795d594fSAndroid Build Coastguard Worker   /*
5471*795d594fSAndroid Build Coastguard Worker    * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
5472*795d594fSAndroid Build Coastguard Worker    * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
5473*795d594fSAndroid Build Coastguard Worker    * For those cases, all we need to ensure is that there is a scheduling barrier in place.
5474*795d594fSAndroid Build Coastguard Worker    */
5475*795d594fSAndroid Build Coastguard Worker   switch (kind) {
5476*795d594fSAndroid Build Coastguard Worker     case MemBarrierKind::kAnyAny: {
5477*795d594fSAndroid Build Coastguard Worker       MemoryFence();
5478*795d594fSAndroid Build Coastguard Worker       break;
5479*795d594fSAndroid Build Coastguard Worker     }
5480*795d594fSAndroid Build Coastguard Worker     case MemBarrierKind::kAnyStore:
5481*795d594fSAndroid Build Coastguard Worker     case MemBarrierKind::kLoadAny:
5482*795d594fSAndroid Build Coastguard Worker     case MemBarrierKind::kStoreStore: {
5483*795d594fSAndroid Build Coastguard Worker       // nop
5484*795d594fSAndroid Build Coastguard Worker       break;
5485*795d594fSAndroid Build Coastguard Worker     }
5486*795d594fSAndroid Build Coastguard Worker     case MemBarrierKind::kNTStoreStore:
5487*795d594fSAndroid Build Coastguard Worker       // Non-Temporal Store/Store needs an explicit fence.
5488*795d594fSAndroid Build Coastguard Worker       MemoryFence(/* non-temporal= */ true);
5489*795d594fSAndroid Build Coastguard Worker       break;
5490*795d594fSAndroid Build Coastguard Worker   }
5491*795d594fSAndroid Build Coastguard Worker }
5492*795d594fSAndroid Build Coastguard Worker 
GetSupportedInvokeStaticOrDirectDispatch(const HInvokeStaticOrDirect::DispatchInfo & desired_dispatch_info,ArtMethod * method)5493*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
5494*795d594fSAndroid Build Coastguard Worker     const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5495*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] ArtMethod* method) {
5496*795d594fSAndroid Build Coastguard Worker   return desired_dispatch_info;
5497*795d594fSAndroid Build Coastguard Worker }
5498*795d594fSAndroid Build Coastguard Worker 
GetInvokeExtraParameter(HInvoke * invoke,Register temp)5499*795d594fSAndroid Build Coastguard Worker Register CodeGeneratorX86::GetInvokeExtraParameter(HInvoke* invoke, Register temp) {
5500*795d594fSAndroid Build Coastguard Worker   if (invoke->IsInvokeStaticOrDirect()) {
5501*795d594fSAndroid Build Coastguard Worker     return GetInvokeStaticOrDirectExtraParameter(invoke->AsInvokeStaticOrDirect(), temp);
5502*795d594fSAndroid Build Coastguard Worker   }
5503*795d594fSAndroid Build Coastguard Worker   DCHECK(invoke->IsInvokeInterface());
5504*795d594fSAndroid Build Coastguard Worker   Location location =
5505*795d594fSAndroid Build Coastguard Worker       invoke->GetLocations()->InAt(invoke->AsInvokeInterface()->GetSpecialInputIndex());
5506*795d594fSAndroid Build Coastguard Worker   return location.AsRegister<Register>();
5507*795d594fSAndroid Build Coastguard Worker }
5508*795d594fSAndroid Build Coastguard Worker 
GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect * invoke,Register temp)5509*795d594fSAndroid Build Coastguard Worker Register CodeGeneratorX86::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
5510*795d594fSAndroid Build Coastguard Worker                                                                  Register temp) {
5511*795d594fSAndroid Build Coastguard Worker   Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
5512*795d594fSAndroid Build Coastguard Worker   if (!invoke->GetLocations()->Intrinsified()) {
5513*795d594fSAndroid Build Coastguard Worker     return location.AsRegister<Register>();
5514*795d594fSAndroid Build Coastguard Worker   }
5515*795d594fSAndroid Build Coastguard Worker   // For intrinsics we allow any location, so it may be on the stack.
5516*795d594fSAndroid Build Coastguard Worker   if (!location.IsRegister()) {
5517*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(ESP, location.GetStackIndex()));
5518*795d594fSAndroid Build Coastguard Worker     return temp;
5519*795d594fSAndroid Build Coastguard Worker   }
5520*795d594fSAndroid Build Coastguard Worker   // For register locations, check if the register was saved. If so, get it from the stack.
5521*795d594fSAndroid Build Coastguard Worker   // Note: There is a chance that the register was saved but not overwritten, so we could
5522*795d594fSAndroid Build Coastguard Worker   // save one load. However, since this is just an intrinsic slow path we prefer this
5523*795d594fSAndroid Build Coastguard Worker   // simple and more robust approach rather that trying to determine if that's the case.
5524*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = GetCurrentSlowPath();
5525*795d594fSAndroid Build Coastguard Worker   DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
5526*795d594fSAndroid Build Coastguard Worker   if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
5527*795d594fSAndroid Build Coastguard Worker     int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
5528*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(ESP, stack_offset));
5529*795d594fSAndroid Build Coastguard Worker     return temp;
5530*795d594fSAndroid Build Coastguard Worker   }
5531*795d594fSAndroid Build Coastguard Worker   return location.AsRegister<Register>();
5532*795d594fSAndroid Build Coastguard Worker }
5533*795d594fSAndroid Build Coastguard Worker 
LoadMethod(MethodLoadKind load_kind,Location temp,HInvoke * invoke)5534*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke) {
5535*795d594fSAndroid Build Coastguard Worker   switch (load_kind) {
5536*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kBootImageLinkTimePcRelative: {
5537*795d594fSAndroid Build Coastguard Worker       DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5538*795d594fSAndroid Build Coastguard Worker       Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5539*795d594fSAndroid Build Coastguard Worker       __ leal(temp.AsRegister<Register>(),
5540*795d594fSAndroid Build Coastguard Worker               Address(base_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5541*795d594fSAndroid Build Coastguard Worker       RecordBootImageMethodPatch(invoke);
5542*795d594fSAndroid Build Coastguard Worker       break;
5543*795d594fSAndroid Build Coastguard Worker     }
5544*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kBootImageRelRo: {
5545*795d594fSAndroid Build Coastguard Worker       size_t index = invoke->IsInvokeInterface()
5546*795d594fSAndroid Build Coastguard Worker           ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5547*795d594fSAndroid Build Coastguard Worker           : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
5548*795d594fSAndroid Build Coastguard Worker       Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5549*795d594fSAndroid Build Coastguard Worker       __ movl(temp.AsRegister<Register>(), Address(base_reg, kPlaceholder32BitOffset));
5550*795d594fSAndroid Build Coastguard Worker       RecordBootImageRelRoPatch(
5551*795d594fSAndroid Build Coastguard Worker           invoke->InputAt(index)->AsX86ComputeBaseMethodAddress(),
5552*795d594fSAndroid Build Coastguard Worker           GetBootImageOffset(invoke));
5553*795d594fSAndroid Build Coastguard Worker       break;
5554*795d594fSAndroid Build Coastguard Worker     }
5555*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kAppImageRelRo: {
5556*795d594fSAndroid Build Coastguard Worker       DCHECK(GetCompilerOptions().IsAppImage());
5557*795d594fSAndroid Build Coastguard Worker       Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5558*795d594fSAndroid Build Coastguard Worker       __ movl(temp.AsRegister<Register>(), Address(base_reg, kPlaceholder32BitOffset));
5559*795d594fSAndroid Build Coastguard Worker       RecordAppImageMethodPatch(invoke);
5560*795d594fSAndroid Build Coastguard Worker       break;
5561*795d594fSAndroid Build Coastguard Worker     }
5562*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kBssEntry: {
5563*795d594fSAndroid Build Coastguard Worker       Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5564*795d594fSAndroid Build Coastguard Worker       __ movl(temp.AsRegister<Register>(), Address(base_reg, kPlaceholder32BitOffset));
5565*795d594fSAndroid Build Coastguard Worker       RecordMethodBssEntryPatch(invoke);
5566*795d594fSAndroid Build Coastguard Worker       // No need for memory fence, thanks to the x86 memory model.
5567*795d594fSAndroid Build Coastguard Worker       break;
5568*795d594fSAndroid Build Coastguard Worker     }
5569*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kJitDirectAddress: {
5570*795d594fSAndroid Build Coastguard Worker       __ movl(temp.AsRegister<Register>(),
5571*795d594fSAndroid Build Coastguard Worker               Immediate(reinterpret_cast32<uint32_t>(invoke->GetResolvedMethod())));
5572*795d594fSAndroid Build Coastguard Worker       break;
5573*795d594fSAndroid Build Coastguard Worker     }
5574*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kRuntimeCall: {
5575*795d594fSAndroid Build Coastguard Worker       // Test situation, don't do anything.
5576*795d594fSAndroid Build Coastguard Worker       break;
5577*795d594fSAndroid Build Coastguard Worker     }
5578*795d594fSAndroid Build Coastguard Worker     default: {
5579*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Load kind should have already been handled " << load_kind;
5580*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
5581*795d594fSAndroid Build Coastguard Worker     }
5582*795d594fSAndroid Build Coastguard Worker   }
5583*795d594fSAndroid Build Coastguard Worker }
5584*795d594fSAndroid Build Coastguard Worker 
GenerateStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Location temp,SlowPathCode * slow_path)5585*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateStaticOrDirectCall(
5586*795d594fSAndroid Build Coastguard Worker     HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
5587*795d594fSAndroid Build Coastguard Worker   Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
5588*795d594fSAndroid Build Coastguard Worker   switch (invoke->GetMethodLoadKind()) {
5589*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kStringInit: {
5590*795d594fSAndroid Build Coastguard Worker       // temp = thread->string_init_entrypoint
5591*795d594fSAndroid Build Coastguard Worker       uint32_t offset =
5592*795d594fSAndroid Build Coastguard Worker           GetThreadOffset<kX86PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
5593*795d594fSAndroid Build Coastguard Worker       __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(offset));
5594*795d594fSAndroid Build Coastguard Worker       break;
5595*795d594fSAndroid Build Coastguard Worker     }
5596*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kRecursive: {
5597*795d594fSAndroid Build Coastguard Worker       callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodIndex());
5598*795d594fSAndroid Build Coastguard Worker       break;
5599*795d594fSAndroid Build Coastguard Worker     }
5600*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kRuntimeCall: {
5601*795d594fSAndroid Build Coastguard Worker       GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
5602*795d594fSAndroid Build Coastguard Worker       return;  // No code pointer retrieval; the runtime performs the call directly.
5603*795d594fSAndroid Build Coastguard Worker     }
5604*795d594fSAndroid Build Coastguard Worker     case MethodLoadKind::kBootImageLinkTimePcRelative:
5605*795d594fSAndroid Build Coastguard Worker       // For kCallCriticalNative we skip loading the method and do the call directly.
5606*795d594fSAndroid Build Coastguard Worker       if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
5607*795d594fSAndroid Build Coastguard Worker         break;
5608*795d594fSAndroid Build Coastguard Worker       }
5609*795d594fSAndroid Build Coastguard Worker       FALLTHROUGH_INTENDED;
5610*795d594fSAndroid Build Coastguard Worker     default: {
5611*795d594fSAndroid Build Coastguard Worker       LoadMethod(invoke->GetMethodLoadKind(), callee_method, invoke);
5612*795d594fSAndroid Build Coastguard Worker     }
5613*795d594fSAndroid Build Coastguard Worker   }
5614*795d594fSAndroid Build Coastguard Worker 
5615*795d594fSAndroid Build Coastguard Worker   switch (invoke->GetCodePtrLocation()) {
5616*795d594fSAndroid Build Coastguard Worker     case CodePtrLocation::kCallSelf:
5617*795d594fSAndroid Build Coastguard Worker       DCHECK(!GetGraph()->HasShouldDeoptimizeFlag());
5618*795d594fSAndroid Build Coastguard Worker       __ call(GetFrameEntryLabel());
5619*795d594fSAndroid Build Coastguard Worker       RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5620*795d594fSAndroid Build Coastguard Worker       break;
5621*795d594fSAndroid Build Coastguard Worker     case CodePtrLocation::kCallCriticalNative: {
5622*795d594fSAndroid Build Coastguard Worker       size_t out_frame_size =
5623*795d594fSAndroid Build Coastguard Worker           PrepareCriticalNativeCall<CriticalNativeCallingConventionVisitorX86,
5624*795d594fSAndroid Build Coastguard Worker                                     kNativeStackAlignment,
5625*795d594fSAndroid Build Coastguard Worker                                     GetCriticalNativeDirectCallFrameSize>(invoke);
5626*795d594fSAndroid Build Coastguard Worker       if (invoke->GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative) {
5627*795d594fSAndroid Build Coastguard Worker         DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5628*795d594fSAndroid Build Coastguard Worker         Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5629*795d594fSAndroid Build Coastguard Worker         __ call(Address(base_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5630*795d594fSAndroid Build Coastguard Worker         RecordBootImageJniEntrypointPatch(invoke);
5631*795d594fSAndroid Build Coastguard Worker       } else {
5632*795d594fSAndroid Build Coastguard Worker         // (callee_method + offset_of_jni_entry_point)()
5633*795d594fSAndroid Build Coastguard Worker         __ call(Address(callee_method.AsRegister<Register>(),
5634*795d594fSAndroid Build Coastguard Worker                         ArtMethod::EntryPointFromJniOffset(kX86PointerSize).Int32Value()));
5635*795d594fSAndroid Build Coastguard Worker       }
5636*795d594fSAndroid Build Coastguard Worker       RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5637*795d594fSAndroid Build Coastguard Worker       if (out_frame_size == 0u && DataType::IsFloatingPointType(invoke->GetType())) {
5638*795d594fSAndroid Build Coastguard Worker         // Create space for conversion.
5639*795d594fSAndroid Build Coastguard Worker         out_frame_size = 8u;
5640*795d594fSAndroid Build Coastguard Worker         IncreaseFrame(out_frame_size);
5641*795d594fSAndroid Build Coastguard Worker       }
5642*795d594fSAndroid Build Coastguard Worker       // Zero-/sign-extend or move the result when needed due to native and managed ABI mismatch.
5643*795d594fSAndroid Build Coastguard Worker       switch (invoke->GetType()) {
5644*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kBool:
5645*795d594fSAndroid Build Coastguard Worker           __ movzxb(EAX, AL);
5646*795d594fSAndroid Build Coastguard Worker           break;
5647*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt8:
5648*795d594fSAndroid Build Coastguard Worker           __ movsxb(EAX, AL);
5649*795d594fSAndroid Build Coastguard Worker           break;
5650*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kUint16:
5651*795d594fSAndroid Build Coastguard Worker           __ movzxw(EAX, EAX);
5652*795d594fSAndroid Build Coastguard Worker           break;
5653*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt16:
5654*795d594fSAndroid Build Coastguard Worker           __ movsxw(EAX, EAX);
5655*795d594fSAndroid Build Coastguard Worker           break;
5656*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat32:
5657*795d594fSAndroid Build Coastguard Worker           __ fstps(Address(ESP, 0));
5658*795d594fSAndroid Build Coastguard Worker           __ movss(XMM0, Address(ESP, 0));
5659*795d594fSAndroid Build Coastguard Worker           break;
5660*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kFloat64:
5661*795d594fSAndroid Build Coastguard Worker           __ fstpl(Address(ESP, 0));
5662*795d594fSAndroid Build Coastguard Worker           __ movsd(XMM0, Address(ESP, 0));
5663*795d594fSAndroid Build Coastguard Worker           break;
5664*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt32:
5665*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kInt64:
5666*795d594fSAndroid Build Coastguard Worker         case DataType::Type::kVoid:
5667*795d594fSAndroid Build Coastguard Worker           break;
5668*795d594fSAndroid Build Coastguard Worker         default:
5669*795d594fSAndroid Build Coastguard Worker           DCHECK(false) << invoke->GetType();
5670*795d594fSAndroid Build Coastguard Worker           break;
5671*795d594fSAndroid Build Coastguard Worker       }
5672*795d594fSAndroid Build Coastguard Worker       if (out_frame_size != 0u) {
5673*795d594fSAndroid Build Coastguard Worker         DecreaseFrame(out_frame_size);
5674*795d594fSAndroid Build Coastguard Worker       }
5675*795d594fSAndroid Build Coastguard Worker       break;
5676*795d594fSAndroid Build Coastguard Worker     }
5677*795d594fSAndroid Build Coastguard Worker     case CodePtrLocation::kCallArtMethod:
5678*795d594fSAndroid Build Coastguard Worker       // (callee_method + offset_of_quick_compiled_code)()
5679*795d594fSAndroid Build Coastguard Worker       __ call(Address(callee_method.AsRegister<Register>(),
5680*795d594fSAndroid Build Coastguard Worker                       ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5681*795d594fSAndroid Build Coastguard Worker                           kX86PointerSize).Int32Value()));
5682*795d594fSAndroid Build Coastguard Worker       RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5683*795d594fSAndroid Build Coastguard Worker       break;
5684*795d594fSAndroid Build Coastguard Worker   }
5685*795d594fSAndroid Build Coastguard Worker 
5686*795d594fSAndroid Build Coastguard Worker   DCHECK(!IsLeafMethod());
5687*795d594fSAndroid Build Coastguard Worker }
5688*795d594fSAndroid Build Coastguard Worker 
GenerateVirtualCall(HInvokeVirtual * invoke,Location temp_in,SlowPathCode * slow_path)5689*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateVirtualCall(
5690*795d594fSAndroid Build Coastguard Worker     HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
5691*795d594fSAndroid Build Coastguard Worker   Register temp = temp_in.AsRegister<Register>();
5692*795d594fSAndroid Build Coastguard Worker   uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5693*795d594fSAndroid Build Coastguard Worker       invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
5694*795d594fSAndroid Build Coastguard Worker 
5695*795d594fSAndroid Build Coastguard Worker   // Use the calling convention instead of the location of the receiver, as
5696*795d594fSAndroid Build Coastguard Worker   // intrinsics may have put the receiver in a different register. In the intrinsics
5697*795d594fSAndroid Build Coastguard Worker   // slow path, the arguments have been moved to the right place, so here we are
5698*795d594fSAndroid Build Coastguard Worker   // guaranteed that the receiver is the first register of the calling convention.
5699*795d594fSAndroid Build Coastguard Worker   InvokeDexCallingConvention calling_convention;
5700*795d594fSAndroid Build Coastguard Worker   Register receiver = calling_convention.GetRegisterAt(0);
5701*795d594fSAndroid Build Coastguard Worker   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5702*795d594fSAndroid Build Coastguard Worker   // /* HeapReference<Class> */ temp = receiver->klass_
5703*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(receiver, class_offset));
5704*795d594fSAndroid Build Coastguard Worker   MaybeRecordImplicitNullCheck(invoke);
5705*795d594fSAndroid Build Coastguard Worker   // Instead of simply (possibly) unpoisoning `temp` here, we should
5706*795d594fSAndroid Build Coastguard Worker   // emit a read barrier for the previous class reference load.
5707*795d594fSAndroid Build Coastguard Worker   // However this is not required in practice, as this is an
5708*795d594fSAndroid Build Coastguard Worker   // intermediate/temporary reference and because the current
5709*795d594fSAndroid Build Coastguard Worker   // concurrent copying collector keeps the from-space memory
5710*795d594fSAndroid Build Coastguard Worker   // intact/accessible until the end of the marking phase (the
5711*795d594fSAndroid Build Coastguard Worker   // concurrent copying collector may not in the future).
5712*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(temp);
5713*795d594fSAndroid Build Coastguard Worker 
5714*795d594fSAndroid Build Coastguard Worker   MaybeGenerateInlineCacheCheck(invoke, temp);
5715*795d594fSAndroid Build Coastguard Worker 
5716*795d594fSAndroid Build Coastguard Worker   // temp = temp->GetMethodAt(method_offset);
5717*795d594fSAndroid Build Coastguard Worker   __ movl(temp, Address(temp, method_offset));
5718*795d594fSAndroid Build Coastguard Worker   // call temp->GetEntryPoint();
5719*795d594fSAndroid Build Coastguard Worker   __ call(Address(
5720*795d594fSAndroid Build Coastguard Worker       temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86PointerSize).Int32Value()));
5721*795d594fSAndroid Build Coastguard Worker   RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5722*795d594fSAndroid Build Coastguard Worker }
5723*795d594fSAndroid Build Coastguard Worker 
RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress * method_address,uint32_t intrinsic_data)5724*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress* method_address,
5725*795d594fSAndroid Build Coastguard Worker                                                      uint32_t intrinsic_data) {
5726*795d594fSAndroid Build Coastguard Worker   boot_image_other_patches_.emplace_back(
5727*795d594fSAndroid Build Coastguard Worker       method_address, /* target_dex_file= */ nullptr, intrinsic_data);
5728*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_other_patches_.back().label);
5729*795d594fSAndroid Build Coastguard Worker }
5730*795d594fSAndroid Build Coastguard Worker 
RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress * method_address,uint32_t boot_image_offset)5731*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
5732*795d594fSAndroid Build Coastguard Worker                                                  uint32_t boot_image_offset) {
5733*795d594fSAndroid Build Coastguard Worker   boot_image_other_patches_.emplace_back(
5734*795d594fSAndroid Build Coastguard Worker       method_address, /* target_dex_file= */ nullptr, boot_image_offset);
5735*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_other_patches_.back().label);
5736*795d594fSAndroid Build Coastguard Worker }
5737*795d594fSAndroid Build Coastguard Worker 
RecordBootImageMethodPatch(HInvoke * invoke)5738*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageMethodPatch(HInvoke* invoke) {
5739*795d594fSAndroid Build Coastguard Worker   size_t index = invoke->IsInvokeInterface()
5740*795d594fSAndroid Build Coastguard Worker       ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5741*795d594fSAndroid Build Coastguard Worker       : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
5742*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5743*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
5744*795d594fSAndroid Build Coastguard Worker   boot_image_method_patches_.emplace_back(
5745*795d594fSAndroid Build Coastguard Worker       method_address,
5746*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().dex_file,
5747*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().index);
5748*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_method_patches_.back().label);
5749*795d594fSAndroid Build Coastguard Worker }
5750*795d594fSAndroid Build Coastguard Worker 
RecordAppImageMethodPatch(HInvoke * invoke)5751*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordAppImageMethodPatch(HInvoke* invoke) {
5752*795d594fSAndroid Build Coastguard Worker   size_t index = invoke->IsInvokeInterface()
5753*795d594fSAndroid Build Coastguard Worker       ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5754*795d594fSAndroid Build Coastguard Worker       : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
5755*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5756*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
5757*795d594fSAndroid Build Coastguard Worker   app_image_method_patches_.emplace_back(
5758*795d594fSAndroid Build Coastguard Worker       method_address,
5759*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().dex_file,
5760*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().index);
5761*795d594fSAndroid Build Coastguard Worker   __ Bind(&app_image_method_patches_.back().label);
5762*795d594fSAndroid Build Coastguard Worker }
5763*795d594fSAndroid Build Coastguard Worker 
RecordMethodBssEntryPatch(HInvoke * invoke)5764*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordMethodBssEntryPatch(HInvoke* invoke) {
5765*795d594fSAndroid Build Coastguard Worker   size_t index = invoke->IsInvokeInterface()
5766*795d594fSAndroid Build Coastguard Worker       ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5767*795d594fSAndroid Build Coastguard Worker       : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
5768*795d594fSAndroid Build Coastguard Worker   DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file) ||
5769*795d594fSAndroid Build Coastguard Worker          GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file) ||
5770*795d594fSAndroid Build Coastguard Worker          ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(),
5771*795d594fSAndroid Build Coastguard Worker                          invoke->GetMethodReference().dex_file));
5772*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5773*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
5774*795d594fSAndroid Build Coastguard Worker   // Add the patch entry and bind its label at the end of the instruction.
5775*795d594fSAndroid Build Coastguard Worker   method_bss_entry_patches_.emplace_back(
5776*795d594fSAndroid Build Coastguard Worker       method_address,
5777*795d594fSAndroid Build Coastguard Worker       invoke->GetMethodReference().dex_file,
5778*795d594fSAndroid Build Coastguard Worker       invoke->GetMethodReference().index);
5779*795d594fSAndroid Build Coastguard Worker   __ Bind(&method_bss_entry_patches_.back().label);
5780*795d594fSAndroid Build Coastguard Worker }
5781*795d594fSAndroid Build Coastguard Worker 
RecordBootImageTypePatch(HLoadClass * load_class)5782*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageTypePatch(HLoadClass* load_class) {
5783*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5784*795d594fSAndroid Build Coastguard Worker       load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
5785*795d594fSAndroid Build Coastguard Worker   boot_image_type_patches_.emplace_back(
5786*795d594fSAndroid Build Coastguard Worker       method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
5787*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_type_patches_.back().label);
5788*795d594fSAndroid Build Coastguard Worker }
5789*795d594fSAndroid Build Coastguard Worker 
RecordAppImageTypePatch(HLoadClass * load_class)5790*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordAppImageTypePatch(HLoadClass* load_class) {
5791*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5792*795d594fSAndroid Build Coastguard Worker       load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
5793*795d594fSAndroid Build Coastguard Worker   app_image_type_patches_.emplace_back(
5794*795d594fSAndroid Build Coastguard Worker       method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
5795*795d594fSAndroid Build Coastguard Worker   __ Bind(&app_image_type_patches_.back().label);
5796*795d594fSAndroid Build Coastguard Worker }
5797*795d594fSAndroid Build Coastguard Worker 
NewTypeBssEntryPatch(HLoadClass * load_class)5798*795d594fSAndroid Build Coastguard Worker Label* CodeGeneratorX86::NewTypeBssEntryPatch(HLoadClass* load_class) {
5799*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5800*795d594fSAndroid Build Coastguard Worker       load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
5801*795d594fSAndroid Build Coastguard Worker   ArenaDeque<X86PcRelativePatchInfo>* patches = nullptr;
5802*795d594fSAndroid Build Coastguard Worker   switch (load_class->GetLoadKind()) {
5803*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntry:
5804*795d594fSAndroid Build Coastguard Worker       patches = &type_bss_entry_patches_;
5805*795d594fSAndroid Build Coastguard Worker       break;
5806*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPublic:
5807*795d594fSAndroid Build Coastguard Worker       patches = &public_type_bss_entry_patches_;
5808*795d594fSAndroid Build Coastguard Worker       break;
5809*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPackage:
5810*795d594fSAndroid Build Coastguard Worker       patches = &package_type_bss_entry_patches_;
5811*795d594fSAndroid Build Coastguard Worker       break;
5812*795d594fSAndroid Build Coastguard Worker     default:
5813*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unexpected load kind: " << load_class->GetLoadKind();
5814*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
5815*795d594fSAndroid Build Coastguard Worker   }
5816*795d594fSAndroid Build Coastguard Worker   patches->emplace_back(
5817*795d594fSAndroid Build Coastguard Worker       method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
5818*795d594fSAndroid Build Coastguard Worker   return &patches->back().label;
5819*795d594fSAndroid Build Coastguard Worker }
5820*795d594fSAndroid Build Coastguard Worker 
RecordBootImageStringPatch(HLoadString * load_string)5821*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageStringPatch(HLoadString* load_string) {
5822*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5823*795d594fSAndroid Build Coastguard Worker       load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
5824*795d594fSAndroid Build Coastguard Worker   boot_image_string_patches_.emplace_back(
5825*795d594fSAndroid Build Coastguard Worker       method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
5826*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_string_patches_.back().label);
5827*795d594fSAndroid Build Coastguard Worker }
5828*795d594fSAndroid Build Coastguard Worker 
NewStringBssEntryPatch(HLoadString * load_string)5829*795d594fSAndroid Build Coastguard Worker Label* CodeGeneratorX86::NewStringBssEntryPatch(HLoadString* load_string) {
5830*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5831*795d594fSAndroid Build Coastguard Worker       load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
5832*795d594fSAndroid Build Coastguard Worker   string_bss_entry_patches_.emplace_back(
5833*795d594fSAndroid Build Coastguard Worker       method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
5834*795d594fSAndroid Build Coastguard Worker   return &string_bss_entry_patches_.back().label;
5835*795d594fSAndroid Build Coastguard Worker }
5836*795d594fSAndroid Build Coastguard Worker 
RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect * invoke)5837*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke) {
5838*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* method_address =
5839*795d594fSAndroid Build Coastguard Worker       invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5840*795d594fSAndroid Build Coastguard Worker   boot_image_jni_entrypoint_patches_.emplace_back(
5841*795d594fSAndroid Build Coastguard Worker       method_address,
5842*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().dex_file,
5843*795d594fSAndroid Build Coastguard Worker       invoke->GetResolvedMethodReference().index);
5844*795d594fSAndroid Build Coastguard Worker   __ Bind(&boot_image_jni_entrypoint_patches_.back().label);
5845*795d594fSAndroid Build Coastguard Worker }
5846*795d594fSAndroid Build Coastguard Worker 
LoadBootImageAddress(Register reg,uint32_t boot_image_reference,HInvokeStaticOrDirect * invoke)5847*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::LoadBootImageAddress(Register reg,
5848*795d594fSAndroid Build Coastguard Worker                                             uint32_t boot_image_reference,
5849*795d594fSAndroid Build Coastguard Worker                                             HInvokeStaticOrDirect* invoke) {
5850*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().IsBootImage()) {
5851*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* method_address =
5852*795d594fSAndroid Build Coastguard Worker         invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5853*795d594fSAndroid Build Coastguard Worker     DCHECK(method_address != nullptr);
5854*795d594fSAndroid Build Coastguard Worker     Register method_address_reg =
5855*795d594fSAndroid Build Coastguard Worker         invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
5856*795d594fSAndroid Build Coastguard Worker     __ leal(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5857*795d594fSAndroid Build Coastguard Worker     RecordBootImageIntrinsicPatch(method_address, boot_image_reference);
5858*795d594fSAndroid Build Coastguard Worker   } else if (GetCompilerOptions().GetCompilePic()) {
5859*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* method_address =
5860*795d594fSAndroid Build Coastguard Worker         invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5861*795d594fSAndroid Build Coastguard Worker     DCHECK(method_address != nullptr);
5862*795d594fSAndroid Build Coastguard Worker     Register method_address_reg =
5863*795d594fSAndroid Build Coastguard Worker         invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
5864*795d594fSAndroid Build Coastguard Worker     __ movl(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5865*795d594fSAndroid Build Coastguard Worker     RecordBootImageRelRoPatch(method_address, boot_image_reference);
5866*795d594fSAndroid Build Coastguard Worker   } else {
5867*795d594fSAndroid Build Coastguard Worker     DCHECK(GetCompilerOptions().IsJitCompiler());
5868*795d594fSAndroid Build Coastguard Worker     gc::Heap* heap = Runtime::Current()->GetHeap();
5869*795d594fSAndroid Build Coastguard Worker     DCHECK(!heap->GetBootImageSpaces().empty());
5870*795d594fSAndroid Build Coastguard Worker     const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_reference;
5871*795d594fSAndroid Build Coastguard Worker     __ movl(reg, Immediate(dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(address))));
5872*795d594fSAndroid Build Coastguard Worker   }
5873*795d594fSAndroid Build Coastguard Worker }
5874*795d594fSAndroid Build Coastguard Worker 
LoadIntrinsicDeclaringClass(Register reg,HInvokeStaticOrDirect * invoke)5875*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::LoadIntrinsicDeclaringClass(Register reg, HInvokeStaticOrDirect* invoke) {
5876*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(invoke->GetIntrinsic(), Intrinsics::kNone);
5877*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().IsBootImage()) {
5878*795d594fSAndroid Build Coastguard Worker     // Load the type the same way as for HLoadClass::LoadKind::kBootImageLinkTimePcRelative.
5879*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* method_address =
5880*795d594fSAndroid Build Coastguard Worker         invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5881*795d594fSAndroid Build Coastguard Worker     DCHECK(method_address != nullptr);
5882*795d594fSAndroid Build Coastguard Worker     Register method_address_reg =
5883*795d594fSAndroid Build Coastguard Worker         invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
5884*795d594fSAndroid Build Coastguard Worker     __ leal(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5885*795d594fSAndroid Build Coastguard Worker     MethodReference target_method = invoke->GetResolvedMethodReference();
5886*795d594fSAndroid Build Coastguard Worker     dex::TypeIndex type_idx = target_method.dex_file->GetMethodId(target_method.index).class_idx_;
5887*795d594fSAndroid Build Coastguard Worker     boot_image_type_patches_.emplace_back(method_address, target_method.dex_file, type_idx.index_);
5888*795d594fSAndroid Build Coastguard Worker     __ Bind(&boot_image_type_patches_.back().label);
5889*795d594fSAndroid Build Coastguard Worker   } else {
5890*795d594fSAndroid Build Coastguard Worker     uint32_t boot_image_offset = GetBootImageOffsetOfIntrinsicDeclaringClass(invoke);
5891*795d594fSAndroid Build Coastguard Worker     LoadBootImageAddress(reg, boot_image_offset, invoke);
5892*795d594fSAndroid Build Coastguard Worker   }
5893*795d594fSAndroid Build Coastguard Worker }
5894*795d594fSAndroid Build Coastguard Worker 
5895*795d594fSAndroid Build Coastguard Worker // The label points to the end of the "movl" or another instruction but the literal offset
5896*795d594fSAndroid Build Coastguard Worker // for method patch needs to point to the embedded constant which occupies the last 4 bytes.
5897*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
5898*795d594fSAndroid Build Coastguard Worker 
5899*795d594fSAndroid Build Coastguard Worker template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
EmitPcRelativeLinkerPatches(const ArenaDeque<X86PcRelativePatchInfo> & infos,ArenaVector<linker::LinkerPatch> * linker_patches)5900*795d594fSAndroid Build Coastguard Worker inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches(
5901*795d594fSAndroid Build Coastguard Worker     const ArenaDeque<X86PcRelativePatchInfo>& infos,
5902*795d594fSAndroid Build Coastguard Worker     ArenaVector<linker::LinkerPatch>* linker_patches) {
5903*795d594fSAndroid Build Coastguard Worker   for (const X86PcRelativePatchInfo& info : infos) {
5904*795d594fSAndroid Build Coastguard Worker     uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
5905*795d594fSAndroid Build Coastguard Worker     linker_patches->push_back(Factory(literal_offset,
5906*795d594fSAndroid Build Coastguard Worker                                       info.target_dex_file,
5907*795d594fSAndroid Build Coastguard Worker                                       GetMethodAddressOffset(info.method_address),
5908*795d594fSAndroid Build Coastguard Worker                                       info.offset_or_index));
5909*795d594fSAndroid Build Coastguard Worker   }
5910*795d594fSAndroid Build Coastguard Worker }
5911*795d594fSAndroid Build Coastguard Worker 
5912*795d594fSAndroid Build Coastguard Worker template <linker::LinkerPatch (*Factory)(size_t, uint32_t, uint32_t)>
NoDexFileAdapter(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,uint32_t boot_image_offset)5913*795d594fSAndroid Build Coastguard Worker linker::LinkerPatch NoDexFileAdapter(size_t literal_offset,
5914*795d594fSAndroid Build Coastguard Worker                                      const DexFile* target_dex_file,
5915*795d594fSAndroid Build Coastguard Worker                                      uint32_t pc_insn_offset,
5916*795d594fSAndroid Build Coastguard Worker                                      uint32_t boot_image_offset) {
5917*795d594fSAndroid Build Coastguard Worker   DCHECK(target_dex_file == nullptr);  // Unused for these patches, should be null.
5918*795d594fSAndroid Build Coastguard Worker   return Factory(literal_offset, pc_insn_offset, boot_image_offset);
5919*795d594fSAndroid Build Coastguard Worker }
5920*795d594fSAndroid Build Coastguard Worker 
EmitLinkerPatches(ArenaVector<linker::LinkerPatch> * linker_patches)5921*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
5922*795d594fSAndroid Build Coastguard Worker   DCHECK(linker_patches->empty());
5923*795d594fSAndroid Build Coastguard Worker   size_t size =
5924*795d594fSAndroid Build Coastguard Worker       boot_image_method_patches_.size() +
5925*795d594fSAndroid Build Coastguard Worker       app_image_method_patches_.size() +
5926*795d594fSAndroid Build Coastguard Worker       method_bss_entry_patches_.size() +
5927*795d594fSAndroid Build Coastguard Worker       boot_image_type_patches_.size() +
5928*795d594fSAndroid Build Coastguard Worker       app_image_type_patches_.size() +
5929*795d594fSAndroid Build Coastguard Worker       type_bss_entry_patches_.size() +
5930*795d594fSAndroid Build Coastguard Worker       public_type_bss_entry_patches_.size() +
5931*795d594fSAndroid Build Coastguard Worker       package_type_bss_entry_patches_.size() +
5932*795d594fSAndroid Build Coastguard Worker       boot_image_string_patches_.size() +
5933*795d594fSAndroid Build Coastguard Worker       string_bss_entry_patches_.size() +
5934*795d594fSAndroid Build Coastguard Worker       boot_image_jni_entrypoint_patches_.size() +
5935*795d594fSAndroid Build Coastguard Worker       boot_image_other_patches_.size();
5936*795d594fSAndroid Build Coastguard Worker   linker_patches->reserve(size);
5937*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
5938*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
5939*795d594fSAndroid Build Coastguard Worker         boot_image_method_patches_, linker_patches);
5940*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
5941*795d594fSAndroid Build Coastguard Worker         boot_image_type_patches_, linker_patches);
5942*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
5943*795d594fSAndroid Build Coastguard Worker         boot_image_string_patches_, linker_patches);
5944*795d594fSAndroid Build Coastguard Worker   } else {
5945*795d594fSAndroid Build Coastguard Worker     DCHECK(boot_image_method_patches_.empty());
5946*795d594fSAndroid Build Coastguard Worker     DCHECK(boot_image_type_patches_.empty());
5947*795d594fSAndroid Build Coastguard Worker     DCHECK(boot_image_string_patches_.empty());
5948*795d594fSAndroid Build Coastguard Worker   }
5949*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!GetCompilerOptions().IsAppImage(), app_image_method_patches_.empty());
5950*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(!GetCompilerOptions().IsAppImage(), app_image_type_patches_.empty());
5951*795d594fSAndroid Build Coastguard Worker   if (GetCompilerOptions().IsBootImage()) {
5952*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::IntrinsicReferencePatch>>(
5953*795d594fSAndroid Build Coastguard Worker         boot_image_other_patches_, linker_patches);
5954*795d594fSAndroid Build Coastguard Worker   } else {
5955*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::BootImageRelRoPatch>>(
5956*795d594fSAndroid Build Coastguard Worker         boot_image_other_patches_, linker_patches);
5957*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodAppImageRelRoPatch>(
5958*795d594fSAndroid Build Coastguard Worker         app_image_method_patches_, linker_patches);
5959*795d594fSAndroid Build Coastguard Worker     EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeAppImageRelRoPatch>(
5960*795d594fSAndroid Build Coastguard Worker         app_image_type_patches_, linker_patches);
5961*795d594fSAndroid Build Coastguard Worker   }
5962*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
5963*795d594fSAndroid Build Coastguard Worker       method_bss_entry_patches_, linker_patches);
5964*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
5965*795d594fSAndroid Build Coastguard Worker       type_bss_entry_patches_, linker_patches);
5966*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::PublicTypeBssEntryPatch>(
5967*795d594fSAndroid Build Coastguard Worker       public_type_bss_entry_patches_, linker_patches);
5968*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::PackageTypeBssEntryPatch>(
5969*795d594fSAndroid Build Coastguard Worker       package_type_bss_entry_patches_, linker_patches);
5970*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
5971*795d594fSAndroid Build Coastguard Worker       string_bss_entry_patches_, linker_patches);
5972*795d594fSAndroid Build Coastguard Worker   EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeJniEntrypointPatch>(
5973*795d594fSAndroid Build Coastguard Worker       boot_image_jni_entrypoint_patches_, linker_patches);
5974*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(size, linker_patches->size());
5975*795d594fSAndroid Build Coastguard Worker }
5976*795d594fSAndroid Build Coastguard Worker 
MaybeMarkGCCard(Register temp,Register card,Register object,Register value,bool emit_null_check)5977*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MaybeMarkGCCard(
5978*795d594fSAndroid Build Coastguard Worker     Register temp, Register card, Register object, Register value, bool emit_null_check) {
5979*795d594fSAndroid Build Coastguard Worker   NearLabel is_null;
5980*795d594fSAndroid Build Coastguard Worker   if (emit_null_check) {
5981*795d594fSAndroid Build Coastguard Worker     __ testl(value, value);
5982*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &is_null);
5983*795d594fSAndroid Build Coastguard Worker   }
5984*795d594fSAndroid Build Coastguard Worker   MarkGCCard(temp, card, object);
5985*795d594fSAndroid Build Coastguard Worker   if (emit_null_check) {
5986*795d594fSAndroid Build Coastguard Worker     __ Bind(&is_null);
5987*795d594fSAndroid Build Coastguard Worker   }
5988*795d594fSAndroid Build Coastguard Worker }
5989*795d594fSAndroid Build Coastguard Worker 
MarkGCCard(Register temp,Register card,Register object)5990*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object) {
5991*795d594fSAndroid Build Coastguard Worker   // Load the address of the card table into `card`.
5992*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86PointerSize>().Int32Value()));
5993*795d594fSAndroid Build Coastguard Worker   // Calculate the offset (in the card table) of the card corresponding to `object`.
5994*795d594fSAndroid Build Coastguard Worker   __ movl(temp, object);
5995*795d594fSAndroid Build Coastguard Worker   __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
5996*795d594fSAndroid Build Coastguard Worker   // Write the `art::gc::accounting::CardTable::kCardDirty` value into the
5997*795d594fSAndroid Build Coastguard Worker   // `object`'s card.
5998*795d594fSAndroid Build Coastguard Worker   //
5999*795d594fSAndroid Build Coastguard Worker   // Register `card` contains the address of the card table. Note that the card
6000*795d594fSAndroid Build Coastguard Worker   // table's base is biased during its creation so that it always starts at an
6001*795d594fSAndroid Build Coastguard Worker   // address whose least-significant byte is equal to `kCardDirty` (see
6002*795d594fSAndroid Build Coastguard Worker   // art::gc::accounting::CardTable::Create). Therefore the MOVB instruction
6003*795d594fSAndroid Build Coastguard Worker   // below writes the `kCardDirty` (byte) value into the `object`'s card
6004*795d594fSAndroid Build Coastguard Worker   // (located at `card + object >> kCardShift`).
6005*795d594fSAndroid Build Coastguard Worker   //
6006*795d594fSAndroid Build Coastguard Worker   // This dual use of the value in register `card` (1. to calculate the location
6007*795d594fSAndroid Build Coastguard Worker   // of the card to mark; and 2. to load the `kCardDirty` value) saves a load
6008*795d594fSAndroid Build Coastguard Worker   // (no need to explicitly load `kCardDirty` as an immediate value).
6009*795d594fSAndroid Build Coastguard Worker   __ movb(Address(temp, card, TIMES_1, 0),
6010*795d594fSAndroid Build Coastguard Worker           X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
6011*795d594fSAndroid Build Coastguard Worker }
6012*795d594fSAndroid Build Coastguard Worker 
CheckGCCardIsValid(Register temp,Register card,Register object)6013*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::CheckGCCardIsValid(Register temp, Register card, Register object) {
6014*795d594fSAndroid Build Coastguard Worker   NearLabel done;
6015*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
6016*795d594fSAndroid Build Coastguard Worker   // Load the address of the card table into `card`.
6017*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86PointerSize>().Int32Value()));
6018*795d594fSAndroid Build Coastguard Worker   // Calculate the offset (in the card table) of the card corresponding to `object`.
6019*795d594fSAndroid Build Coastguard Worker   __ movl(temp, object);
6020*795d594fSAndroid Build Coastguard Worker   __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
6021*795d594fSAndroid Build Coastguard Worker   // assert (!clean || !self->is_gc_marking)
6022*795d594fSAndroid Build Coastguard Worker   __ cmpb(Address(temp, card, TIMES_1, 0), Immediate(gc::accounting::CardTable::kCardClean));
6023*795d594fSAndroid Build Coastguard Worker   __ j(kNotEqual, &done);
6024*795d594fSAndroid Build Coastguard Worker   __ fs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86PointerSize>()), Immediate(0));
6025*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, &done);
6026*795d594fSAndroid Build Coastguard Worker   __ int3();
6027*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
6028*795d594fSAndroid Build Coastguard Worker }
6029*795d594fSAndroid Build Coastguard Worker 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)6030*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
6031*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
6032*795d594fSAndroid Build Coastguard Worker 
6033*795d594fSAndroid Build Coastguard Worker   bool object_field_get_with_read_barrier =
6034*795d594fSAndroid Build Coastguard Worker       (instruction->GetType() == DataType::Type::kReference) && codegen_->EmitReadBarrier();
6035*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
6036*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction,
6037*795d594fSAndroid Build Coastguard Worker                                                        codegen_->EmitReadBarrier()
6038*795d594fSAndroid Build Coastguard Worker                                                            ? LocationSummary::kCallOnSlowPath
6039*795d594fSAndroid Build Coastguard Worker                                                            : LocationSummary::kNoCall);
6040*795d594fSAndroid Build Coastguard Worker   if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
6041*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
6042*795d594fSAndroid Build Coastguard Worker   }
6043*795d594fSAndroid Build Coastguard Worker   // receiver_input
6044*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
6045*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(instruction->GetType())) {
6046*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresFpuRegister());
6047*795d594fSAndroid Build Coastguard Worker   } else {
6048*795d594fSAndroid Build Coastguard Worker     // The output overlaps in case of long: we don't want the low move
6049*795d594fSAndroid Build Coastguard Worker     // to overwrite the object's location.  Likewise, in the case of
6050*795d594fSAndroid Build Coastguard Worker     // an object field get with read barriers enabled, we do not want
6051*795d594fSAndroid Build Coastguard Worker     // the move to overwrite the object's location, as we need it to emit
6052*795d594fSAndroid Build Coastguard Worker     // the read barrier.
6053*795d594fSAndroid Build Coastguard Worker     locations->SetOut(
6054*795d594fSAndroid Build Coastguard Worker         Location::RequiresRegister(),
6055*795d594fSAndroid Build Coastguard Worker         (object_field_get_with_read_barrier || instruction->GetType() == DataType::Type::kInt64)
6056*795d594fSAndroid Build Coastguard Worker             ? Location::kOutputOverlap
6057*795d594fSAndroid Build Coastguard Worker             : Location::kNoOutputOverlap);
6058*795d594fSAndroid Build Coastguard Worker   }
6059*795d594fSAndroid Build Coastguard Worker 
6060*795d594fSAndroid Build Coastguard Worker   if (field_info.IsVolatile() && (field_info.GetFieldType() == DataType::Type::kInt64)) {
6061*795d594fSAndroid Build Coastguard Worker     // Long values can be loaded atomically into an XMM using movsd.
6062*795d594fSAndroid Build Coastguard Worker     // So we use an XMM register as a temp to achieve atomicity (first
6063*795d594fSAndroid Build Coastguard Worker     // load the temp into the XMM and then copy the XMM into the
6064*795d594fSAndroid Build Coastguard Worker     // output, 32 bits at a time).
6065*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
6066*795d594fSAndroid Build Coastguard Worker   }
6067*795d594fSAndroid Build Coastguard Worker }
6068*795d594fSAndroid Build Coastguard Worker 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)6069*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
6070*795d594fSAndroid Build Coastguard Worker                                                  const FieldInfo& field_info) {
6071*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
6072*795d594fSAndroid Build Coastguard Worker 
6073*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6074*795d594fSAndroid Build Coastguard Worker   Location base_loc = locations->InAt(0);
6075*795d594fSAndroid Build Coastguard Worker   Register base = base_loc.AsRegister<Register>();
6076*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
6077*795d594fSAndroid Build Coastguard Worker   bool is_volatile = field_info.IsVolatile();
6078*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
6079*795d594fSAndroid Build Coastguard Worker   DataType::Type load_type = instruction->GetType();
6080*795d594fSAndroid Build Coastguard Worker   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
6081*795d594fSAndroid Build Coastguard Worker 
6082*795d594fSAndroid Build Coastguard Worker   if (load_type == DataType::Type::kReference) {
6083*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Object> */ out = *(base + offset)
6084*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
6085*795d594fSAndroid Build Coastguard Worker       // Note that a potential implicit null check is handled in this
6086*795d594fSAndroid Build Coastguard Worker       // CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier call.
6087*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(
6088*795d594fSAndroid Build Coastguard Worker           instruction, out, base, offset, /* needs_null_check= */ true);
6089*795d594fSAndroid Build Coastguard Worker       if (is_volatile) {
6090*795d594fSAndroid Build Coastguard Worker         codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6091*795d594fSAndroid Build Coastguard Worker       }
6092*795d594fSAndroid Build Coastguard Worker     } else {
6093*795d594fSAndroid Build Coastguard Worker       __ movl(out.AsRegister<Register>(), Address(base, offset));
6094*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6095*795d594fSAndroid Build Coastguard Worker       if (is_volatile) {
6096*795d594fSAndroid Build Coastguard Worker         codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6097*795d594fSAndroid Build Coastguard Worker       }
6098*795d594fSAndroid Build Coastguard Worker       // If read barriers are enabled, emit read barriers other than
6099*795d594fSAndroid Build Coastguard Worker       // Baker's using a slow path (and also unpoison the loaded
6100*795d594fSAndroid Build Coastguard Worker       // reference, if heap poisoning is enabled).
6101*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
6102*795d594fSAndroid Build Coastguard Worker     }
6103*795d594fSAndroid Build Coastguard Worker   } else {
6104*795d594fSAndroid Build Coastguard Worker     Address src(base, offset);
6105*795d594fSAndroid Build Coastguard Worker     XmmRegister temp = (load_type == DataType::Type::kInt64 && is_volatile)
6106*795d594fSAndroid Build Coastguard Worker         ? locations->GetTemp(0).AsFpuRegister<XmmRegister>()
6107*795d594fSAndroid Build Coastguard Worker         : kNoXmmRegister;
6108*795d594fSAndroid Build Coastguard Worker     codegen_->LoadFromMemoryNoBarrier(load_type, out, src, instruction, temp, is_volatile);
6109*795d594fSAndroid Build Coastguard Worker     if (is_volatile) {
6110*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6111*795d594fSAndroid Build Coastguard Worker     }
6112*795d594fSAndroid Build Coastguard Worker   }
6113*795d594fSAndroid Build Coastguard Worker }
6114*795d594fSAndroid Build Coastguard Worker 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info,WriteBarrierKind write_barrier_kind)6115*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction,
6116*795d594fSAndroid Build Coastguard Worker                                          const FieldInfo& field_info,
6117*795d594fSAndroid Build Coastguard Worker                                          WriteBarrierKind write_barrier_kind) {
6118*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
6119*795d594fSAndroid Build Coastguard Worker 
6120*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
6121*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
6122*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
6123*795d594fSAndroid Build Coastguard Worker   bool is_volatile = field_info.IsVolatile();
6124*795d594fSAndroid Build Coastguard Worker   DataType::Type field_type = field_info.GetFieldType();
6125*795d594fSAndroid Build Coastguard Worker   bool is_byte_type = DataType::Size(field_type) == 1u;
6126*795d594fSAndroid Build Coastguard Worker 
6127*795d594fSAndroid Build Coastguard Worker   // The register allocator does not support multiple
6128*795d594fSAndroid Build Coastguard Worker   // inputs that die at entry with one in a specific register.
6129*795d594fSAndroid Build Coastguard Worker   if (is_byte_type) {
6130*795d594fSAndroid Build Coastguard Worker     // Ensure the value is in a byte register.
6131*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RegisterLocation(EAX));
6132*795d594fSAndroid Build Coastguard Worker   } else if (DataType::IsFloatingPointType(field_type)) {
6133*795d594fSAndroid Build Coastguard Worker     if (is_volatile && field_type == DataType::Type::kFloat64) {
6134*795d594fSAndroid Build Coastguard Worker       // In order to satisfy the semantics of volatile, this must be a single instruction store.
6135*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::RequiresFpuRegister());
6136*795d594fSAndroid Build Coastguard Worker     } else {
6137*795d594fSAndroid Build Coastguard Worker       locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
6138*795d594fSAndroid Build Coastguard Worker     }
6139*795d594fSAndroid Build Coastguard Worker   } else if (is_volatile && field_type == DataType::Type::kInt64) {
6140*795d594fSAndroid Build Coastguard Worker     // In order to satisfy the semantics of volatile, this must be a single instruction store.
6141*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
6142*795d594fSAndroid Build Coastguard Worker 
6143*795d594fSAndroid Build Coastguard Worker     // 64bits value can be atomically written to an address with movsd and an XMM register.
6144*795d594fSAndroid Build Coastguard Worker     // We need two XMM registers because there's no easier way to (bit) copy a register pair
6145*795d594fSAndroid Build Coastguard Worker     // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
6146*795d594fSAndroid Build Coastguard Worker     // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
6147*795d594fSAndroid Build Coastguard Worker     // isolated cases when we need this it isn't worth adding the extra complexity.
6148*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
6149*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresFpuRegister());
6150*795d594fSAndroid Build Coastguard Worker   } else {
6151*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6152*795d594fSAndroid Build Coastguard Worker 
6153*795d594fSAndroid Build Coastguard Worker     bool needs_write_barrier =
6154*795d594fSAndroid Build Coastguard Worker         codegen_->StoreNeedsWriteBarrier(field_type, instruction->InputAt(1), write_barrier_kind);
6155*795d594fSAndroid Build Coastguard Worker     bool check_gc_card =
6156*795d594fSAndroid Build Coastguard Worker         codegen_->ShouldCheckGCCard(field_type, instruction->InputAt(1), write_barrier_kind);
6157*795d594fSAndroid Build Coastguard Worker 
6158*795d594fSAndroid Build Coastguard Worker     if (needs_write_barrier || check_gc_card) {
6159*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
6160*795d594fSAndroid Build Coastguard Worker       // Ensure the card is in a byte register.
6161*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RegisterLocation(ECX));
6162*795d594fSAndroid Build Coastguard Worker     } else if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
6163*795d594fSAndroid Build Coastguard Worker       locations->AddTemp(Location::RequiresRegister());
6164*795d594fSAndroid Build Coastguard Worker     }
6165*795d594fSAndroid Build Coastguard Worker   }
6166*795d594fSAndroid Build Coastguard Worker }
6167*795d594fSAndroid Build Coastguard Worker 
HandleFieldSet(HInstruction * instruction,uint32_t value_index,DataType::Type field_type,Address field_addr,Register base,bool is_volatile,bool value_can_be_null,WriteBarrierKind write_barrier_kind)6168*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
6169*795d594fSAndroid Build Coastguard Worker                                                  uint32_t value_index,
6170*795d594fSAndroid Build Coastguard Worker                                                  DataType::Type field_type,
6171*795d594fSAndroid Build Coastguard Worker                                                  Address field_addr,
6172*795d594fSAndroid Build Coastguard Worker                                                  Register base,
6173*795d594fSAndroid Build Coastguard Worker                                                  bool is_volatile,
6174*795d594fSAndroid Build Coastguard Worker                                                  bool value_can_be_null,
6175*795d594fSAndroid Build Coastguard Worker                                                  WriteBarrierKind write_barrier_kind) {
6176*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6177*795d594fSAndroid Build Coastguard Worker   Location value = locations->InAt(value_index);
6178*795d594fSAndroid Build Coastguard Worker   bool needs_write_barrier =
6179*795d594fSAndroid Build Coastguard Worker       codegen_->StoreNeedsWriteBarrier(field_type, instruction->InputAt(1), write_barrier_kind);
6180*795d594fSAndroid Build Coastguard Worker 
6181*795d594fSAndroid Build Coastguard Worker   if (is_volatile) {
6182*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
6183*795d594fSAndroid Build Coastguard Worker   }
6184*795d594fSAndroid Build Coastguard Worker 
6185*795d594fSAndroid Build Coastguard Worker   bool maybe_record_implicit_null_check_done = false;
6186*795d594fSAndroid Build Coastguard Worker 
6187*795d594fSAndroid Build Coastguard Worker   switch (field_type) {
6188*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
6189*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
6190*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8: {
6191*795d594fSAndroid Build Coastguard Worker       if (value.IsConstant()) {
6192*795d594fSAndroid Build Coastguard Worker         __ movb(field_addr, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
6193*795d594fSAndroid Build Coastguard Worker       } else {
6194*795d594fSAndroid Build Coastguard Worker         __ movb(field_addr, value.AsRegister<ByteRegister>());
6195*795d594fSAndroid Build Coastguard Worker       }
6196*795d594fSAndroid Build Coastguard Worker       break;
6197*795d594fSAndroid Build Coastguard Worker     }
6198*795d594fSAndroid Build Coastguard Worker 
6199*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
6200*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16: {
6201*795d594fSAndroid Build Coastguard Worker       if (value.IsConstant()) {
6202*795d594fSAndroid Build Coastguard Worker         __ movw(field_addr, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
6203*795d594fSAndroid Build Coastguard Worker       } else {
6204*795d594fSAndroid Build Coastguard Worker         __ movw(field_addr, value.AsRegister<Register>());
6205*795d594fSAndroid Build Coastguard Worker       }
6206*795d594fSAndroid Build Coastguard Worker       break;
6207*795d594fSAndroid Build Coastguard Worker     }
6208*795d594fSAndroid Build Coastguard Worker 
6209*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
6210*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference: {
6211*795d594fSAndroid Build Coastguard Worker       if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
6212*795d594fSAndroid Build Coastguard Worker         if (value.IsConstant()) {
6213*795d594fSAndroid Build Coastguard Worker           DCHECK(value.GetConstant()->IsNullConstant())
6214*795d594fSAndroid Build Coastguard Worker               << "constant value " << CodeGenerator::GetInt32ValueOf(value.GetConstant())
6215*795d594fSAndroid Build Coastguard Worker               << " is not null. Instruction " << *instruction;
6216*795d594fSAndroid Build Coastguard Worker           // No need to poison null, just do a movl.
6217*795d594fSAndroid Build Coastguard Worker           __ movl(field_addr, Immediate(0));
6218*795d594fSAndroid Build Coastguard Worker         } else {
6219*795d594fSAndroid Build Coastguard Worker           Register temp = locations->GetTemp(0).AsRegister<Register>();
6220*795d594fSAndroid Build Coastguard Worker           __ movl(temp, value.AsRegister<Register>());
6221*795d594fSAndroid Build Coastguard Worker           __ PoisonHeapReference(temp);
6222*795d594fSAndroid Build Coastguard Worker           __ movl(field_addr, temp);
6223*795d594fSAndroid Build Coastguard Worker         }
6224*795d594fSAndroid Build Coastguard Worker       } else if (value.IsConstant()) {
6225*795d594fSAndroid Build Coastguard Worker         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
6226*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, Immediate(v));
6227*795d594fSAndroid Build Coastguard Worker       } else {
6228*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsRegister()) << value;
6229*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, value.AsRegister<Register>());
6230*795d594fSAndroid Build Coastguard Worker       }
6231*795d594fSAndroid Build Coastguard Worker       break;
6232*795d594fSAndroid Build Coastguard Worker     }
6233*795d594fSAndroid Build Coastguard Worker 
6234*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
6235*795d594fSAndroid Build Coastguard Worker       if (is_volatile) {
6236*795d594fSAndroid Build Coastguard Worker         XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
6237*795d594fSAndroid Build Coastguard Worker         XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
6238*795d594fSAndroid Build Coastguard Worker         __ movd(temp1, value.AsRegisterPairLow<Register>());
6239*795d594fSAndroid Build Coastguard Worker         __ movd(temp2, value.AsRegisterPairHigh<Register>());
6240*795d594fSAndroid Build Coastguard Worker         __ punpckldq(temp1, temp2);
6241*795d594fSAndroid Build Coastguard Worker         __ movsd(field_addr, temp1);
6242*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6243*795d594fSAndroid Build Coastguard Worker       } else if (value.IsConstant()) {
6244*795d594fSAndroid Build Coastguard Worker         int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant());
6245*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, Immediate(Low32Bits(v)));
6246*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6247*795d594fSAndroid Build Coastguard Worker         __ movl(Address::displace(field_addr, kX86WordSize), Immediate(High32Bits(v)));
6248*795d594fSAndroid Build Coastguard Worker       } else {
6249*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, value.AsRegisterPairLow<Register>());
6250*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6251*795d594fSAndroid Build Coastguard Worker         __ movl(Address::displace(field_addr, kX86WordSize), value.AsRegisterPairHigh<Register>());
6252*795d594fSAndroid Build Coastguard Worker       }
6253*795d594fSAndroid Build Coastguard Worker       maybe_record_implicit_null_check_done = true;
6254*795d594fSAndroid Build Coastguard Worker       break;
6255*795d594fSAndroid Build Coastguard Worker     }
6256*795d594fSAndroid Build Coastguard Worker 
6257*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
6258*795d594fSAndroid Build Coastguard Worker       if (value.IsConstant()) {
6259*795d594fSAndroid Build Coastguard Worker         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
6260*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, Immediate(v));
6261*795d594fSAndroid Build Coastguard Worker       } else {
6262*795d594fSAndroid Build Coastguard Worker         __ movss(field_addr, value.AsFpuRegister<XmmRegister>());
6263*795d594fSAndroid Build Coastguard Worker       }
6264*795d594fSAndroid Build Coastguard Worker       break;
6265*795d594fSAndroid Build Coastguard Worker     }
6266*795d594fSAndroid Build Coastguard Worker 
6267*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
6268*795d594fSAndroid Build Coastguard Worker       if (value.IsConstant()) {
6269*795d594fSAndroid Build Coastguard Worker         DCHECK(!is_volatile);
6270*795d594fSAndroid Build Coastguard Worker         int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant());
6271*795d594fSAndroid Build Coastguard Worker         __ movl(field_addr, Immediate(Low32Bits(v)));
6272*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6273*795d594fSAndroid Build Coastguard Worker         __ movl(Address::displace(field_addr, kX86WordSize), Immediate(High32Bits(v)));
6274*795d594fSAndroid Build Coastguard Worker         maybe_record_implicit_null_check_done = true;
6275*795d594fSAndroid Build Coastguard Worker       } else {
6276*795d594fSAndroid Build Coastguard Worker         __ movsd(field_addr, value.AsFpuRegister<XmmRegister>());
6277*795d594fSAndroid Build Coastguard Worker       }
6278*795d594fSAndroid Build Coastguard Worker       break;
6279*795d594fSAndroid Build Coastguard Worker     }
6280*795d594fSAndroid Build Coastguard Worker 
6281*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
6282*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
6283*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
6284*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable type " << field_type;
6285*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
6286*795d594fSAndroid Build Coastguard Worker   }
6287*795d594fSAndroid Build Coastguard Worker 
6288*795d594fSAndroid Build Coastguard Worker   if (!maybe_record_implicit_null_check_done) {
6289*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeRecordImplicitNullCheck(instruction);
6290*795d594fSAndroid Build Coastguard Worker   }
6291*795d594fSAndroid Build Coastguard Worker 
6292*795d594fSAndroid Build Coastguard Worker   if (needs_write_barrier) {
6293*795d594fSAndroid Build Coastguard Worker     Register temp = locations->GetTemp(0).AsRegister<Register>();
6294*795d594fSAndroid Build Coastguard Worker     Register card = locations->GetTemp(1).AsRegister<Register>();
6295*795d594fSAndroid Build Coastguard Worker     if (value.IsConstant()) {
6296*795d594fSAndroid Build Coastguard Worker       DCHECK(value.GetConstant()->IsNullConstant())
6297*795d594fSAndroid Build Coastguard Worker           << "constant value " << CodeGenerator::GetInt32ValueOf(value.GetConstant())
6298*795d594fSAndroid Build Coastguard Worker           << " is not null. Instruction: " << *instruction;
6299*795d594fSAndroid Build Coastguard Worker       if (write_barrier_kind == WriteBarrierKind::kEmitBeingReliedOn) {
6300*795d594fSAndroid Build Coastguard Worker         codegen_->MarkGCCard(temp, card, base);
6301*795d594fSAndroid Build Coastguard Worker       }
6302*795d594fSAndroid Build Coastguard Worker     } else {
6303*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeMarkGCCard(
6304*795d594fSAndroid Build Coastguard Worker           temp,
6305*795d594fSAndroid Build Coastguard Worker           card,
6306*795d594fSAndroid Build Coastguard Worker           base,
6307*795d594fSAndroid Build Coastguard Worker           value.AsRegister<Register>(),
6308*795d594fSAndroid Build Coastguard Worker           value_can_be_null && write_barrier_kind == WriteBarrierKind::kEmitNotBeingReliedOn);
6309*795d594fSAndroid Build Coastguard Worker     }
6310*795d594fSAndroid Build Coastguard Worker   } else if (codegen_->ShouldCheckGCCard(field_type, instruction->InputAt(1), write_barrier_kind)) {
6311*795d594fSAndroid Build Coastguard Worker     if (value.IsConstant()) {
6312*795d594fSAndroid Build Coastguard Worker       // If we are storing a constant for a reference, we are in the case where we are storing
6313*795d594fSAndroid Build Coastguard Worker       // null but we cannot skip it as this write barrier is being relied on by coalesced write
6314*795d594fSAndroid Build Coastguard Worker       // barriers.
6315*795d594fSAndroid Build Coastguard Worker       DCHECK(value.GetConstant()->IsNullConstant())
6316*795d594fSAndroid Build Coastguard Worker           << "constant value " << CodeGenerator::GetInt32ValueOf(value.GetConstant())
6317*795d594fSAndroid Build Coastguard Worker           << " is not null. Instruction: " << *instruction;
6318*795d594fSAndroid Build Coastguard Worker       // No need to check the dirty bit as this value is null.
6319*795d594fSAndroid Build Coastguard Worker     } else {
6320*795d594fSAndroid Build Coastguard Worker       Register temp = locations->GetTemp(0).AsRegister<Register>();
6321*795d594fSAndroid Build Coastguard Worker       Register card = locations->GetTemp(1).AsRegister<Register>();
6322*795d594fSAndroid Build Coastguard Worker       codegen_->CheckGCCardIsValid(temp, card, base);
6323*795d594fSAndroid Build Coastguard Worker     }
6324*795d594fSAndroid Build Coastguard Worker   }
6325*795d594fSAndroid Build Coastguard Worker 
6326*795d594fSAndroid Build Coastguard Worker   if (is_volatile) {
6327*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
6328*795d594fSAndroid Build Coastguard Worker   }
6329*795d594fSAndroid Build Coastguard Worker }
6330*795d594fSAndroid Build Coastguard Worker 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info,bool value_can_be_null,WriteBarrierKind write_barrier_kind)6331*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
6332*795d594fSAndroid Build Coastguard Worker                                                  const FieldInfo& field_info,
6333*795d594fSAndroid Build Coastguard Worker                                                  bool value_can_be_null,
6334*795d594fSAndroid Build Coastguard Worker                                                  WriteBarrierKind write_barrier_kind) {
6335*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
6336*795d594fSAndroid Build Coastguard Worker 
6337*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6338*795d594fSAndroid Build Coastguard Worker   Register base = locations->InAt(0).AsRegister<Register>();
6339*795d594fSAndroid Build Coastguard Worker   bool is_volatile = field_info.IsVolatile();
6340*795d594fSAndroid Build Coastguard Worker   DataType::Type field_type = field_info.GetFieldType();
6341*795d594fSAndroid Build Coastguard Worker   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
6342*795d594fSAndroid Build Coastguard Worker   Address field_addr(base, offset);
6343*795d594fSAndroid Build Coastguard Worker 
6344*795d594fSAndroid Build Coastguard Worker   HandleFieldSet(instruction,
6345*795d594fSAndroid Build Coastguard Worker                  /* value_index= */ 1,
6346*795d594fSAndroid Build Coastguard Worker                  field_type,
6347*795d594fSAndroid Build Coastguard Worker                  field_addr,
6348*795d594fSAndroid Build Coastguard Worker                  base,
6349*795d594fSAndroid Build Coastguard Worker                  is_volatile,
6350*795d594fSAndroid Build Coastguard Worker                  value_can_be_null,
6351*795d594fSAndroid Build Coastguard Worker                  write_barrier_kind);
6352*795d594fSAndroid Build Coastguard Worker }
6353*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldGet(HStaticFieldGet * instruction)6354*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6355*795d594fSAndroid Build Coastguard Worker   HandleFieldGet(instruction, instruction->GetFieldInfo());
6356*795d594fSAndroid Build Coastguard Worker }
6357*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldGet(HStaticFieldGet * instruction)6358*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6359*795d594fSAndroid Build Coastguard Worker   HandleFieldGet(instruction, instruction->GetFieldInfo());
6360*795d594fSAndroid Build Coastguard Worker }
6361*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldSet(HStaticFieldSet * instruction)6362*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6363*795d594fSAndroid Build Coastguard Worker   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetWriteBarrierKind());
6364*795d594fSAndroid Build Coastguard Worker }
6365*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldSet(HStaticFieldSet * instruction)6366*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6367*795d594fSAndroid Build Coastguard Worker   HandleFieldSet(instruction,
6368*795d594fSAndroid Build Coastguard Worker                  instruction->GetFieldInfo(),
6369*795d594fSAndroid Build Coastguard Worker                  instruction->GetValueCanBeNull(),
6370*795d594fSAndroid Build Coastguard Worker                  instruction->GetWriteBarrierKind());
6371*795d594fSAndroid Build Coastguard Worker }
6372*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)6373*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6374*795d594fSAndroid Build Coastguard Worker   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetWriteBarrierKind());
6375*795d594fSAndroid Build Coastguard Worker }
6376*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)6377*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6378*795d594fSAndroid Build Coastguard Worker   HandleFieldSet(instruction,
6379*795d594fSAndroid Build Coastguard Worker                  instruction->GetFieldInfo(),
6380*795d594fSAndroid Build Coastguard Worker                  instruction->GetValueCanBeNull(),
6381*795d594fSAndroid Build Coastguard Worker                  instruction->GetWriteBarrierKind());
6382*795d594fSAndroid Build Coastguard Worker }
6383*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)6384*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6385*795d594fSAndroid Build Coastguard Worker   HandleFieldGet(instruction, instruction->GetFieldInfo());
6386*795d594fSAndroid Build Coastguard Worker }
6387*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)6388*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6389*795d594fSAndroid Build Coastguard Worker   HandleFieldGet(instruction, instruction->GetFieldInfo());
6390*795d594fSAndroid Build Coastguard Worker }
6391*795d594fSAndroid Build Coastguard Worker 
VisitStringBuilderAppend(HStringBuilderAppend * instruction)6392*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6393*795d594fSAndroid Build Coastguard Worker   codegen_->CreateStringBuilderAppendLocations(instruction, Location::RegisterLocation(EAX));
6394*795d594fSAndroid Build Coastguard Worker }
6395*795d594fSAndroid Build Coastguard Worker 
VisitStringBuilderAppend(HStringBuilderAppend * instruction)6396*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6397*795d594fSAndroid Build Coastguard Worker   __ movl(EAX, Immediate(instruction->GetFormat()->GetValue()));
6398*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickStringBuilderAppend, instruction, instruction->GetDexPc());
6399*795d594fSAndroid Build Coastguard Worker }
6400*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)6401*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
6402*795d594fSAndroid Build Coastguard Worker     HUnresolvedInstanceFieldGet* instruction) {
6403*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6404*795d594fSAndroid Build Coastguard Worker   codegen_->CreateUnresolvedFieldLocationSummary(
6405*795d594fSAndroid Build Coastguard Worker       instruction, instruction->GetFieldType(), calling_convention);
6406*795d594fSAndroid Build Coastguard Worker }
6407*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)6408*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
6409*795d594fSAndroid Build Coastguard Worker     HUnresolvedInstanceFieldGet* instruction) {
6410*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6411*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateUnresolvedFieldAccess(instruction,
6412*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldType(),
6413*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldIndex(),
6414*795d594fSAndroid Build Coastguard Worker                                           instruction->GetDexPc(),
6415*795d594fSAndroid Build Coastguard Worker                                           calling_convention);
6416*795d594fSAndroid Build Coastguard Worker }
6417*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)6418*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
6419*795d594fSAndroid Build Coastguard Worker     HUnresolvedInstanceFieldSet* instruction) {
6420*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6421*795d594fSAndroid Build Coastguard Worker   codegen_->CreateUnresolvedFieldLocationSummary(
6422*795d594fSAndroid Build Coastguard Worker       instruction, instruction->GetFieldType(), calling_convention);
6423*795d594fSAndroid Build Coastguard Worker }
6424*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)6425*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
6426*795d594fSAndroid Build Coastguard Worker     HUnresolvedInstanceFieldSet* instruction) {
6427*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6428*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateUnresolvedFieldAccess(instruction,
6429*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldType(),
6430*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldIndex(),
6431*795d594fSAndroid Build Coastguard Worker                                           instruction->GetDexPc(),
6432*795d594fSAndroid Build Coastguard Worker                                           calling_convention);
6433*795d594fSAndroid Build Coastguard Worker }
6434*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)6435*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
6436*795d594fSAndroid Build Coastguard Worker     HUnresolvedStaticFieldGet* instruction) {
6437*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6438*795d594fSAndroid Build Coastguard Worker   codegen_->CreateUnresolvedFieldLocationSummary(
6439*795d594fSAndroid Build Coastguard Worker       instruction, instruction->GetFieldType(), calling_convention);
6440*795d594fSAndroid Build Coastguard Worker }
6441*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)6442*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
6443*795d594fSAndroid Build Coastguard Worker     HUnresolvedStaticFieldGet* instruction) {
6444*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6445*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateUnresolvedFieldAccess(instruction,
6446*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldType(),
6447*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldIndex(),
6448*795d594fSAndroid Build Coastguard Worker                                           instruction->GetDexPc(),
6449*795d594fSAndroid Build Coastguard Worker                                           calling_convention);
6450*795d594fSAndroid Build Coastguard Worker }
6451*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)6452*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
6453*795d594fSAndroid Build Coastguard Worker     HUnresolvedStaticFieldSet* instruction) {
6454*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6455*795d594fSAndroid Build Coastguard Worker   codegen_->CreateUnresolvedFieldLocationSummary(
6456*795d594fSAndroid Build Coastguard Worker       instruction, instruction->GetFieldType(), calling_convention);
6457*795d594fSAndroid Build Coastguard Worker }
6458*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)6459*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
6460*795d594fSAndroid Build Coastguard Worker     HUnresolvedStaticFieldSet* instruction) {
6461*795d594fSAndroid Build Coastguard Worker   FieldAccessCallingConventionX86 calling_convention;
6462*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateUnresolvedFieldAccess(instruction,
6463*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldType(),
6464*795d594fSAndroid Build Coastguard Worker                                           instruction->GetFieldIndex(),
6465*795d594fSAndroid Build Coastguard Worker                                           instruction->GetDexPc(),
6466*795d594fSAndroid Build Coastguard Worker                                           calling_convention);
6467*795d594fSAndroid Build Coastguard Worker }
6468*795d594fSAndroid Build Coastguard Worker 
VisitNullCheck(HNullCheck * instruction)6469*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
6470*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
6471*795d594fSAndroid Build Coastguard Worker   Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
6472*795d594fSAndroid Build Coastguard Worker       ? Location::RequiresRegister()
6473*795d594fSAndroid Build Coastguard Worker       : Location::Any();
6474*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, loc);
6475*795d594fSAndroid Build Coastguard Worker }
6476*795d594fSAndroid Build Coastguard Worker 
GenerateImplicitNullCheck(HNullCheck * instruction)6477*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
6478*795d594fSAndroid Build Coastguard Worker   if (CanMoveNullCheckToUser(instruction)) {
6479*795d594fSAndroid Build Coastguard Worker     return;
6480*795d594fSAndroid Build Coastguard Worker   }
6481*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6482*795d594fSAndroid Build Coastguard Worker   Location obj = locations->InAt(0);
6483*795d594fSAndroid Build Coastguard Worker 
6484*795d594fSAndroid Build Coastguard Worker   __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
6485*795d594fSAndroid Build Coastguard Worker   RecordPcInfo(instruction, instruction->GetDexPc());
6486*795d594fSAndroid Build Coastguard Worker }
6487*795d594fSAndroid Build Coastguard Worker 
GenerateExplicitNullCheck(HNullCheck * instruction)6488*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
6489*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (GetScopedAllocator()) NullCheckSlowPathX86(instruction);
6490*795d594fSAndroid Build Coastguard Worker   AddSlowPath(slow_path);
6491*795d594fSAndroid Build Coastguard Worker 
6492*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6493*795d594fSAndroid Build Coastguard Worker   Location obj = locations->InAt(0);
6494*795d594fSAndroid Build Coastguard Worker 
6495*795d594fSAndroid Build Coastguard Worker   if (obj.IsRegister()) {
6496*795d594fSAndroid Build Coastguard Worker     __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
6497*795d594fSAndroid Build Coastguard Worker   } else if (obj.IsStackSlot()) {
6498*795d594fSAndroid Build Coastguard Worker     __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
6499*795d594fSAndroid Build Coastguard Worker   } else {
6500*795d594fSAndroid Build Coastguard Worker     DCHECK(obj.IsConstant()) << obj;
6501*795d594fSAndroid Build Coastguard Worker     DCHECK(obj.GetConstant()->IsNullConstant());
6502*795d594fSAndroid Build Coastguard Worker     __ jmp(slow_path->GetEntryLabel());
6503*795d594fSAndroid Build Coastguard Worker     return;
6504*795d594fSAndroid Build Coastguard Worker   }
6505*795d594fSAndroid Build Coastguard Worker   __ j(kEqual, slow_path->GetEntryLabel());
6506*795d594fSAndroid Build Coastguard Worker }
6507*795d594fSAndroid Build Coastguard Worker 
VisitNullCheck(HNullCheck * instruction)6508*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
6509*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateNullCheck(instruction);
6510*795d594fSAndroid Build Coastguard Worker }
6511*795d594fSAndroid Build Coastguard Worker 
VisitArrayGet(HArrayGet * instruction)6512*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
6513*795d594fSAndroid Build Coastguard Worker   bool object_array_get_with_read_barrier =
6514*795d594fSAndroid Build Coastguard Worker       (instruction->GetType() == DataType::Type::kReference) && codegen_->EmitReadBarrier();
6515*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
6516*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction,
6517*795d594fSAndroid Build Coastguard Worker                                                        object_array_get_with_read_barrier
6518*795d594fSAndroid Build Coastguard Worker                                                            ? LocationSummary::kCallOnSlowPath
6519*795d594fSAndroid Build Coastguard Worker                                                            : LocationSummary::kNoCall);
6520*795d594fSAndroid Build Coastguard Worker   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
6521*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
6522*795d594fSAndroid Build Coastguard Worker   }
6523*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
6524*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6525*795d594fSAndroid Build Coastguard Worker   if (DataType::IsFloatingPointType(instruction->GetType())) {
6526*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6527*795d594fSAndroid Build Coastguard Worker   } else {
6528*795d594fSAndroid Build Coastguard Worker     // The output overlaps in case of long: we don't want the low move
6529*795d594fSAndroid Build Coastguard Worker     // to overwrite the array's location.  Likewise, in the case of an
6530*795d594fSAndroid Build Coastguard Worker     // object array get with read barriers enabled, we do not want the
6531*795d594fSAndroid Build Coastguard Worker     // move to overwrite the array's location, as we need it to emit
6532*795d594fSAndroid Build Coastguard Worker     // the read barrier.
6533*795d594fSAndroid Build Coastguard Worker     locations->SetOut(
6534*795d594fSAndroid Build Coastguard Worker         Location::RequiresRegister(),
6535*795d594fSAndroid Build Coastguard Worker         (instruction->GetType() == DataType::Type::kInt64 || object_array_get_with_read_barrier)
6536*795d594fSAndroid Build Coastguard Worker             ? Location::kOutputOverlap
6537*795d594fSAndroid Build Coastguard Worker             : Location::kNoOutputOverlap);
6538*795d594fSAndroid Build Coastguard Worker   }
6539*795d594fSAndroid Build Coastguard Worker }
6540*795d594fSAndroid Build Coastguard Worker 
VisitArrayGet(HArrayGet * instruction)6541*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
6542*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6543*795d594fSAndroid Build Coastguard Worker   Location obj_loc = locations->InAt(0);
6544*795d594fSAndroid Build Coastguard Worker   Register obj = obj_loc.AsRegister<Register>();
6545*795d594fSAndroid Build Coastguard Worker   Location index = locations->InAt(1);
6546*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
6547*795d594fSAndroid Build Coastguard Worker   uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
6548*795d594fSAndroid Build Coastguard Worker 
6549*795d594fSAndroid Build Coastguard Worker   DataType::Type type = instruction->GetType();
6550*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
6551*795d594fSAndroid Build Coastguard Worker     static_assert(
6552*795d594fSAndroid Build Coastguard Worker         sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6553*795d594fSAndroid Build Coastguard Worker         "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6554*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Object> */ out =
6555*795d594fSAndroid Build Coastguard Worker     //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
6556*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitBakerReadBarrier()) {
6557*795d594fSAndroid Build Coastguard Worker       // Note that a potential implicit null check is handled in this
6558*795d594fSAndroid Build Coastguard Worker       // CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier call.
6559*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateArrayLoadWithBakerReadBarrier(
6560*795d594fSAndroid Build Coastguard Worker           instruction, out_loc, obj, data_offset, index, /* needs_null_check= */ true);
6561*795d594fSAndroid Build Coastguard Worker     } else {
6562*795d594fSAndroid Build Coastguard Worker       Register out = out_loc.AsRegister<Register>();
6563*795d594fSAndroid Build Coastguard Worker       __ movl(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset));
6564*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6565*795d594fSAndroid Build Coastguard Worker       // If read barriers are enabled, emit read barriers other than
6566*795d594fSAndroid Build Coastguard Worker       // Baker's using a slow path (and also unpoison the loaded
6567*795d594fSAndroid Build Coastguard Worker       // reference, if heap poisoning is enabled).
6568*795d594fSAndroid Build Coastguard Worker       if (index.IsConstant()) {
6569*795d594fSAndroid Build Coastguard Worker         uint32_t offset =
6570*795d594fSAndroid Build Coastguard Worker             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6571*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
6572*795d594fSAndroid Build Coastguard Worker       } else {
6573*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeGenerateReadBarrierSlow(
6574*795d594fSAndroid Build Coastguard Worker             instruction, out_loc, out_loc, obj_loc, data_offset, index);
6575*795d594fSAndroid Build Coastguard Worker       }
6576*795d594fSAndroid Build Coastguard Worker     }
6577*795d594fSAndroid Build Coastguard Worker   } else if (type == DataType::Type::kUint16
6578*795d594fSAndroid Build Coastguard Worker       && mirror::kUseStringCompression
6579*795d594fSAndroid Build Coastguard Worker       && instruction->IsStringCharAt()) {
6580*795d594fSAndroid Build Coastguard Worker     // Branch cases into compressed and uncompressed for each index's type.
6581*795d594fSAndroid Build Coastguard Worker     Register out = out_loc.AsRegister<Register>();
6582*795d594fSAndroid Build Coastguard Worker     uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
6583*795d594fSAndroid Build Coastguard Worker     NearLabel done, not_compressed;
6584*795d594fSAndroid Build Coastguard Worker     __ testb(Address(obj, count_offset), Immediate(1));
6585*795d594fSAndroid Build Coastguard Worker     codegen_->MaybeRecordImplicitNullCheck(instruction);
6586*795d594fSAndroid Build Coastguard Worker     static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6587*795d594fSAndroid Build Coastguard Worker                   "Expecting 0=compressed, 1=uncompressed");
6588*795d594fSAndroid Build Coastguard Worker     __ j(kNotZero, &not_compressed);
6589*795d594fSAndroid Build Coastguard Worker     __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
6590*795d594fSAndroid Build Coastguard Worker     __ jmp(&done);
6591*795d594fSAndroid Build Coastguard Worker     __ Bind(&not_compressed);
6592*795d594fSAndroid Build Coastguard Worker     __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
6593*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
6594*795d594fSAndroid Build Coastguard Worker   } else {
6595*795d594fSAndroid Build Coastguard Worker     ScaleFactor scale = CodeGenerator::ScaleFactorForType(type);
6596*795d594fSAndroid Build Coastguard Worker     Address src = CodeGeneratorX86::ArrayAddress(obj, index, scale, data_offset);
6597*795d594fSAndroid Build Coastguard Worker     codegen_->LoadFromMemoryNoBarrier(type, out_loc, src, instruction);
6598*795d594fSAndroid Build Coastguard Worker   }
6599*795d594fSAndroid Build Coastguard Worker }
6600*795d594fSAndroid Build Coastguard Worker 
VisitArraySet(HArraySet * instruction)6601*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
6602*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = instruction->GetComponentType();
6603*795d594fSAndroid Build Coastguard Worker 
6604*795d594fSAndroid Build Coastguard Worker   WriteBarrierKind write_barrier_kind = instruction->GetWriteBarrierKind();
6605*795d594fSAndroid Build Coastguard Worker   bool needs_write_barrier =
6606*795d594fSAndroid Build Coastguard Worker       codegen_->StoreNeedsWriteBarrier(value_type, instruction->GetValue(), write_barrier_kind);
6607*795d594fSAndroid Build Coastguard Worker   bool check_gc_card =
6608*795d594fSAndroid Build Coastguard Worker       codegen_->ShouldCheckGCCard(value_type, instruction->GetValue(), write_barrier_kind);
6609*795d594fSAndroid Build Coastguard Worker   bool needs_type_check = instruction->NeedsTypeCheck();
6610*795d594fSAndroid Build Coastguard Worker 
6611*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6612*795d594fSAndroid Build Coastguard Worker       instruction,
6613*795d594fSAndroid Build Coastguard Worker       needs_type_check ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
6614*795d594fSAndroid Build Coastguard Worker 
6615*795d594fSAndroid Build Coastguard Worker   bool is_byte_type = DataType::Size(value_type) == 1u;
6616*795d594fSAndroid Build Coastguard Worker   // We need the inputs to be different than the output in case of long operation.
6617*795d594fSAndroid Build Coastguard Worker   // In case of a byte operation, the register allocator does not support multiple
6618*795d594fSAndroid Build Coastguard Worker   // inputs that die at entry with one in a specific register.
6619*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
6620*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6621*795d594fSAndroid Build Coastguard Worker   if (is_byte_type) {
6622*795d594fSAndroid Build Coastguard Worker     // Ensure the value is in a byte register.
6623*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
6624*795d594fSAndroid Build Coastguard Worker   } else if (DataType::IsFloatingPointType(value_type)) {
6625*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
6626*795d594fSAndroid Build Coastguard Worker   } else {
6627*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
6628*795d594fSAndroid Build Coastguard Worker   }
6629*795d594fSAndroid Build Coastguard Worker   if (needs_write_barrier || check_gc_card) {
6630*795d594fSAndroid Build Coastguard Worker     // Used by reference poisoning, type checking, emitting, or checking a write barrier.
6631*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
6632*795d594fSAndroid Build Coastguard Worker     // Only used when emitting or checking a write barrier. Ensure the card is in a byte register.
6633*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RegisterLocation(ECX));
6634*795d594fSAndroid Build Coastguard Worker   } else if ((kPoisonHeapReferences && value_type == DataType::Type::kReference) ||
6635*795d594fSAndroid Build Coastguard Worker              instruction->NeedsTypeCheck()) {
6636*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
6637*795d594fSAndroid Build Coastguard Worker   }
6638*795d594fSAndroid Build Coastguard Worker }
6639*795d594fSAndroid Build Coastguard Worker 
VisitArraySet(HArraySet * instruction)6640*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
6641*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6642*795d594fSAndroid Build Coastguard Worker   Location array_loc = locations->InAt(0);
6643*795d594fSAndroid Build Coastguard Worker   Register array = array_loc.AsRegister<Register>();
6644*795d594fSAndroid Build Coastguard Worker   Location index = locations->InAt(1);
6645*795d594fSAndroid Build Coastguard Worker   Location value = locations->InAt(2);
6646*795d594fSAndroid Build Coastguard Worker   DataType::Type value_type = instruction->GetComponentType();
6647*795d594fSAndroid Build Coastguard Worker   bool needs_type_check = instruction->NeedsTypeCheck();
6648*795d594fSAndroid Build Coastguard Worker   WriteBarrierKind write_barrier_kind = instruction->GetWriteBarrierKind();
6649*795d594fSAndroid Build Coastguard Worker   bool needs_write_barrier =
6650*795d594fSAndroid Build Coastguard Worker       codegen_->StoreNeedsWriteBarrier(value_type, instruction->GetValue(), write_barrier_kind);
6651*795d594fSAndroid Build Coastguard Worker 
6652*795d594fSAndroid Build Coastguard Worker   switch (value_type) {
6653*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kBool:
6654*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint8:
6655*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt8: {
6656*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
6657*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_1, offset);
6658*795d594fSAndroid Build Coastguard Worker       if (value.IsRegister()) {
6659*795d594fSAndroid Build Coastguard Worker         __ movb(address, value.AsRegister<ByteRegister>());
6660*795d594fSAndroid Build Coastguard Worker       } else {
6661*795d594fSAndroid Build Coastguard Worker         __ movb(address, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
6662*795d594fSAndroid Build Coastguard Worker       }
6663*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6664*795d594fSAndroid Build Coastguard Worker       break;
6665*795d594fSAndroid Build Coastguard Worker     }
6666*795d594fSAndroid Build Coastguard Worker 
6667*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint16:
6668*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt16: {
6669*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
6670*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_2, offset);
6671*795d594fSAndroid Build Coastguard Worker       if (value.IsRegister()) {
6672*795d594fSAndroid Build Coastguard Worker         __ movw(address, value.AsRegister<Register>());
6673*795d594fSAndroid Build Coastguard Worker       } else {
6674*795d594fSAndroid Build Coastguard Worker         __ movw(address, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
6675*795d594fSAndroid Build Coastguard Worker       }
6676*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6677*795d594fSAndroid Build Coastguard Worker       break;
6678*795d594fSAndroid Build Coastguard Worker     }
6679*795d594fSAndroid Build Coastguard Worker 
6680*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kReference: {
6681*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
6682*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
6683*795d594fSAndroid Build Coastguard Worker 
6684*795d594fSAndroid Build Coastguard Worker       if (!value.IsRegister()) {
6685*795d594fSAndroid Build Coastguard Worker         // Just setting null.
6686*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->InputAt(2)->IsNullConstant());
6687*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant()) << value;
6688*795d594fSAndroid Build Coastguard Worker         __ movl(address, Immediate(0));
6689*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6690*795d594fSAndroid Build Coastguard Worker         if (write_barrier_kind == WriteBarrierKind::kEmitBeingReliedOn) {
6691*795d594fSAndroid Build Coastguard Worker           // We need to set a write barrier here even though we are writing null, since this write
6692*795d594fSAndroid Build Coastguard Worker           // barrier is being relied on.
6693*795d594fSAndroid Build Coastguard Worker           DCHECK(needs_write_barrier);
6694*795d594fSAndroid Build Coastguard Worker           Register temp = locations->GetTemp(0).AsRegister<Register>();
6695*795d594fSAndroid Build Coastguard Worker           Register card = locations->GetTemp(1).AsRegister<Register>();
6696*795d594fSAndroid Build Coastguard Worker           codegen_->MarkGCCard(temp, card, array);
6697*795d594fSAndroid Build Coastguard Worker         }
6698*795d594fSAndroid Build Coastguard Worker         DCHECK(!needs_type_check);
6699*795d594fSAndroid Build Coastguard Worker         break;
6700*795d594fSAndroid Build Coastguard Worker       }
6701*795d594fSAndroid Build Coastguard Worker 
6702*795d594fSAndroid Build Coastguard Worker       Register register_value = value.AsRegister<Register>();
6703*795d594fSAndroid Build Coastguard Worker       const bool can_value_be_null = instruction->GetValueCanBeNull();
6704*795d594fSAndroid Build Coastguard Worker       // The WriteBarrierKind::kEmitNotBeingReliedOn case is able to skip the write barrier when its
6705*795d594fSAndroid Build Coastguard Worker       // value is null (without an extra CompareAndBranchIfZero since we already checked if the
6706*795d594fSAndroid Build Coastguard Worker       // value is null for the type check).
6707*795d594fSAndroid Build Coastguard Worker       const bool skip_marking_gc_card =
6708*795d594fSAndroid Build Coastguard Worker           can_value_be_null && write_barrier_kind == WriteBarrierKind::kEmitNotBeingReliedOn;
6709*795d594fSAndroid Build Coastguard Worker       NearLabel do_store;
6710*795d594fSAndroid Build Coastguard Worker       NearLabel skip_writing_card;
6711*795d594fSAndroid Build Coastguard Worker       if (can_value_be_null) {
6712*795d594fSAndroid Build Coastguard Worker         __ testl(register_value, register_value);
6713*795d594fSAndroid Build Coastguard Worker         if (skip_marking_gc_card) {
6714*795d594fSAndroid Build Coastguard Worker           __ j(kEqual, &skip_writing_card);
6715*795d594fSAndroid Build Coastguard Worker         } else {
6716*795d594fSAndroid Build Coastguard Worker           __ j(kEqual, &do_store);
6717*795d594fSAndroid Build Coastguard Worker         }
6718*795d594fSAndroid Build Coastguard Worker       }
6719*795d594fSAndroid Build Coastguard Worker 
6720*795d594fSAndroid Build Coastguard Worker       SlowPathCode* slow_path = nullptr;
6721*795d594fSAndroid Build Coastguard Worker       if (needs_type_check) {
6722*795d594fSAndroid Build Coastguard Worker         slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathX86(instruction);
6723*795d594fSAndroid Build Coastguard Worker         codegen_->AddSlowPath(slow_path);
6724*795d594fSAndroid Build Coastguard Worker 
6725*795d594fSAndroid Build Coastguard Worker         const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6726*795d594fSAndroid Build Coastguard Worker         const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6727*795d594fSAndroid Build Coastguard Worker         const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6728*795d594fSAndroid Build Coastguard Worker 
6729*795d594fSAndroid Build Coastguard Worker         // Note that when Baker read barriers are enabled, the type
6730*795d594fSAndroid Build Coastguard Worker         // checks are performed without read barriers.  This is fine,
6731*795d594fSAndroid Build Coastguard Worker         // even in the case where a class object is in the from-space
6732*795d594fSAndroid Build Coastguard Worker         // after the flip, as a comparison involving such a type would
6733*795d594fSAndroid Build Coastguard Worker         // not produce a false positive; it may of course produce a
6734*795d594fSAndroid Build Coastguard Worker         // false negative, in which case we would take the ArraySet
6735*795d594fSAndroid Build Coastguard Worker         // slow path.
6736*795d594fSAndroid Build Coastguard Worker 
6737*795d594fSAndroid Build Coastguard Worker         Register temp = locations->GetTemp(0).AsRegister<Register>();
6738*795d594fSAndroid Build Coastguard Worker         // /* HeapReference<Class> */ temp = array->klass_
6739*795d594fSAndroid Build Coastguard Worker         __ movl(temp, Address(array, class_offset));
6740*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6741*795d594fSAndroid Build Coastguard Worker         __ MaybeUnpoisonHeapReference(temp);
6742*795d594fSAndroid Build Coastguard Worker 
6743*795d594fSAndroid Build Coastguard Worker         // /* HeapReference<Class> */ temp = temp->component_type_
6744*795d594fSAndroid Build Coastguard Worker         __ movl(temp, Address(temp, component_offset));
6745*795d594fSAndroid Build Coastguard Worker         // If heap poisoning is enabled, no need to unpoison `temp`
6746*795d594fSAndroid Build Coastguard Worker         // nor the object reference in `register_value->klass`, as
6747*795d594fSAndroid Build Coastguard Worker         // we are comparing two poisoned references.
6748*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, Address(register_value, class_offset));
6749*795d594fSAndroid Build Coastguard Worker 
6750*795d594fSAndroid Build Coastguard Worker         if (instruction->StaticTypeOfArrayIsObjectArray()) {
6751*795d594fSAndroid Build Coastguard Worker           NearLabel do_put;
6752*795d594fSAndroid Build Coastguard Worker           __ j(kEqual, &do_put);
6753*795d594fSAndroid Build Coastguard Worker           // If heap poisoning is enabled, the `temp` reference has
6754*795d594fSAndroid Build Coastguard Worker           // not been unpoisoned yet; unpoison it now.
6755*795d594fSAndroid Build Coastguard Worker           __ MaybeUnpoisonHeapReference(temp);
6756*795d594fSAndroid Build Coastguard Worker 
6757*795d594fSAndroid Build Coastguard Worker           // If heap poisoning is enabled, no need to unpoison the
6758*795d594fSAndroid Build Coastguard Worker           // heap reference loaded below, as it is only used for a
6759*795d594fSAndroid Build Coastguard Worker           // comparison with null.
6760*795d594fSAndroid Build Coastguard Worker           __ cmpl(Address(temp, super_offset), Immediate(0));
6761*795d594fSAndroid Build Coastguard Worker           __ j(kNotEqual, slow_path->GetEntryLabel());
6762*795d594fSAndroid Build Coastguard Worker           __ Bind(&do_put);
6763*795d594fSAndroid Build Coastguard Worker         } else {
6764*795d594fSAndroid Build Coastguard Worker           __ j(kNotEqual, slow_path->GetEntryLabel());
6765*795d594fSAndroid Build Coastguard Worker         }
6766*795d594fSAndroid Build Coastguard Worker       }
6767*795d594fSAndroid Build Coastguard Worker 
6768*795d594fSAndroid Build Coastguard Worker       if (can_value_be_null && !skip_marking_gc_card) {
6769*795d594fSAndroid Build Coastguard Worker         DCHECK(do_store.IsLinked());
6770*795d594fSAndroid Build Coastguard Worker         __ Bind(&do_store);
6771*795d594fSAndroid Build Coastguard Worker       }
6772*795d594fSAndroid Build Coastguard Worker 
6773*795d594fSAndroid Build Coastguard Worker       if (needs_write_barrier) {
6774*795d594fSAndroid Build Coastguard Worker         Register temp = locations->GetTemp(0).AsRegister<Register>();
6775*795d594fSAndroid Build Coastguard Worker         Register card = locations->GetTemp(1).AsRegister<Register>();
6776*795d594fSAndroid Build Coastguard Worker         codegen_->MarkGCCard(temp, card, array);
6777*795d594fSAndroid Build Coastguard Worker       } else if (codegen_->ShouldCheckGCCard(
6778*795d594fSAndroid Build Coastguard Worker                      value_type, instruction->GetValue(), write_barrier_kind)) {
6779*795d594fSAndroid Build Coastguard Worker         Register temp = locations->GetTemp(0).AsRegister<Register>();
6780*795d594fSAndroid Build Coastguard Worker         Register card = locations->GetTemp(1).AsRegister<Register>();
6781*795d594fSAndroid Build Coastguard Worker         codegen_->CheckGCCardIsValid(temp, card, array);
6782*795d594fSAndroid Build Coastguard Worker       }
6783*795d594fSAndroid Build Coastguard Worker 
6784*795d594fSAndroid Build Coastguard Worker       if (skip_marking_gc_card) {
6785*795d594fSAndroid Build Coastguard Worker         // Note that we don't check that the GC card is valid as it can be correctly clean.
6786*795d594fSAndroid Build Coastguard Worker         DCHECK(skip_writing_card.IsLinked());
6787*795d594fSAndroid Build Coastguard Worker         __ Bind(&skip_writing_card);
6788*795d594fSAndroid Build Coastguard Worker       }
6789*795d594fSAndroid Build Coastguard Worker 
6790*795d594fSAndroid Build Coastguard Worker       Register source = register_value;
6791*795d594fSAndroid Build Coastguard Worker       if (kPoisonHeapReferences) {
6792*795d594fSAndroid Build Coastguard Worker         Register temp = locations->GetTemp(0).AsRegister<Register>();
6793*795d594fSAndroid Build Coastguard Worker         __ movl(temp, register_value);
6794*795d594fSAndroid Build Coastguard Worker         __ PoisonHeapReference(temp);
6795*795d594fSAndroid Build Coastguard Worker         source = temp;
6796*795d594fSAndroid Build Coastguard Worker       }
6797*795d594fSAndroid Build Coastguard Worker 
6798*795d594fSAndroid Build Coastguard Worker       __ movl(address, source);
6799*795d594fSAndroid Build Coastguard Worker 
6800*795d594fSAndroid Build Coastguard Worker       if (can_value_be_null || !needs_type_check) {
6801*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6802*795d594fSAndroid Build Coastguard Worker       }
6803*795d594fSAndroid Build Coastguard Worker 
6804*795d594fSAndroid Build Coastguard Worker       if (slow_path != nullptr) {
6805*795d594fSAndroid Build Coastguard Worker         __ Bind(slow_path->GetExitLabel());
6806*795d594fSAndroid Build Coastguard Worker       }
6807*795d594fSAndroid Build Coastguard Worker 
6808*795d594fSAndroid Build Coastguard Worker       break;
6809*795d594fSAndroid Build Coastguard Worker     }
6810*795d594fSAndroid Build Coastguard Worker 
6811*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32: {
6812*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
6813*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
6814*795d594fSAndroid Build Coastguard Worker       if (value.IsRegister()) {
6815*795d594fSAndroid Build Coastguard Worker         __ movl(address, value.AsRegister<Register>());
6816*795d594fSAndroid Build Coastguard Worker       } else {
6817*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant()) << value;
6818*795d594fSAndroid Build Coastguard Worker         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
6819*795d594fSAndroid Build Coastguard Worker         __ movl(address, Immediate(v));
6820*795d594fSAndroid Build Coastguard Worker       }
6821*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6822*795d594fSAndroid Build Coastguard Worker       break;
6823*795d594fSAndroid Build Coastguard Worker     }
6824*795d594fSAndroid Build Coastguard Worker 
6825*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt64: {
6826*795d594fSAndroid Build Coastguard Worker       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
6827*795d594fSAndroid Build Coastguard Worker       if (value.IsRegisterPair()) {
6828*795d594fSAndroid Build Coastguard Worker         __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset),
6829*795d594fSAndroid Build Coastguard Worker                 value.AsRegisterPairLow<Register>());
6830*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6831*795d594fSAndroid Build Coastguard Worker         __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset + kX86WordSize),
6832*795d594fSAndroid Build Coastguard Worker                 value.AsRegisterPairHigh<Register>());
6833*795d594fSAndroid Build Coastguard Worker       } else {
6834*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant());
6835*795d594fSAndroid Build Coastguard Worker         int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
6836*795d594fSAndroid Build Coastguard Worker         __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset),
6837*795d594fSAndroid Build Coastguard Worker                 Immediate(Low32Bits(val)));
6838*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6839*795d594fSAndroid Build Coastguard Worker         __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset + kX86WordSize),
6840*795d594fSAndroid Build Coastguard Worker                 Immediate(High32Bits(val)));
6841*795d594fSAndroid Build Coastguard Worker       }
6842*795d594fSAndroid Build Coastguard Worker       break;
6843*795d594fSAndroid Build Coastguard Worker     }
6844*795d594fSAndroid Build Coastguard Worker 
6845*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32: {
6846*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
6847*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
6848*795d594fSAndroid Build Coastguard Worker       if (value.IsFpuRegister()) {
6849*795d594fSAndroid Build Coastguard Worker         __ movss(address, value.AsFpuRegister<XmmRegister>());
6850*795d594fSAndroid Build Coastguard Worker       } else {
6851*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant());
6852*795d594fSAndroid Build Coastguard Worker         int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
6853*795d594fSAndroid Build Coastguard Worker         __ movl(address, Immediate(v));
6854*795d594fSAndroid Build Coastguard Worker       }
6855*795d594fSAndroid Build Coastguard Worker       codegen_->MaybeRecordImplicitNullCheck(instruction);
6856*795d594fSAndroid Build Coastguard Worker       break;
6857*795d594fSAndroid Build Coastguard Worker     }
6858*795d594fSAndroid Build Coastguard Worker 
6859*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64: {
6860*795d594fSAndroid Build Coastguard Worker       uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
6861*795d594fSAndroid Build Coastguard Worker       Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, offset);
6862*795d594fSAndroid Build Coastguard Worker       if (value.IsFpuRegister()) {
6863*795d594fSAndroid Build Coastguard Worker         __ movsd(address, value.AsFpuRegister<XmmRegister>());
6864*795d594fSAndroid Build Coastguard Worker       } else {
6865*795d594fSAndroid Build Coastguard Worker         DCHECK(value.IsConstant());
6866*795d594fSAndroid Build Coastguard Worker         Address address_hi =
6867*795d594fSAndroid Build Coastguard Worker             CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, offset + kX86WordSize);
6868*795d594fSAndroid Build Coastguard Worker         int64_t v = bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
6869*795d594fSAndroid Build Coastguard Worker         __ movl(address, Immediate(Low32Bits(v)));
6870*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(instruction);
6871*795d594fSAndroid Build Coastguard Worker         __ movl(address_hi, Immediate(High32Bits(v)));
6872*795d594fSAndroid Build Coastguard Worker       }
6873*795d594fSAndroid Build Coastguard Worker       break;
6874*795d594fSAndroid Build Coastguard Worker     }
6875*795d594fSAndroid Build Coastguard Worker 
6876*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint32:
6877*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kUint64:
6878*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kVoid:
6879*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable type " << instruction->GetType();
6880*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
6881*795d594fSAndroid Build Coastguard Worker   }
6882*795d594fSAndroid Build Coastguard Worker }
6883*795d594fSAndroid Build Coastguard Worker 
VisitArrayLength(HArrayLength * instruction)6884*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
6885*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6886*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
6887*795d594fSAndroid Build Coastguard Worker   if (!instruction->IsEmittedAtUseSite()) {
6888*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6889*795d594fSAndroid Build Coastguard Worker   }
6890*795d594fSAndroid Build Coastguard Worker }
6891*795d594fSAndroid Build Coastguard Worker 
VisitArrayLength(HArrayLength * instruction)6892*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
6893*795d594fSAndroid Build Coastguard Worker   if (instruction->IsEmittedAtUseSite()) {
6894*795d594fSAndroid Build Coastguard Worker     return;
6895*795d594fSAndroid Build Coastguard Worker   }
6896*795d594fSAndroid Build Coastguard Worker 
6897*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6898*795d594fSAndroid Build Coastguard Worker   uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
6899*795d594fSAndroid Build Coastguard Worker   Register obj = locations->InAt(0).AsRegister<Register>();
6900*795d594fSAndroid Build Coastguard Worker   Register out = locations->Out().AsRegister<Register>();
6901*795d594fSAndroid Build Coastguard Worker   __ movl(out, Address(obj, offset));
6902*795d594fSAndroid Build Coastguard Worker   codegen_->MaybeRecordImplicitNullCheck(instruction);
6903*795d594fSAndroid Build Coastguard Worker   // Mask out most significant bit in case the array is String's array of char.
6904*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression && instruction->IsStringLength()) {
6905*795d594fSAndroid Build Coastguard Worker     __ shrl(out, Immediate(1));
6906*795d594fSAndroid Build Coastguard Worker   }
6907*795d594fSAndroid Build Coastguard Worker }
6908*795d594fSAndroid Build Coastguard Worker 
VisitBoundsCheck(HBoundsCheck * instruction)6909*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
6910*795d594fSAndroid Build Coastguard Worker   RegisterSet caller_saves = RegisterSet::Empty();
6911*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
6912*795d594fSAndroid Build Coastguard Worker   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6913*795d594fSAndroid Build Coastguard Worker   caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6914*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
6915*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
6916*795d594fSAndroid Build Coastguard Worker   HInstruction* length = instruction->InputAt(1);
6917*795d594fSAndroid Build Coastguard Worker   if (!length->IsEmittedAtUseSite()) {
6918*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6919*795d594fSAndroid Build Coastguard Worker   }
6920*795d594fSAndroid Build Coastguard Worker   // Need register to see array's length.
6921*795d594fSAndroid Build Coastguard Worker   if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
6922*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(Location::RequiresRegister());
6923*795d594fSAndroid Build Coastguard Worker   }
6924*795d594fSAndroid Build Coastguard Worker }
6925*795d594fSAndroid Build Coastguard Worker 
VisitBoundsCheck(HBoundsCheck * instruction)6926*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
6927*795d594fSAndroid Build Coastguard Worker   const bool is_string_compressed_char_at =
6928*795d594fSAndroid Build Coastguard Worker       mirror::kUseStringCompression && instruction->IsStringCharAt();
6929*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
6930*795d594fSAndroid Build Coastguard Worker   Location index_loc = locations->InAt(0);
6931*795d594fSAndroid Build Coastguard Worker   Location length_loc = locations->InAt(1);
6932*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path =
6933*795d594fSAndroid Build Coastguard Worker     new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathX86(instruction);
6934*795d594fSAndroid Build Coastguard Worker 
6935*795d594fSAndroid Build Coastguard Worker   if (length_loc.IsConstant()) {
6936*795d594fSAndroid Build Coastguard Worker     int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
6937*795d594fSAndroid Build Coastguard Worker     if (index_loc.IsConstant()) {
6938*795d594fSAndroid Build Coastguard Worker       // BCE will remove the bounds check if we are guarenteed to pass.
6939*795d594fSAndroid Build Coastguard Worker       int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
6940*795d594fSAndroid Build Coastguard Worker       if (index < 0 || index >= length) {
6941*795d594fSAndroid Build Coastguard Worker         codegen_->AddSlowPath(slow_path);
6942*795d594fSAndroid Build Coastguard Worker         __ jmp(slow_path->GetEntryLabel());
6943*795d594fSAndroid Build Coastguard Worker       } else {
6944*795d594fSAndroid Build Coastguard Worker         // Some optimization after BCE may have generated this, and we should not
6945*795d594fSAndroid Build Coastguard Worker         // generate a bounds check if it is a valid range.
6946*795d594fSAndroid Build Coastguard Worker       }
6947*795d594fSAndroid Build Coastguard Worker       return;
6948*795d594fSAndroid Build Coastguard Worker     }
6949*795d594fSAndroid Build Coastguard Worker 
6950*795d594fSAndroid Build Coastguard Worker     // We have to reverse the jump condition because the length is the constant.
6951*795d594fSAndroid Build Coastguard Worker     Register index_reg = index_loc.AsRegister<Register>();
6952*795d594fSAndroid Build Coastguard Worker     __ cmpl(index_reg, Immediate(length));
6953*795d594fSAndroid Build Coastguard Worker     codegen_->AddSlowPath(slow_path);
6954*795d594fSAndroid Build Coastguard Worker     __ j(kAboveEqual, slow_path->GetEntryLabel());
6955*795d594fSAndroid Build Coastguard Worker   } else {
6956*795d594fSAndroid Build Coastguard Worker     HInstruction* array_length = instruction->InputAt(1);
6957*795d594fSAndroid Build Coastguard Worker     if (array_length->IsEmittedAtUseSite()) {
6958*795d594fSAndroid Build Coastguard Worker       // Address the length field in the array.
6959*795d594fSAndroid Build Coastguard Worker       DCHECK(array_length->IsArrayLength());
6960*795d594fSAndroid Build Coastguard Worker       uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
6961*795d594fSAndroid Build Coastguard Worker       Location array_loc = array_length->GetLocations()->InAt(0);
6962*795d594fSAndroid Build Coastguard Worker       Address array_len(array_loc.AsRegister<Register>(), len_offset);
6963*795d594fSAndroid Build Coastguard Worker       if (is_string_compressed_char_at) {
6964*795d594fSAndroid Build Coastguard Worker         // TODO: if index_loc.IsConstant(), compare twice the index (to compensate for
6965*795d594fSAndroid Build Coastguard Worker         // the string compression flag) with the in-memory length and avoid the temporary.
6966*795d594fSAndroid Build Coastguard Worker         Register length_reg = locations->GetTemp(0).AsRegister<Register>();
6967*795d594fSAndroid Build Coastguard Worker         __ movl(length_reg, array_len);
6968*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(array_length);
6969*795d594fSAndroid Build Coastguard Worker         __ shrl(length_reg, Immediate(1));
6970*795d594fSAndroid Build Coastguard Worker         codegen_->GenerateIntCompare(length_reg, index_loc);
6971*795d594fSAndroid Build Coastguard Worker       } else {
6972*795d594fSAndroid Build Coastguard Worker         // Checking bounds for general case:
6973*795d594fSAndroid Build Coastguard Worker         // Array of char or string's array with feature compression off.
6974*795d594fSAndroid Build Coastguard Worker         if (index_loc.IsConstant()) {
6975*795d594fSAndroid Build Coastguard Worker           int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
6976*795d594fSAndroid Build Coastguard Worker           __ cmpl(array_len, Immediate(value));
6977*795d594fSAndroid Build Coastguard Worker         } else {
6978*795d594fSAndroid Build Coastguard Worker           __ cmpl(array_len, index_loc.AsRegister<Register>());
6979*795d594fSAndroid Build Coastguard Worker         }
6980*795d594fSAndroid Build Coastguard Worker         codegen_->MaybeRecordImplicitNullCheck(array_length);
6981*795d594fSAndroid Build Coastguard Worker       }
6982*795d594fSAndroid Build Coastguard Worker     } else {
6983*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateIntCompare(length_loc, index_loc);
6984*795d594fSAndroid Build Coastguard Worker     }
6985*795d594fSAndroid Build Coastguard Worker     codegen_->AddSlowPath(slow_path);
6986*795d594fSAndroid Build Coastguard Worker     __ j(kBelowEqual, slow_path->GetEntryLabel());
6987*795d594fSAndroid Build Coastguard Worker   }
6988*795d594fSAndroid Build Coastguard Worker }
6989*795d594fSAndroid Build Coastguard Worker 
VisitParallelMove(HParallelMove * instruction)6990*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitParallelMove([[maybe_unused]] HParallelMove* instruction) {
6991*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
6992*795d594fSAndroid Build Coastguard Worker }
6993*795d594fSAndroid Build Coastguard Worker 
VisitParallelMove(HParallelMove * instruction)6994*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
6995*795d594fSAndroid Build Coastguard Worker   if (instruction->GetNext()->IsSuspendCheck() &&
6996*795d594fSAndroid Build Coastguard Worker       instruction->GetBlock()->GetLoopInformation() != nullptr) {
6997*795d594fSAndroid Build Coastguard Worker     HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
6998*795d594fSAndroid Build Coastguard Worker     // The back edge will generate the suspend check.
6999*795d594fSAndroid Build Coastguard Worker     codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
7000*795d594fSAndroid Build Coastguard Worker   }
7001*795d594fSAndroid Build Coastguard Worker 
7002*795d594fSAndroid Build Coastguard Worker   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
7003*795d594fSAndroid Build Coastguard Worker }
7004*795d594fSAndroid Build Coastguard Worker 
VisitSuspendCheck(HSuspendCheck * instruction)7005*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
7006*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
7007*795d594fSAndroid Build Coastguard Worker       instruction, LocationSummary::kCallOnSlowPath);
7008*795d594fSAndroid Build Coastguard Worker   // In suspend check slow path, usually there are no caller-save registers at all.
7009*795d594fSAndroid Build Coastguard Worker   // If SIMD instructions are present, however, we force spilling all live SIMD
7010*795d594fSAndroid Build Coastguard Worker   // registers in full width (since the runtime only saves/restores lower part).
7011*795d594fSAndroid Build Coastguard Worker   locations->SetCustomSlowPathCallerSaves(
7012*795d594fSAndroid Build Coastguard Worker       GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
7013*795d594fSAndroid Build Coastguard Worker }
7014*795d594fSAndroid Build Coastguard Worker 
VisitSuspendCheck(HSuspendCheck * instruction)7015*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
7016*795d594fSAndroid Build Coastguard Worker   HBasicBlock* block = instruction->GetBlock();
7017*795d594fSAndroid Build Coastguard Worker   if (block->GetLoopInformation() != nullptr) {
7018*795d594fSAndroid Build Coastguard Worker     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
7019*795d594fSAndroid Build Coastguard Worker     // The back edge will generate the suspend check.
7020*795d594fSAndroid Build Coastguard Worker     return;
7021*795d594fSAndroid Build Coastguard Worker   }
7022*795d594fSAndroid Build Coastguard Worker   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
7023*795d594fSAndroid Build Coastguard Worker     // The goto will generate the suspend check.
7024*795d594fSAndroid Build Coastguard Worker     return;
7025*795d594fSAndroid Build Coastguard Worker   }
7026*795d594fSAndroid Build Coastguard Worker   GenerateSuspendCheck(instruction, nullptr);
7027*795d594fSAndroid Build Coastguard Worker }
7028*795d594fSAndroid Build Coastguard Worker 
GenerateSuspendCheck(HSuspendCheck * instruction,HBasicBlock * successor)7029*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
7030*795d594fSAndroid Build Coastguard Worker                                                        HBasicBlock* successor) {
7031*795d594fSAndroid Build Coastguard Worker   SuspendCheckSlowPathX86* slow_path =
7032*795d594fSAndroid Build Coastguard Worker       down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
7033*795d594fSAndroid Build Coastguard Worker   if (slow_path == nullptr) {
7034*795d594fSAndroid Build Coastguard Worker     slow_path =
7035*795d594fSAndroid Build Coastguard Worker         new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathX86(instruction, successor);
7036*795d594fSAndroid Build Coastguard Worker     instruction->SetSlowPath(slow_path);
7037*795d594fSAndroid Build Coastguard Worker     codegen_->AddSlowPath(slow_path);
7038*795d594fSAndroid Build Coastguard Worker     if (successor != nullptr) {
7039*795d594fSAndroid Build Coastguard Worker       DCHECK(successor->IsLoopHeader());
7040*795d594fSAndroid Build Coastguard Worker     }
7041*795d594fSAndroid Build Coastguard Worker   } else {
7042*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(slow_path->GetSuccessor(), successor);
7043*795d594fSAndroid Build Coastguard Worker   }
7044*795d594fSAndroid Build Coastguard Worker 
7045*795d594fSAndroid Build Coastguard Worker   __ fs()->testl(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>().Int32Value()),
7046*795d594fSAndroid Build Coastguard Worker                  Immediate(Thread::SuspendOrCheckpointRequestFlags()));
7047*795d594fSAndroid Build Coastguard Worker   if (successor == nullptr) {
7048*795d594fSAndroid Build Coastguard Worker     __ j(kNotZero, slow_path->GetEntryLabel());
7049*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetReturnLabel());
7050*795d594fSAndroid Build Coastguard Worker   } else {
7051*795d594fSAndroid Build Coastguard Worker     __ j(kZero, codegen_->GetLabelOf(successor));
7052*795d594fSAndroid Build Coastguard Worker     __ jmp(slow_path->GetEntryLabel());
7053*795d594fSAndroid Build Coastguard Worker   }
7054*795d594fSAndroid Build Coastguard Worker }
7055*795d594fSAndroid Build Coastguard Worker 
GetAssembler() const7056*795d594fSAndroid Build Coastguard Worker X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
7057*795d594fSAndroid Build Coastguard Worker   return codegen_->GetAssembler();
7058*795d594fSAndroid Build Coastguard Worker }
7059*795d594fSAndroid Build Coastguard Worker 
MoveMemoryToMemory(int dst,int src,int number_of_words)7060*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src, int number_of_words) {
7061*795d594fSAndroid Build Coastguard Worker   ScratchRegisterScope ensure_scratch(
7062*795d594fSAndroid Build Coastguard Worker       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
7063*795d594fSAndroid Build Coastguard Worker   Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
7064*795d594fSAndroid Build Coastguard Worker   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
7065*795d594fSAndroid Build Coastguard Worker 
7066*795d594fSAndroid Build Coastguard Worker   // Now that temp register is available (possibly spilled), move blocks of memory.
7067*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < number_of_words; i++) {
7068*795d594fSAndroid Build Coastguard Worker     __ movl(temp_reg, Address(ESP, src + stack_offset));
7069*795d594fSAndroid Build Coastguard Worker     __ movl(Address(ESP, dst + stack_offset), temp_reg);
7070*795d594fSAndroid Build Coastguard Worker     stack_offset += kX86WordSize;
7071*795d594fSAndroid Build Coastguard Worker   }
7072*795d594fSAndroid Build Coastguard Worker }
7073*795d594fSAndroid Build Coastguard Worker 
EmitMove(size_t index)7074*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::EmitMove(size_t index) {
7075*795d594fSAndroid Build Coastguard Worker   MoveOperands* move = moves_[index];
7076*795d594fSAndroid Build Coastguard Worker   Location source = move->GetSource();
7077*795d594fSAndroid Build Coastguard Worker   Location destination = move->GetDestination();
7078*795d594fSAndroid Build Coastguard Worker 
7079*795d594fSAndroid Build Coastguard Worker   if (source.IsRegister()) {
7080*795d594fSAndroid Build Coastguard Worker     if (destination.IsRegister()) {
7081*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
7082*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsFpuRegister()) {
7083*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
7084*795d594fSAndroid Build Coastguard Worker     } else {
7085*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsStackSlot());
7086*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
7087*795d594fSAndroid Build Coastguard Worker     }
7088*795d594fSAndroid Build Coastguard Worker   } else if (source.IsRegisterPair()) {
7089*795d594fSAndroid Build Coastguard Worker     if (destination.IsRegisterPair()) {
7090*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
7091*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
7092*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
7093*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsFpuRegister()) {
7094*795d594fSAndroid Build Coastguard Worker       size_t elem_size = DataType::Size(DataType::Type::kInt32);
7095*795d594fSAndroid Build Coastguard Worker       // Push the 2 source registers to the stack.
7096*795d594fSAndroid Build Coastguard Worker       __ pushl(source.AsRegisterPairHigh<Register>());
7097*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(elem_size);
7098*795d594fSAndroid Build Coastguard Worker       __ pushl(source.AsRegisterPairLow<Register>());
7099*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(elem_size);
7100*795d594fSAndroid Build Coastguard Worker       // Load the destination register.
7101*795d594fSAndroid Build Coastguard Worker       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
7102*795d594fSAndroid Build Coastguard Worker       // And remove the temporary stack space we allocated.
7103*795d594fSAndroid Build Coastguard Worker       codegen_->DecreaseFrame(2 * elem_size);
7104*795d594fSAndroid Build Coastguard Worker     } else {
7105*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsDoubleStackSlot());
7106*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
7107*795d594fSAndroid Build Coastguard Worker       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
7108*795d594fSAndroid Build Coastguard Worker               source.AsRegisterPairHigh<Register>());
7109*795d594fSAndroid Build Coastguard Worker     }
7110*795d594fSAndroid Build Coastguard Worker   } else if (source.IsFpuRegister()) {
7111*795d594fSAndroid Build Coastguard Worker     if (destination.IsRegister()) {
7112*795d594fSAndroid Build Coastguard Worker       __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
7113*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsFpuRegister()) {
7114*795d594fSAndroid Build Coastguard Worker       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
7115*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsRegisterPair()) {
7116*795d594fSAndroid Build Coastguard Worker       size_t elem_size = DataType::Size(DataType::Type::kInt32);
7117*795d594fSAndroid Build Coastguard Worker       // Create stack space for 2 elements.
7118*795d594fSAndroid Build Coastguard Worker       codegen_->IncreaseFrame(2 * elem_size);
7119*795d594fSAndroid Build Coastguard Worker       // Store the source register.
7120*795d594fSAndroid Build Coastguard Worker       __ movsd(Address(ESP, 0), source.AsFpuRegister<XmmRegister>());
7121*795d594fSAndroid Build Coastguard Worker       // And pop the values into destination registers.
7122*795d594fSAndroid Build Coastguard Worker       __ popl(destination.AsRegisterPairLow<Register>());
7123*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(-elem_size);
7124*795d594fSAndroid Build Coastguard Worker       __ popl(destination.AsRegisterPairHigh<Register>());
7125*795d594fSAndroid Build Coastguard Worker       __ cfi().AdjustCFAOffset(-elem_size);
7126*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsStackSlot()) {
7127*795d594fSAndroid Build Coastguard Worker       __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
7128*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsDoubleStackSlot()) {
7129*795d594fSAndroid Build Coastguard Worker       __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
7130*795d594fSAndroid Build Coastguard Worker     } else {
7131*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsSIMDStackSlot());
7132*795d594fSAndroid Build Coastguard Worker       __ movups(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
7133*795d594fSAndroid Build Coastguard Worker     }
7134*795d594fSAndroid Build Coastguard Worker   } else if (source.IsStackSlot()) {
7135*795d594fSAndroid Build Coastguard Worker     if (destination.IsRegister()) {
7136*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
7137*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsFpuRegister()) {
7138*795d594fSAndroid Build Coastguard Worker       __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
7139*795d594fSAndroid Build Coastguard Worker     } else {
7140*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsStackSlot());
7141*795d594fSAndroid Build Coastguard Worker       MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
7142*795d594fSAndroid Build Coastguard Worker     }
7143*795d594fSAndroid Build Coastguard Worker   } else if (source.IsDoubleStackSlot()) {
7144*795d594fSAndroid Build Coastguard Worker     if (destination.IsRegisterPair()) {
7145*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
7146*795d594fSAndroid Build Coastguard Worker       __ movl(destination.AsRegisterPairHigh<Register>(),
7147*795d594fSAndroid Build Coastguard Worker               Address(ESP, source.GetHighStackIndex(kX86WordSize)));
7148*795d594fSAndroid Build Coastguard Worker     } else if (destination.IsFpuRegister()) {
7149*795d594fSAndroid Build Coastguard Worker       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
7150*795d594fSAndroid Build Coastguard Worker     } else {
7151*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsDoubleStackSlot()) << destination;
7152*795d594fSAndroid Build Coastguard Worker       MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
7153*795d594fSAndroid Build Coastguard Worker     }
7154*795d594fSAndroid Build Coastguard Worker   } else if (source.IsSIMDStackSlot()) {
7155*795d594fSAndroid Build Coastguard Worker     if (destination.IsFpuRegister()) {
7156*795d594fSAndroid Build Coastguard Worker       __ movups(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
7157*795d594fSAndroid Build Coastguard Worker     } else {
7158*795d594fSAndroid Build Coastguard Worker       DCHECK(destination.IsSIMDStackSlot());
7159*795d594fSAndroid Build Coastguard Worker       MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
7160*795d594fSAndroid Build Coastguard Worker     }
7161*795d594fSAndroid Build Coastguard Worker   } else if (source.IsConstant()) {
7162*795d594fSAndroid Build Coastguard Worker     HConstant* constant = source.GetConstant();
7163*795d594fSAndroid Build Coastguard Worker     if (constant->IsIntConstant() || constant->IsNullConstant()) {
7164*795d594fSAndroid Build Coastguard Worker       int32_t value = CodeGenerator::GetInt32ValueOf(constant);
7165*795d594fSAndroid Build Coastguard Worker       if (destination.IsRegister()) {
7166*795d594fSAndroid Build Coastguard Worker         if (value == 0) {
7167*795d594fSAndroid Build Coastguard Worker           __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
7168*795d594fSAndroid Build Coastguard Worker         } else {
7169*795d594fSAndroid Build Coastguard Worker           __ movl(destination.AsRegister<Register>(), Immediate(value));
7170*795d594fSAndroid Build Coastguard Worker         }
7171*795d594fSAndroid Build Coastguard Worker       } else {
7172*795d594fSAndroid Build Coastguard Worker         DCHECK(destination.IsStackSlot()) << destination;
7173*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
7174*795d594fSAndroid Build Coastguard Worker       }
7175*795d594fSAndroid Build Coastguard Worker     } else if (constant->IsFloatConstant()) {
7176*795d594fSAndroid Build Coastguard Worker       float fp_value = constant->AsFloatConstant()->GetValue();
7177*795d594fSAndroid Build Coastguard Worker       int32_t value = bit_cast<int32_t, float>(fp_value);
7178*795d594fSAndroid Build Coastguard Worker       Immediate imm(value);
7179*795d594fSAndroid Build Coastguard Worker       if (destination.IsFpuRegister()) {
7180*795d594fSAndroid Build Coastguard Worker         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
7181*795d594fSAndroid Build Coastguard Worker         if (value == 0) {
7182*795d594fSAndroid Build Coastguard Worker           // Easy handling of 0.0.
7183*795d594fSAndroid Build Coastguard Worker           __ xorps(dest, dest);
7184*795d594fSAndroid Build Coastguard Worker         } else {
7185*795d594fSAndroid Build Coastguard Worker           ScratchRegisterScope ensure_scratch(
7186*795d594fSAndroid Build Coastguard Worker               this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
7187*795d594fSAndroid Build Coastguard Worker           Register temp = static_cast<Register>(ensure_scratch.GetRegister());
7188*795d594fSAndroid Build Coastguard Worker           __ movl(temp, Immediate(value));
7189*795d594fSAndroid Build Coastguard Worker           __ movd(dest, temp);
7190*795d594fSAndroid Build Coastguard Worker         }
7191*795d594fSAndroid Build Coastguard Worker       } else {
7192*795d594fSAndroid Build Coastguard Worker         DCHECK(destination.IsStackSlot()) << destination;
7193*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetStackIndex()), imm);
7194*795d594fSAndroid Build Coastguard Worker       }
7195*795d594fSAndroid Build Coastguard Worker     } else if (constant->IsLongConstant()) {
7196*795d594fSAndroid Build Coastguard Worker       int64_t value = constant->AsLongConstant()->GetValue();
7197*795d594fSAndroid Build Coastguard Worker       int32_t low_value = Low32Bits(value);
7198*795d594fSAndroid Build Coastguard Worker       int32_t high_value = High32Bits(value);
7199*795d594fSAndroid Build Coastguard Worker       Immediate low(low_value);
7200*795d594fSAndroid Build Coastguard Worker       Immediate high(high_value);
7201*795d594fSAndroid Build Coastguard Worker       if (destination.IsDoubleStackSlot()) {
7202*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetStackIndex()), low);
7203*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
7204*795d594fSAndroid Build Coastguard Worker       } else {
7205*795d594fSAndroid Build Coastguard Worker         __ movl(destination.AsRegisterPairLow<Register>(), low);
7206*795d594fSAndroid Build Coastguard Worker         __ movl(destination.AsRegisterPairHigh<Register>(), high);
7207*795d594fSAndroid Build Coastguard Worker       }
7208*795d594fSAndroid Build Coastguard Worker     } else {
7209*795d594fSAndroid Build Coastguard Worker       DCHECK(constant->IsDoubleConstant());
7210*795d594fSAndroid Build Coastguard Worker       double dbl_value = constant->AsDoubleConstant()->GetValue();
7211*795d594fSAndroid Build Coastguard Worker       int64_t value = bit_cast<int64_t, double>(dbl_value);
7212*795d594fSAndroid Build Coastguard Worker       int32_t low_value = Low32Bits(value);
7213*795d594fSAndroid Build Coastguard Worker       int32_t high_value = High32Bits(value);
7214*795d594fSAndroid Build Coastguard Worker       Immediate low(low_value);
7215*795d594fSAndroid Build Coastguard Worker       Immediate high(high_value);
7216*795d594fSAndroid Build Coastguard Worker       if (destination.IsFpuRegister()) {
7217*795d594fSAndroid Build Coastguard Worker         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
7218*795d594fSAndroid Build Coastguard Worker         if (value == 0) {
7219*795d594fSAndroid Build Coastguard Worker           // Easy handling of 0.0.
7220*795d594fSAndroid Build Coastguard Worker           __ xorpd(dest, dest);
7221*795d594fSAndroid Build Coastguard Worker         } else {
7222*795d594fSAndroid Build Coastguard Worker           __ pushl(high);
7223*795d594fSAndroid Build Coastguard Worker           __ cfi().AdjustCFAOffset(4);
7224*795d594fSAndroid Build Coastguard Worker           __ pushl(low);
7225*795d594fSAndroid Build Coastguard Worker           __ cfi().AdjustCFAOffset(4);
7226*795d594fSAndroid Build Coastguard Worker           __ movsd(dest, Address(ESP, 0));
7227*795d594fSAndroid Build Coastguard Worker           codegen_->DecreaseFrame(8);
7228*795d594fSAndroid Build Coastguard Worker         }
7229*795d594fSAndroid Build Coastguard Worker       } else {
7230*795d594fSAndroid Build Coastguard Worker         DCHECK(destination.IsDoubleStackSlot()) << destination;
7231*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetStackIndex()), low);
7232*795d594fSAndroid Build Coastguard Worker         __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
7233*795d594fSAndroid Build Coastguard Worker       }
7234*795d594fSAndroid Build Coastguard Worker     }
7235*795d594fSAndroid Build Coastguard Worker   } else {
7236*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
7237*795d594fSAndroid Build Coastguard Worker   }
7238*795d594fSAndroid Build Coastguard Worker }
7239*795d594fSAndroid Build Coastguard Worker 
Exchange(Register reg,int mem)7240*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
7241*795d594fSAndroid Build Coastguard Worker   Register suggested_scratch = reg == EAX ? EBX : EAX;
7242*795d594fSAndroid Build Coastguard Worker   ScratchRegisterScope ensure_scratch(
7243*795d594fSAndroid Build Coastguard Worker       this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
7244*795d594fSAndroid Build Coastguard Worker 
7245*795d594fSAndroid Build Coastguard Worker   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
7246*795d594fSAndroid Build Coastguard Worker   __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
7247*795d594fSAndroid Build Coastguard Worker   __ movl(Address(ESP, mem + stack_offset), reg);
7248*795d594fSAndroid Build Coastguard Worker   __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
7249*795d594fSAndroid Build Coastguard Worker }
7250*795d594fSAndroid Build Coastguard Worker 
Exchange32(XmmRegister reg,int mem)7251*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
7252*795d594fSAndroid Build Coastguard Worker   ScratchRegisterScope ensure_scratch(
7253*795d594fSAndroid Build Coastguard Worker       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
7254*795d594fSAndroid Build Coastguard Worker 
7255*795d594fSAndroid Build Coastguard Worker   Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
7256*795d594fSAndroid Build Coastguard Worker   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
7257*795d594fSAndroid Build Coastguard Worker   __ movl(temp_reg, Address(ESP, mem + stack_offset));
7258*795d594fSAndroid Build Coastguard Worker   __ movss(Address(ESP, mem + stack_offset), reg);
7259*795d594fSAndroid Build Coastguard Worker   __ movd(reg, temp_reg);
7260*795d594fSAndroid Build Coastguard Worker }
7261*795d594fSAndroid Build Coastguard Worker 
Exchange128(XmmRegister reg,int mem)7262*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::Exchange128(XmmRegister reg, int mem) {
7263*795d594fSAndroid Build Coastguard Worker   size_t extra_slot = 4 * kX86WordSize;
7264*795d594fSAndroid Build Coastguard Worker   codegen_->IncreaseFrame(extra_slot);
7265*795d594fSAndroid Build Coastguard Worker   __ movups(Address(ESP, 0), XmmRegister(reg));
7266*795d594fSAndroid Build Coastguard Worker   ExchangeMemory(0, mem + extra_slot, 4);
7267*795d594fSAndroid Build Coastguard Worker   __ movups(XmmRegister(reg), Address(ESP, 0));
7268*795d594fSAndroid Build Coastguard Worker   codegen_->DecreaseFrame(extra_slot);
7269*795d594fSAndroid Build Coastguard Worker }
7270*795d594fSAndroid Build Coastguard Worker 
ExchangeMemory(int mem1,int mem2,int number_of_words)7271*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::ExchangeMemory(int mem1, int mem2, int number_of_words) {
7272*795d594fSAndroid Build Coastguard Worker   ScratchRegisterScope ensure_scratch1(
7273*795d594fSAndroid Build Coastguard Worker       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
7274*795d594fSAndroid Build Coastguard Worker 
7275*795d594fSAndroid Build Coastguard Worker   Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
7276*795d594fSAndroid Build Coastguard Worker   ScratchRegisterScope ensure_scratch2(
7277*795d594fSAndroid Build Coastguard Worker       this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
7278*795d594fSAndroid Build Coastguard Worker 
7279*795d594fSAndroid Build Coastguard Worker   int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
7280*795d594fSAndroid Build Coastguard Worker   stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
7281*795d594fSAndroid Build Coastguard Worker 
7282*795d594fSAndroid Build Coastguard Worker   // Now that temp registers are available (possibly spilled), exchange blocks of memory.
7283*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < number_of_words; i++) {
7284*795d594fSAndroid Build Coastguard Worker     __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
7285*795d594fSAndroid Build Coastguard Worker     __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
7286*795d594fSAndroid Build Coastguard Worker     __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
7287*795d594fSAndroid Build Coastguard Worker     __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
7288*795d594fSAndroid Build Coastguard Worker     stack_offset += kX86WordSize;
7289*795d594fSAndroid Build Coastguard Worker   }
7290*795d594fSAndroid Build Coastguard Worker }
7291*795d594fSAndroid Build Coastguard Worker 
EmitSwap(size_t index)7292*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::EmitSwap(size_t index) {
7293*795d594fSAndroid Build Coastguard Worker   MoveOperands* move = moves_[index];
7294*795d594fSAndroid Build Coastguard Worker   Location source = move->GetSource();
7295*795d594fSAndroid Build Coastguard Worker   Location destination = move->GetDestination();
7296*795d594fSAndroid Build Coastguard Worker 
7297*795d594fSAndroid Build Coastguard Worker   if (source.IsRegister() && destination.IsRegister()) {
7298*795d594fSAndroid Build Coastguard Worker     // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
7299*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
7300*795d594fSAndroid Build Coastguard Worker     __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
7301*795d594fSAndroid Build Coastguard Worker     __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
7302*795d594fSAndroid Build Coastguard Worker     __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
7303*795d594fSAndroid Build Coastguard Worker   } else if (source.IsRegister() && destination.IsStackSlot()) {
7304*795d594fSAndroid Build Coastguard Worker     Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
7305*795d594fSAndroid Build Coastguard Worker   } else if (source.IsStackSlot() && destination.IsRegister()) {
7306*795d594fSAndroid Build Coastguard Worker     Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
7307*795d594fSAndroid Build Coastguard Worker   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
7308*795d594fSAndroid Build Coastguard Worker     ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
7309*795d594fSAndroid Build Coastguard Worker   } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
7310*795d594fSAndroid Build Coastguard Worker     // Use XOR Swap algorithm to avoid a temporary.
7311*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(source.reg(), destination.reg());
7312*795d594fSAndroid Build Coastguard Worker     __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
7313*795d594fSAndroid Build Coastguard Worker     __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
7314*795d594fSAndroid Build Coastguard Worker     __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
7315*795d594fSAndroid Build Coastguard Worker   } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
7316*795d594fSAndroid Build Coastguard Worker     Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
7317*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
7318*795d594fSAndroid Build Coastguard Worker     Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
7319*795d594fSAndroid Build Coastguard Worker   } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
7320*795d594fSAndroid Build Coastguard Worker     // Take advantage of the 16 bytes in the XMM register.
7321*795d594fSAndroid Build Coastguard Worker     XmmRegister reg = source.AsFpuRegister<XmmRegister>();
7322*795d594fSAndroid Build Coastguard Worker     Address stack(ESP, destination.GetStackIndex());
7323*795d594fSAndroid Build Coastguard Worker     // Load the double into the high doubleword.
7324*795d594fSAndroid Build Coastguard Worker     __ movhpd(reg, stack);
7325*795d594fSAndroid Build Coastguard Worker 
7326*795d594fSAndroid Build Coastguard Worker     // Store the low double into the destination.
7327*795d594fSAndroid Build Coastguard Worker     __ movsd(stack, reg);
7328*795d594fSAndroid Build Coastguard Worker 
7329*795d594fSAndroid Build Coastguard Worker     // Move the high double to the low double.
7330*795d594fSAndroid Build Coastguard Worker     __ psrldq(reg, Immediate(8));
7331*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
7332*795d594fSAndroid Build Coastguard Worker     // Take advantage of the 16 bytes in the XMM register.
7333*795d594fSAndroid Build Coastguard Worker     XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
7334*795d594fSAndroid Build Coastguard Worker     Address stack(ESP, source.GetStackIndex());
7335*795d594fSAndroid Build Coastguard Worker     // Load the double into the high doubleword.
7336*795d594fSAndroid Build Coastguard Worker     __ movhpd(reg, stack);
7337*795d594fSAndroid Build Coastguard Worker 
7338*795d594fSAndroid Build Coastguard Worker     // Store the low double into the destination.
7339*795d594fSAndroid Build Coastguard Worker     __ movsd(stack, reg);
7340*795d594fSAndroid Build Coastguard Worker 
7341*795d594fSAndroid Build Coastguard Worker     // Move the high double to the low double.
7342*795d594fSAndroid Build Coastguard Worker     __ psrldq(reg, Immediate(8));
7343*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
7344*795d594fSAndroid Build Coastguard Worker     ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
7345*795d594fSAndroid Build Coastguard Worker   } else if (source.IsSIMDStackSlot() && destination.IsSIMDStackSlot()) {
7346*795d594fSAndroid Build Coastguard Worker     ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
7347*795d594fSAndroid Build Coastguard Worker   } else if (source.IsFpuRegister() && destination.IsSIMDStackSlot()) {
7348*795d594fSAndroid Build Coastguard Worker     Exchange128(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
7349*795d594fSAndroid Build Coastguard Worker   } else if (destination.IsFpuRegister() && source.IsSIMDStackSlot()) {
7350*795d594fSAndroid Build Coastguard Worker     Exchange128(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
7351*795d594fSAndroid Build Coastguard Worker   } else {
7352*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
7353*795d594fSAndroid Build Coastguard Worker   }
7354*795d594fSAndroid Build Coastguard Worker }
7355*795d594fSAndroid Build Coastguard Worker 
SpillScratch(int reg)7356*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::SpillScratch(int reg) {
7357*795d594fSAndroid Build Coastguard Worker   __ pushl(static_cast<Register>(reg));
7358*795d594fSAndroid Build Coastguard Worker }
7359*795d594fSAndroid Build Coastguard Worker 
RestoreScratch(int reg)7360*795d594fSAndroid Build Coastguard Worker void ParallelMoveResolverX86::RestoreScratch(int reg) {
7361*795d594fSAndroid Build Coastguard Worker   __ popl(static_cast<Register>(reg));
7362*795d594fSAndroid Build Coastguard Worker }
7363*795d594fSAndroid Build Coastguard Worker 
GetSupportedLoadClassKind(HLoadClass::LoadKind desired_class_load_kind)7364*795d594fSAndroid Build Coastguard Worker HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind(
7365*795d594fSAndroid Build Coastguard Worker     HLoadClass::LoadKind desired_class_load_kind) {
7366*795d594fSAndroid Build Coastguard Worker   switch (desired_class_load_kind) {
7367*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kInvalid:
7368*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "UNREACHABLE";
7369*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
7370*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kReferrersClass:
7371*795d594fSAndroid Build Coastguard Worker       break;
7372*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
7373*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBootImageRelRo:
7374*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kAppImageRelRo:
7375*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntry:
7376*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPublic:
7377*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPackage:
7378*795d594fSAndroid Build Coastguard Worker       DCHECK(!GetCompilerOptions().IsJitCompiler());
7379*795d594fSAndroid Build Coastguard Worker       break;
7380*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kJitBootImageAddress:
7381*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kJitTableAddress:
7382*795d594fSAndroid Build Coastguard Worker       DCHECK(GetCompilerOptions().IsJitCompiler());
7383*795d594fSAndroid Build Coastguard Worker       break;
7384*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kRuntimeCall:
7385*795d594fSAndroid Build Coastguard Worker       break;
7386*795d594fSAndroid Build Coastguard Worker   }
7387*795d594fSAndroid Build Coastguard Worker   return desired_class_load_kind;
7388*795d594fSAndroid Build Coastguard Worker }
7389*795d594fSAndroid Build Coastguard Worker 
VisitLoadClass(HLoadClass * cls)7390*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
7391*795d594fSAndroid Build Coastguard Worker   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7392*795d594fSAndroid Build Coastguard Worker   if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
7393*795d594fSAndroid Build Coastguard Worker     InvokeRuntimeCallingConvention calling_convention;
7394*795d594fSAndroid Build Coastguard Worker     CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
7395*795d594fSAndroid Build Coastguard Worker         cls,
7396*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
7397*795d594fSAndroid Build Coastguard Worker         Location::RegisterLocation(EAX));
7398*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(calling_convention.GetRegisterAt(0), EAX);
7399*795d594fSAndroid Build Coastguard Worker     return;
7400*795d594fSAndroid Build Coastguard Worker   }
7401*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(cls->NeedsAccessCheck(),
7402*795d594fSAndroid Build Coastguard Worker             load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
7403*795d594fSAndroid Build Coastguard Worker                 load_kind == HLoadClass::LoadKind::kBssEntryPackage);
7404*795d594fSAndroid Build Coastguard Worker 
7405*795d594fSAndroid Build Coastguard Worker   const bool requires_read_barrier = !cls->IsInImage() && codegen_->EmitReadBarrier();
7406*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
7407*795d594fSAndroid Build Coastguard Worker       ? LocationSummary::kCallOnSlowPath
7408*795d594fSAndroid Build Coastguard Worker       : LocationSummary::kNoCall;
7409*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
7410*795d594fSAndroid Build Coastguard Worker   if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
7411*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
7412*795d594fSAndroid Build Coastguard Worker   }
7413*795d594fSAndroid Build Coastguard Worker 
7414*795d594fSAndroid Build Coastguard Worker   if (load_kind == HLoadClass::LoadKind::kReferrersClass || cls->HasPcRelativeLoadKind()) {
7415*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
7416*795d594fSAndroid Build Coastguard Worker   }
7417*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
7418*795d594fSAndroid Build Coastguard Worker   if (call_kind == LocationSummary::kCallOnSlowPath && cls->HasPcRelativeLoadKind()) {
7419*795d594fSAndroid Build Coastguard Worker     if (codegen_->EmitNonBakerReadBarrier()) {
7420*795d594fSAndroid Build Coastguard Worker       // For non-Baker read barrier we have a temp-clobbering call.
7421*795d594fSAndroid Build Coastguard Worker     } else {
7422*795d594fSAndroid Build Coastguard Worker       // Rely on the type resolution and/or initialization to save everything.
7423*795d594fSAndroid Build Coastguard Worker       locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
7424*795d594fSAndroid Build Coastguard Worker     }
7425*795d594fSAndroid Build Coastguard Worker   }
7426*795d594fSAndroid Build Coastguard Worker }
7427*795d594fSAndroid Build Coastguard Worker 
NewJitRootClassPatch(const DexFile & dex_file,dex::TypeIndex type_index,Handle<mirror::Class> handle)7428*795d594fSAndroid Build Coastguard Worker Label* CodeGeneratorX86::NewJitRootClassPatch(const DexFile& dex_file,
7429*795d594fSAndroid Build Coastguard Worker                                               dex::TypeIndex type_index,
7430*795d594fSAndroid Build Coastguard Worker                                               Handle<mirror::Class> handle) {
7431*795d594fSAndroid Build Coastguard Worker   ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
7432*795d594fSAndroid Build Coastguard Worker   // Add a patch entry and return the label.
7433*795d594fSAndroid Build Coastguard Worker   jit_class_patches_.emplace_back(&dex_file, type_index.index_);
7434*795d594fSAndroid Build Coastguard Worker   PatchInfo<Label>* info = &jit_class_patches_.back();
7435*795d594fSAndroid Build Coastguard Worker   return &info->label;
7436*795d594fSAndroid Build Coastguard Worker }
7437*795d594fSAndroid Build Coastguard Worker 
7438*795d594fSAndroid Build Coastguard Worker // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7439*795d594fSAndroid Build Coastguard Worker // move.
VisitLoadClass(HLoadClass * cls)7440*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
7441*795d594fSAndroid Build Coastguard Worker   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7442*795d594fSAndroid Build Coastguard Worker   if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
7443*795d594fSAndroid Build Coastguard Worker     codegen_->GenerateLoadClassRuntimeCall(cls);
7444*795d594fSAndroid Build Coastguard Worker     return;
7445*795d594fSAndroid Build Coastguard Worker   }
7446*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(cls->NeedsAccessCheck(),
7447*795d594fSAndroid Build Coastguard Worker             load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
7448*795d594fSAndroid Build Coastguard Worker                 load_kind == HLoadClass::LoadKind::kBssEntryPackage);
7449*795d594fSAndroid Build Coastguard Worker 
7450*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = cls->GetLocations();
7451*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
7452*795d594fSAndroid Build Coastguard Worker   Register out = out_loc.AsRegister<Register>();
7453*795d594fSAndroid Build Coastguard Worker 
7454*795d594fSAndroid Build Coastguard Worker   bool generate_null_check = false;
7455*795d594fSAndroid Build Coastguard Worker   const ReadBarrierOption read_barrier_option =
7456*795d594fSAndroid Build Coastguard Worker       cls->IsInImage() ? kWithoutReadBarrier : codegen_->GetCompilerReadBarrierOption();
7457*795d594fSAndroid Build Coastguard Worker   switch (load_kind) {
7458*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kReferrersClass: {
7459*795d594fSAndroid Build Coastguard Worker       DCHECK(!cls->CanCallRuntime());
7460*795d594fSAndroid Build Coastguard Worker       DCHECK(!cls->MustGenerateClinitCheck());
7461*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7462*795d594fSAndroid Build Coastguard Worker       Register current_method = locations->InAt(0).AsRegister<Register>();
7463*795d594fSAndroid Build Coastguard Worker       GenerateGcRootFieldLoad(
7464*795d594fSAndroid Build Coastguard Worker           cls,
7465*795d594fSAndroid Build Coastguard Worker           out_loc,
7466*795d594fSAndroid Build Coastguard Worker           Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
7467*795d594fSAndroid Build Coastguard Worker           /* fixup_label= */ nullptr,
7468*795d594fSAndroid Build Coastguard Worker           read_barrier_option);
7469*795d594fSAndroid Build Coastguard Worker       break;
7470*795d594fSAndroid Build Coastguard Worker     }
7471*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
7472*795d594fSAndroid Build Coastguard Worker       DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
7473*795d594fSAndroid Build Coastguard Worker              codegen_->GetCompilerOptions().IsBootImageExtension());
7474*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7475*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7476*795d594fSAndroid Build Coastguard Worker       __ leal(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
7477*795d594fSAndroid Build Coastguard Worker       codegen_->RecordBootImageTypePatch(cls);
7478*795d594fSAndroid Build Coastguard Worker       break;
7479*795d594fSAndroid Build Coastguard Worker     }
7480*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBootImageRelRo: {
7481*795d594fSAndroid Build Coastguard Worker       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7482*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7483*795d594fSAndroid Build Coastguard Worker       __ movl(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
7484*795d594fSAndroid Build Coastguard Worker       codegen_->RecordBootImageRelRoPatch(cls->InputAt(0)->AsX86ComputeBaseMethodAddress(),
7485*795d594fSAndroid Build Coastguard Worker                                           CodeGenerator::GetBootImageOffset(cls));
7486*795d594fSAndroid Build Coastguard Worker       break;
7487*795d594fSAndroid Build Coastguard Worker     }
7488*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kAppImageRelRo: {
7489*795d594fSAndroid Build Coastguard Worker       DCHECK(codegen_->GetCompilerOptions().IsAppImage());
7490*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7491*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7492*795d594fSAndroid Build Coastguard Worker       __ movl(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
7493*795d594fSAndroid Build Coastguard Worker       codegen_->RecordAppImageTypePatch(cls);
7494*795d594fSAndroid Build Coastguard Worker       break;
7495*795d594fSAndroid Build Coastguard Worker     }
7496*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntry:
7497*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPublic:
7498*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kBssEntryPackage: {
7499*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7500*795d594fSAndroid Build Coastguard Worker       Address address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset);
7501*795d594fSAndroid Build Coastguard Worker       Label* fixup_label = codegen_->NewTypeBssEntryPatch(cls);
7502*795d594fSAndroid Build Coastguard Worker       GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
7503*795d594fSAndroid Build Coastguard Worker       // No need for memory fence, thanks to the x86 memory model.
7504*795d594fSAndroid Build Coastguard Worker       generate_null_check = true;
7505*795d594fSAndroid Build Coastguard Worker       break;
7506*795d594fSAndroid Build Coastguard Worker     }
7507*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kJitBootImageAddress: {
7508*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7509*795d594fSAndroid Build Coastguard Worker       uint32_t address = reinterpret_cast32<uint32_t>(cls->GetClass().Get());
7510*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(address, 0u);
7511*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(address));
7512*795d594fSAndroid Build Coastguard Worker       break;
7513*795d594fSAndroid Build Coastguard Worker     }
7514*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kJitTableAddress: {
7515*795d594fSAndroid Build Coastguard Worker       Address address = Address::Absolute(CodeGeneratorX86::kPlaceholder32BitOffset);
7516*795d594fSAndroid Build Coastguard Worker       Label* fixup_label = codegen_->NewJitRootClassPatch(
7517*795d594fSAndroid Build Coastguard Worker           cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
7518*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::Class> */ out = *address
7519*795d594fSAndroid Build Coastguard Worker       GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
7520*795d594fSAndroid Build Coastguard Worker       break;
7521*795d594fSAndroid Build Coastguard Worker     }
7522*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kRuntimeCall:
7523*795d594fSAndroid Build Coastguard Worker     case HLoadClass::LoadKind::kInvalid:
7524*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "UNREACHABLE";
7525*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
7526*795d594fSAndroid Build Coastguard Worker   }
7527*795d594fSAndroid Build Coastguard Worker 
7528*795d594fSAndroid Build Coastguard Worker   if (generate_null_check || cls->MustGenerateClinitCheck()) {
7529*795d594fSAndroid Build Coastguard Worker     DCHECK(cls->CanCallRuntime());
7530*795d594fSAndroid Build Coastguard Worker     SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86(cls, cls);
7531*795d594fSAndroid Build Coastguard Worker     codegen_->AddSlowPath(slow_path);
7532*795d594fSAndroid Build Coastguard Worker 
7533*795d594fSAndroid Build Coastguard Worker     if (generate_null_check) {
7534*795d594fSAndroid Build Coastguard Worker       __ testl(out, out);
7535*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, slow_path->GetEntryLabel());
7536*795d594fSAndroid Build Coastguard Worker     }
7537*795d594fSAndroid Build Coastguard Worker 
7538*795d594fSAndroid Build Coastguard Worker     if (cls->MustGenerateClinitCheck()) {
7539*795d594fSAndroid Build Coastguard Worker       GenerateClassInitializationCheck(slow_path, out);
7540*795d594fSAndroid Build Coastguard Worker     } else {
7541*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetExitLabel());
7542*795d594fSAndroid Build Coastguard Worker     }
7543*795d594fSAndroid Build Coastguard Worker   }
7544*795d594fSAndroid Build Coastguard Worker }
7545*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodHandle(HLoadMethodHandle * load)7546*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
7547*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
7548*795d594fSAndroid Build Coastguard Worker   Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
7549*795d594fSAndroid Build Coastguard Worker   CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
7550*795d594fSAndroid Build Coastguard Worker }
7551*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodHandle(HLoadMethodHandle * load)7552*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
7553*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateLoadMethodHandleRuntimeCall(load);
7554*795d594fSAndroid Build Coastguard Worker }
7555*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodType(HLoadMethodType * load)7556*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
7557*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
7558*795d594fSAndroid Build Coastguard Worker   Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
7559*795d594fSAndroid Build Coastguard Worker   CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
7560*795d594fSAndroid Build Coastguard Worker }
7561*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodType(HLoadMethodType * load)7562*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) {
7563*795d594fSAndroid Build Coastguard Worker   codegen_->GenerateLoadMethodTypeRuntimeCall(load);
7564*795d594fSAndroid Build Coastguard Worker }
7565*795d594fSAndroid Build Coastguard Worker 
VisitClinitCheck(HClinitCheck * check)7566*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
7567*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
7568*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
7569*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
7570*795d594fSAndroid Build Coastguard Worker   if (check->HasUses()) {
7571*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::SameAsFirstInput());
7572*795d594fSAndroid Build Coastguard Worker   }
7573*795d594fSAndroid Build Coastguard Worker   // Rely on the type initialization to save everything we need.
7574*795d594fSAndroid Build Coastguard Worker   locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
7575*795d594fSAndroid Build Coastguard Worker }
7576*795d594fSAndroid Build Coastguard Worker 
VisitClinitCheck(HClinitCheck * check)7577*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
7578*795d594fSAndroid Build Coastguard Worker   // We assume the class to not be null.
7579*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path =
7580*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86(check->GetLoadClass(), check);
7581*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(slow_path);
7582*795d594fSAndroid Build Coastguard Worker   GenerateClassInitializationCheck(slow_path,
7583*795d594fSAndroid Build Coastguard Worker                                    check->GetLocations()->InAt(0).AsRegister<Register>());
7584*795d594fSAndroid Build Coastguard Worker }
7585*795d594fSAndroid Build Coastguard Worker 
GenerateClassInitializationCheck(SlowPathCode * slow_path,Register class_reg)7586*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
7587*795d594fSAndroid Build Coastguard Worker     SlowPathCode* slow_path, Register class_reg) {
7588*795d594fSAndroid Build Coastguard Worker   __ cmpb(Address(class_reg, kClassStatusByteOffset), Immediate(kShiftedVisiblyInitializedValue));
7589*795d594fSAndroid Build Coastguard Worker   __ j(kBelow, slow_path->GetEntryLabel());
7590*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
7591*795d594fSAndroid Build Coastguard Worker }
7592*795d594fSAndroid Build Coastguard Worker 
GenerateBitstringTypeCheckCompare(HTypeCheckInstruction * check,Register temp)7593*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
7594*795d594fSAndroid Build Coastguard Worker                                                                     Register temp) {
7595*795d594fSAndroid Build Coastguard Worker   uint32_t path_to_root = check->GetBitstringPathToRoot();
7596*795d594fSAndroid Build Coastguard Worker   uint32_t mask = check->GetBitstringMask();
7597*795d594fSAndroid Build Coastguard Worker   DCHECK(IsPowerOfTwo(mask + 1));
7598*795d594fSAndroid Build Coastguard Worker   size_t mask_bits = WhichPowerOf2(mask + 1);
7599*795d594fSAndroid Build Coastguard Worker 
7600*795d594fSAndroid Build Coastguard Worker   if (mask_bits == 16u) {
7601*795d594fSAndroid Build Coastguard Worker     // Compare the bitstring in memory.
7602*795d594fSAndroid Build Coastguard Worker     __ cmpw(Address(temp, mirror::Class::StatusOffset()), Immediate(path_to_root));
7603*795d594fSAndroid Build Coastguard Worker   } else {
7604*795d594fSAndroid Build Coastguard Worker     // /* uint32_t */ temp = temp->status_
7605*795d594fSAndroid Build Coastguard Worker     __ movl(temp, Address(temp, mirror::Class::StatusOffset()));
7606*795d594fSAndroid Build Coastguard Worker     // Compare the bitstring bits using SUB.
7607*795d594fSAndroid Build Coastguard Worker     __ subl(temp, Immediate(path_to_root));
7608*795d594fSAndroid Build Coastguard Worker     // Shift out bits that do not contribute to the comparison.
7609*795d594fSAndroid Build Coastguard Worker     __ shll(temp, Immediate(32u - mask_bits));
7610*795d594fSAndroid Build Coastguard Worker   }
7611*795d594fSAndroid Build Coastguard Worker }
7612*795d594fSAndroid Build Coastguard Worker 
GetSupportedLoadStringKind(HLoadString::LoadKind desired_string_load_kind)7613*795d594fSAndroid Build Coastguard Worker HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
7614*795d594fSAndroid Build Coastguard Worker     HLoadString::LoadKind desired_string_load_kind) {
7615*795d594fSAndroid Build Coastguard Worker   switch (desired_string_load_kind) {
7616*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
7617*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBootImageRelRo:
7618*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBssEntry:
7619*795d594fSAndroid Build Coastguard Worker       DCHECK(!GetCompilerOptions().IsJitCompiler());
7620*795d594fSAndroid Build Coastguard Worker       break;
7621*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kJitBootImageAddress:
7622*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kJitTableAddress:
7623*795d594fSAndroid Build Coastguard Worker       DCHECK(GetCompilerOptions().IsJitCompiler());
7624*795d594fSAndroid Build Coastguard Worker       break;
7625*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kRuntimeCall:
7626*795d594fSAndroid Build Coastguard Worker       break;
7627*795d594fSAndroid Build Coastguard Worker   }
7628*795d594fSAndroid Build Coastguard Worker   return desired_string_load_kind;
7629*795d594fSAndroid Build Coastguard Worker }
7630*795d594fSAndroid Build Coastguard Worker 
VisitLoadString(HLoadString * load)7631*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
7632*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = codegen_->GetLoadStringCallKind(load);
7633*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
7634*795d594fSAndroid Build Coastguard Worker   HLoadString::LoadKind load_kind = load->GetLoadKind();
7635*795d594fSAndroid Build Coastguard Worker   if (load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative ||
7636*795d594fSAndroid Build Coastguard Worker       load_kind == HLoadString::LoadKind::kBootImageRelRo ||
7637*795d594fSAndroid Build Coastguard Worker       load_kind == HLoadString::LoadKind::kBssEntry) {
7638*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RequiresRegister());
7639*795d594fSAndroid Build Coastguard Worker   }
7640*795d594fSAndroid Build Coastguard Worker   if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
7641*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RegisterLocation(EAX));
7642*795d594fSAndroid Build Coastguard Worker   } else {
7643*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister());
7644*795d594fSAndroid Build Coastguard Worker     if (load_kind == HLoadString::LoadKind::kBssEntry) {
7645*795d594fSAndroid Build Coastguard Worker       if (codegen_->EmitNonBakerReadBarrier()) {
7646*795d594fSAndroid Build Coastguard Worker         // For non-Baker read barrier we have a temp-clobbering call.
7647*795d594fSAndroid Build Coastguard Worker       } else {
7648*795d594fSAndroid Build Coastguard Worker         // Rely on the pResolveString to save everything.
7649*795d594fSAndroid Build Coastguard Worker         locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
7650*795d594fSAndroid Build Coastguard Worker       }
7651*795d594fSAndroid Build Coastguard Worker     }
7652*795d594fSAndroid Build Coastguard Worker   }
7653*795d594fSAndroid Build Coastguard Worker }
7654*795d594fSAndroid Build Coastguard Worker 
NewJitRootStringPatch(const DexFile & dex_file,dex::StringIndex string_index,Handle<mirror::String> handle)7655*795d594fSAndroid Build Coastguard Worker Label* CodeGeneratorX86::NewJitRootStringPatch(const DexFile& dex_file,
7656*795d594fSAndroid Build Coastguard Worker                                                dex::StringIndex string_index,
7657*795d594fSAndroid Build Coastguard Worker                                                Handle<mirror::String> handle) {
7658*795d594fSAndroid Build Coastguard Worker   ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
7659*795d594fSAndroid Build Coastguard Worker   // Add a patch entry and return the label.
7660*795d594fSAndroid Build Coastguard Worker   jit_string_patches_.emplace_back(&dex_file, string_index.index_);
7661*795d594fSAndroid Build Coastguard Worker   PatchInfo<Label>* info = &jit_string_patches_.back();
7662*795d594fSAndroid Build Coastguard Worker   return &info->label;
7663*795d594fSAndroid Build Coastguard Worker }
7664*795d594fSAndroid Build Coastguard Worker 
7665*795d594fSAndroid Build Coastguard Worker // NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7666*795d594fSAndroid Build Coastguard Worker // move.
VisitLoadString(HLoadString * load)7667*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
7668*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = load->GetLocations();
7669*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
7670*795d594fSAndroid Build Coastguard Worker   Register out = out_loc.AsRegister<Register>();
7671*795d594fSAndroid Build Coastguard Worker 
7672*795d594fSAndroid Build Coastguard Worker   switch (load->GetLoadKind()) {
7673*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
7674*795d594fSAndroid Build Coastguard Worker       DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
7675*795d594fSAndroid Build Coastguard Worker              codegen_->GetCompilerOptions().IsBootImageExtension());
7676*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7677*795d594fSAndroid Build Coastguard Worker       __ leal(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
7678*795d594fSAndroid Build Coastguard Worker       codegen_->RecordBootImageStringPatch(load);
7679*795d594fSAndroid Build Coastguard Worker       return;
7680*795d594fSAndroid Build Coastguard Worker     }
7681*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBootImageRelRo: {
7682*795d594fSAndroid Build Coastguard Worker       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7683*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7684*795d594fSAndroid Build Coastguard Worker       __ movl(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
7685*795d594fSAndroid Build Coastguard Worker       codegen_->RecordBootImageRelRoPatch(load->InputAt(0)->AsX86ComputeBaseMethodAddress(),
7686*795d594fSAndroid Build Coastguard Worker                                           CodeGenerator::GetBootImageOffset(load));
7687*795d594fSAndroid Build Coastguard Worker       return;
7688*795d594fSAndroid Build Coastguard Worker     }
7689*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kBssEntry: {
7690*795d594fSAndroid Build Coastguard Worker       Register method_address = locations->InAt(0).AsRegister<Register>();
7691*795d594fSAndroid Build Coastguard Worker       Address address = Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset);
7692*795d594fSAndroid Build Coastguard Worker       Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
7693*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::String> */ out = *address  /* PC-relative */
7694*795d594fSAndroid Build Coastguard Worker       GenerateGcRootFieldLoad(
7695*795d594fSAndroid Build Coastguard Worker           load, out_loc, address, fixup_label, codegen_->GetCompilerReadBarrierOption());
7696*795d594fSAndroid Build Coastguard Worker       // No need for memory fence, thanks to the x86 memory model.
7697*795d594fSAndroid Build Coastguard Worker       SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadStringSlowPathX86(load);
7698*795d594fSAndroid Build Coastguard Worker       codegen_->AddSlowPath(slow_path);
7699*795d594fSAndroid Build Coastguard Worker       __ testl(out, out);
7700*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, slow_path->GetEntryLabel());
7701*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetExitLabel());
7702*795d594fSAndroid Build Coastguard Worker       return;
7703*795d594fSAndroid Build Coastguard Worker     }
7704*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kJitBootImageAddress: {
7705*795d594fSAndroid Build Coastguard Worker       uint32_t address = reinterpret_cast32<uint32_t>(load->GetString().Get());
7706*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(address, 0u);
7707*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(address));
7708*795d594fSAndroid Build Coastguard Worker       return;
7709*795d594fSAndroid Build Coastguard Worker     }
7710*795d594fSAndroid Build Coastguard Worker     case HLoadString::LoadKind::kJitTableAddress: {
7711*795d594fSAndroid Build Coastguard Worker       Address address = Address::Absolute(CodeGeneratorX86::kPlaceholder32BitOffset);
7712*795d594fSAndroid Build Coastguard Worker       Label* fixup_label = codegen_->NewJitRootStringPatch(
7713*795d594fSAndroid Build Coastguard Worker           load->GetDexFile(), load->GetStringIndex(), load->GetString());
7714*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::String> */ out = *address
7715*795d594fSAndroid Build Coastguard Worker       GenerateGcRootFieldLoad(
7716*795d594fSAndroid Build Coastguard Worker           load, out_loc, address, fixup_label, codegen_->GetCompilerReadBarrierOption());
7717*795d594fSAndroid Build Coastguard Worker       return;
7718*795d594fSAndroid Build Coastguard Worker     }
7719*795d594fSAndroid Build Coastguard Worker     default:
7720*795d594fSAndroid Build Coastguard Worker       break;
7721*795d594fSAndroid Build Coastguard Worker   }
7722*795d594fSAndroid Build Coastguard Worker 
7723*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
7724*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
7725*795d594fSAndroid Build Coastguard Worker   __ movl(calling_convention.GetRegisterAt(0), Immediate(load->GetStringIndex().index_));
7726*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7727*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
7728*795d594fSAndroid Build Coastguard Worker }
7729*795d594fSAndroid Build Coastguard Worker 
GetExceptionTlsAddress()7730*795d594fSAndroid Build Coastguard Worker static Address GetExceptionTlsAddress() {
7731*795d594fSAndroid Build Coastguard Worker   return Address::Absolute(Thread::ExceptionOffset<kX86PointerSize>().Int32Value());
7732*795d594fSAndroid Build Coastguard Worker }
7733*795d594fSAndroid Build Coastguard Worker 
VisitLoadException(HLoadException * load)7734*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
7735*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
7736*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
7737*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
7738*795d594fSAndroid Build Coastguard Worker }
7739*795d594fSAndroid Build Coastguard Worker 
VisitLoadException(HLoadException * load)7740*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
7741*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
7742*795d594fSAndroid Build Coastguard Worker }
7743*795d594fSAndroid Build Coastguard Worker 
VisitClearException(HClearException * clear)7744*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitClearException(HClearException* clear) {
7745*795d594fSAndroid Build Coastguard Worker   new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
7746*795d594fSAndroid Build Coastguard Worker }
7747*795d594fSAndroid Build Coastguard Worker 
VisitClearException(HClearException * clear)7748*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitClearException([[maybe_unused]] HClearException* clear) {
7749*795d594fSAndroid Build Coastguard Worker   __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
7750*795d594fSAndroid Build Coastguard Worker }
7751*795d594fSAndroid Build Coastguard Worker 
VisitThrow(HThrow * instruction)7752*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
7753*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
7754*795d594fSAndroid Build Coastguard Worker       instruction, LocationSummary::kCallOnMainOnly);
7755*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
7756*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7757*795d594fSAndroid Build Coastguard Worker }
7758*795d594fSAndroid Build Coastguard Worker 
VisitThrow(HThrow * instruction)7759*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
7760*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
7761*795d594fSAndroid Build Coastguard Worker   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
7762*795d594fSAndroid Build Coastguard Worker }
7763*795d594fSAndroid Build Coastguard Worker 
7764*795d594fSAndroid Build Coastguard Worker // Temp is used for read barrier.
NumberOfInstanceOfTemps(bool emit_read_barrier,TypeCheckKind type_check_kind)7765*795d594fSAndroid Build Coastguard Worker static size_t NumberOfInstanceOfTemps(bool emit_read_barrier, TypeCheckKind type_check_kind) {
7766*795d594fSAndroid Build Coastguard Worker   if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7767*795d594fSAndroid Build Coastguard Worker     return 1;
7768*795d594fSAndroid Build Coastguard Worker   }
7769*795d594fSAndroid Build Coastguard Worker   if (emit_read_barrier &&
7770*795d594fSAndroid Build Coastguard Worker       !kUseBakerReadBarrier &&
7771*795d594fSAndroid Build Coastguard Worker       (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7772*795d594fSAndroid Build Coastguard Worker        type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7773*795d594fSAndroid Build Coastguard Worker        type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7774*795d594fSAndroid Build Coastguard Worker     return 1;
7775*795d594fSAndroid Build Coastguard Worker   }
7776*795d594fSAndroid Build Coastguard Worker   return 0;
7777*795d594fSAndroid Build Coastguard Worker }
7778*795d594fSAndroid Build Coastguard Worker 
7779*795d594fSAndroid Build Coastguard Worker // Interface case has 2 temps, one for holding the number of interfaces, one for the current
7780*795d594fSAndroid Build Coastguard Worker // interface pointer, the current interface is compared in memory.
7781*795d594fSAndroid Build Coastguard Worker // The other checks have one temp for loading the object's class.
NumberOfCheckCastTemps(bool emit_read_barrier,TypeCheckKind type_check_kind)7782*795d594fSAndroid Build Coastguard Worker static size_t NumberOfCheckCastTemps(bool emit_read_barrier, TypeCheckKind type_check_kind) {
7783*795d594fSAndroid Build Coastguard Worker   return 1 + NumberOfInstanceOfTemps(emit_read_barrier, type_check_kind);
7784*795d594fSAndroid Build Coastguard Worker }
7785*795d594fSAndroid Build Coastguard Worker 
VisitInstanceOf(HInstanceOf * instruction)7786*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
7787*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7788*795d594fSAndroid Build Coastguard Worker   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7789*795d594fSAndroid Build Coastguard Worker   bool baker_read_barrier_slow_path = false;
7790*795d594fSAndroid Build Coastguard Worker   switch (type_check_kind) {
7791*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kExactCheck:
7792*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kAbstractClassCheck:
7793*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kClassHierarchyCheck:
7794*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayObjectCheck:
7795*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kInterfaceCheck: {
7796*795d594fSAndroid Build Coastguard Worker       bool needs_read_barrier = codegen_->InstanceOfNeedsReadBarrier(instruction);
7797*795d594fSAndroid Build Coastguard Worker       call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
7798*795d594fSAndroid Build Coastguard Worker       baker_read_barrier_slow_path = (kUseBakerReadBarrier && needs_read_barrier) &&
7799*795d594fSAndroid Build Coastguard Worker                                      (type_check_kind != TypeCheckKind::kInterfaceCheck);
7800*795d594fSAndroid Build Coastguard Worker       break;
7801*795d594fSAndroid Build Coastguard Worker     }
7802*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayCheck:
7803*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kUnresolvedCheck:
7804*795d594fSAndroid Build Coastguard Worker       call_kind = LocationSummary::kCallOnSlowPath;
7805*795d594fSAndroid Build Coastguard Worker       break;
7806*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kBitstringCheck:
7807*795d594fSAndroid Build Coastguard Worker       break;
7808*795d594fSAndroid Build Coastguard Worker   }
7809*795d594fSAndroid Build Coastguard Worker 
7810*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
7811*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
7812*795d594fSAndroid Build Coastguard Worker   if (baker_read_barrier_slow_path) {
7813*795d594fSAndroid Build Coastguard Worker     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
7814*795d594fSAndroid Build Coastguard Worker   }
7815*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
7816*795d594fSAndroid Build Coastguard Worker   if (type_check_kind == TypeCheckKind::kBitstringCheck) {
7817*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)));
7818*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)));
7819*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)));
7820*795d594fSAndroid Build Coastguard Worker   } else if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7821*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
7822*795d594fSAndroid Build Coastguard Worker   } else {
7823*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::Any());
7824*795d594fSAndroid Build Coastguard Worker   }
7825*795d594fSAndroid Build Coastguard Worker   // Note that TypeCheckSlowPathX86 uses this "out" register too.
7826*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
7827*795d594fSAndroid Build Coastguard Worker   // When read barriers are enabled, we need a temporary register for some cases.
7828*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(
7829*795d594fSAndroid Build Coastguard Worker       NumberOfInstanceOfTemps(codegen_->EmitReadBarrier(), type_check_kind));
7830*795d594fSAndroid Build Coastguard Worker }
7831*795d594fSAndroid Build Coastguard Worker 
VisitInstanceOf(HInstanceOf * instruction)7832*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
7833*795d594fSAndroid Build Coastguard Worker   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7834*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
7835*795d594fSAndroid Build Coastguard Worker   Location obj_loc = locations->InAt(0);
7836*795d594fSAndroid Build Coastguard Worker   Register obj = obj_loc.AsRegister<Register>();
7837*795d594fSAndroid Build Coastguard Worker   Location cls = locations->InAt(1);
7838*795d594fSAndroid Build Coastguard Worker   Location out_loc = locations->Out();
7839*795d594fSAndroid Build Coastguard Worker   Register out = out_loc.AsRegister<Register>();
7840*795d594fSAndroid Build Coastguard Worker   const size_t num_temps = NumberOfInstanceOfTemps(codegen_->EmitReadBarrier(), type_check_kind);
7841*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(num_temps, 1u);
7842*795d594fSAndroid Build Coastguard Worker   Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
7843*795d594fSAndroid Build Coastguard Worker   const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7844*795d594fSAndroid Build Coastguard Worker   const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7845*795d594fSAndroid Build Coastguard Worker   const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7846*795d594fSAndroid Build Coastguard Worker   const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7847*795d594fSAndroid Build Coastguard Worker   const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7848*795d594fSAndroid Build Coastguard Worker   const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7849*795d594fSAndroid Build Coastguard Worker   const uint32_t object_array_data_offset =
7850*795d594fSAndroid Build Coastguard Worker       mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
7851*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = nullptr;
7852*795d594fSAndroid Build Coastguard Worker   NearLabel done, zero;
7853*795d594fSAndroid Build Coastguard Worker 
7854*795d594fSAndroid Build Coastguard Worker   // Return 0 if `obj` is null.
7855*795d594fSAndroid Build Coastguard Worker   // Avoid null check if we know obj is not null.
7856*795d594fSAndroid Build Coastguard Worker   if (instruction->MustDoNullCheck()) {
7857*795d594fSAndroid Build Coastguard Worker     __ testl(obj, obj);
7858*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &zero);
7859*795d594fSAndroid Build Coastguard Worker   }
7860*795d594fSAndroid Build Coastguard Worker 
7861*795d594fSAndroid Build Coastguard Worker   switch (type_check_kind) {
7862*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kExactCheck: {
7863*795d594fSAndroid Build Coastguard Worker       ReadBarrierOption read_barrier_option =
7864*795d594fSAndroid Build Coastguard Worker           codegen_->ReadBarrierOptionForInstanceOf(instruction);
7865*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = obj->klass_
7866*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
7867*795d594fSAndroid Build Coastguard Worker                                         out_loc,
7868*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
7869*795d594fSAndroid Build Coastguard Worker                                         class_offset,
7870*795d594fSAndroid Build Coastguard Worker                                         read_barrier_option);
7871*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
7872*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, cls.AsRegister<Register>());
7873*795d594fSAndroid Build Coastguard Worker       } else {
7874*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
7875*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7876*795d594fSAndroid Build Coastguard Worker       }
7877*795d594fSAndroid Build Coastguard Worker 
7878*795d594fSAndroid Build Coastguard Worker       // Classes must be equal for the instanceof to succeed.
7879*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &zero);
7880*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
7881*795d594fSAndroid Build Coastguard Worker       __ jmp(&done);
7882*795d594fSAndroid Build Coastguard Worker       break;
7883*795d594fSAndroid Build Coastguard Worker     }
7884*795d594fSAndroid Build Coastguard Worker 
7885*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kAbstractClassCheck: {
7886*795d594fSAndroid Build Coastguard Worker       ReadBarrierOption read_barrier_option =
7887*795d594fSAndroid Build Coastguard Worker           codegen_->ReadBarrierOptionForInstanceOf(instruction);
7888*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = obj->klass_
7889*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
7890*795d594fSAndroid Build Coastguard Worker                                         out_loc,
7891*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
7892*795d594fSAndroid Build Coastguard Worker                                         class_offset,
7893*795d594fSAndroid Build Coastguard Worker                                         read_barrier_option);
7894*795d594fSAndroid Build Coastguard Worker       // If the class is abstract, we eagerly fetch the super class of the
7895*795d594fSAndroid Build Coastguard Worker       // object to avoid doing a comparison we know will fail.
7896*795d594fSAndroid Build Coastguard Worker       NearLabel loop;
7897*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
7898*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = out->super_class_
7899*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
7900*795d594fSAndroid Build Coastguard Worker                                        out_loc,
7901*795d594fSAndroid Build Coastguard Worker                                        super_offset,
7902*795d594fSAndroid Build Coastguard Worker                                        maybe_temp_loc,
7903*795d594fSAndroid Build Coastguard Worker                                        read_barrier_option);
7904*795d594fSAndroid Build Coastguard Worker       __ testl(out, out);
7905*795d594fSAndroid Build Coastguard Worker       // If `out` is null, we use it for the result, and jump to `done`.
7906*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &done);
7907*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
7908*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, cls.AsRegister<Register>());
7909*795d594fSAndroid Build Coastguard Worker       } else {
7910*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
7911*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7912*795d594fSAndroid Build Coastguard Worker       }
7913*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &loop);
7914*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
7915*795d594fSAndroid Build Coastguard Worker       if (zero.IsLinked()) {
7916*795d594fSAndroid Build Coastguard Worker         __ jmp(&done);
7917*795d594fSAndroid Build Coastguard Worker       }
7918*795d594fSAndroid Build Coastguard Worker       break;
7919*795d594fSAndroid Build Coastguard Worker     }
7920*795d594fSAndroid Build Coastguard Worker 
7921*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kClassHierarchyCheck: {
7922*795d594fSAndroid Build Coastguard Worker       ReadBarrierOption read_barrier_option =
7923*795d594fSAndroid Build Coastguard Worker           codegen_->ReadBarrierOptionForInstanceOf(instruction);
7924*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = obj->klass_
7925*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
7926*795d594fSAndroid Build Coastguard Worker                                         out_loc,
7927*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
7928*795d594fSAndroid Build Coastguard Worker                                         class_offset,
7929*795d594fSAndroid Build Coastguard Worker                                         read_barrier_option);
7930*795d594fSAndroid Build Coastguard Worker       // Walk over the class hierarchy to find a match.
7931*795d594fSAndroid Build Coastguard Worker       NearLabel loop, success;
7932*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
7933*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
7934*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, cls.AsRegister<Register>());
7935*795d594fSAndroid Build Coastguard Worker       } else {
7936*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
7937*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7938*795d594fSAndroid Build Coastguard Worker       }
7939*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &success);
7940*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = out->super_class_
7941*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
7942*795d594fSAndroid Build Coastguard Worker                                        out_loc,
7943*795d594fSAndroid Build Coastguard Worker                                        super_offset,
7944*795d594fSAndroid Build Coastguard Worker                                        maybe_temp_loc,
7945*795d594fSAndroid Build Coastguard Worker                                        read_barrier_option);
7946*795d594fSAndroid Build Coastguard Worker       __ testl(out, out);
7947*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &loop);
7948*795d594fSAndroid Build Coastguard Worker       // If `out` is null, we use it for the result, and jump to `done`.
7949*795d594fSAndroid Build Coastguard Worker       __ jmp(&done);
7950*795d594fSAndroid Build Coastguard Worker       __ Bind(&success);
7951*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
7952*795d594fSAndroid Build Coastguard Worker       if (zero.IsLinked()) {
7953*795d594fSAndroid Build Coastguard Worker         __ jmp(&done);
7954*795d594fSAndroid Build Coastguard Worker       }
7955*795d594fSAndroid Build Coastguard Worker       break;
7956*795d594fSAndroid Build Coastguard Worker     }
7957*795d594fSAndroid Build Coastguard Worker 
7958*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayObjectCheck: {
7959*795d594fSAndroid Build Coastguard Worker       ReadBarrierOption read_barrier_option =
7960*795d594fSAndroid Build Coastguard Worker           codegen_->ReadBarrierOptionForInstanceOf(instruction);
7961*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = obj->klass_
7962*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
7963*795d594fSAndroid Build Coastguard Worker                                         out_loc,
7964*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
7965*795d594fSAndroid Build Coastguard Worker                                         class_offset,
7966*795d594fSAndroid Build Coastguard Worker                                         read_barrier_option);
7967*795d594fSAndroid Build Coastguard Worker       // Do an exact check.
7968*795d594fSAndroid Build Coastguard Worker       NearLabel exact_check;
7969*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
7970*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, cls.AsRegister<Register>());
7971*795d594fSAndroid Build Coastguard Worker       } else {
7972*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
7973*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7974*795d594fSAndroid Build Coastguard Worker       }
7975*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &exact_check);
7976*795d594fSAndroid Build Coastguard Worker       // Otherwise, we need to check that the object's class is a non-primitive array.
7977*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = out->component_type_
7978*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
7979*795d594fSAndroid Build Coastguard Worker                                        out_loc,
7980*795d594fSAndroid Build Coastguard Worker                                        component_offset,
7981*795d594fSAndroid Build Coastguard Worker                                        maybe_temp_loc,
7982*795d594fSAndroid Build Coastguard Worker                                        read_barrier_option);
7983*795d594fSAndroid Build Coastguard Worker       __ testl(out, out);
7984*795d594fSAndroid Build Coastguard Worker       // If `out` is null, we use it for the result, and jump to `done`.
7985*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &done);
7986*795d594fSAndroid Build Coastguard Worker       __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
7987*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &zero);
7988*795d594fSAndroid Build Coastguard Worker       __ Bind(&exact_check);
7989*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
7990*795d594fSAndroid Build Coastguard Worker       __ jmp(&done);
7991*795d594fSAndroid Build Coastguard Worker       break;
7992*795d594fSAndroid Build Coastguard Worker     }
7993*795d594fSAndroid Build Coastguard Worker 
7994*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayCheck: {
7995*795d594fSAndroid Build Coastguard Worker       // No read barrier since the slow path will retry upon failure.
7996*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ out = obj->klass_
7997*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
7998*795d594fSAndroid Build Coastguard Worker                                         out_loc,
7999*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8000*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8001*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8002*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
8003*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, cls.AsRegister<Register>());
8004*795d594fSAndroid Build Coastguard Worker       } else {
8005*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
8006*795d594fSAndroid Build Coastguard Worker         __ cmpl(out, Address(ESP, cls.GetStackIndex()));
8007*795d594fSAndroid Build Coastguard Worker       }
8008*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->OnlyCallsOnSlowPath());
8009*795d594fSAndroid Build Coastguard Worker       slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
8010*795d594fSAndroid Build Coastguard Worker           instruction, /* is_fatal= */ false);
8011*795d594fSAndroid Build Coastguard Worker       codegen_->AddSlowPath(slow_path);
8012*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, slow_path->GetEntryLabel());
8013*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
8014*795d594fSAndroid Build Coastguard Worker       if (zero.IsLinked()) {
8015*795d594fSAndroid Build Coastguard Worker         __ jmp(&done);
8016*795d594fSAndroid Build Coastguard Worker       }
8017*795d594fSAndroid Build Coastguard Worker       break;
8018*795d594fSAndroid Build Coastguard Worker     }
8019*795d594fSAndroid Build Coastguard Worker 
8020*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kInterfaceCheck: {
8021*795d594fSAndroid Build Coastguard Worker       if (codegen_->InstanceOfNeedsReadBarrier(instruction)) {
8022*795d594fSAndroid Build Coastguard Worker         DCHECK(locations->OnlyCallsOnSlowPath());
8023*795d594fSAndroid Build Coastguard Worker         slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
8024*795d594fSAndroid Build Coastguard Worker             instruction, /* is_fatal= */ false);
8025*795d594fSAndroid Build Coastguard Worker         codegen_->AddSlowPath(slow_path);
8026*795d594fSAndroid Build Coastguard Worker         if (codegen_->EmitNonBakerReadBarrier()) {
8027*795d594fSAndroid Build Coastguard Worker           __ jmp(slow_path->GetEntryLabel());
8028*795d594fSAndroid Build Coastguard Worker           break;
8029*795d594fSAndroid Build Coastguard Worker         }
8030*795d594fSAndroid Build Coastguard Worker         // For Baker read barrier, take the slow path while marking.
8031*795d594fSAndroid Build Coastguard Worker         __ fs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86PointerSize>()),
8032*795d594fSAndroid Build Coastguard Worker                       Immediate(0));
8033*795d594fSAndroid Build Coastguard Worker         __ j(kNotEqual, slow_path->GetEntryLabel());
8034*795d594fSAndroid Build Coastguard Worker       }
8035*795d594fSAndroid Build Coastguard Worker 
8036*795d594fSAndroid Build Coastguard Worker       // Fast-path without read barriers.
8037*795d594fSAndroid Build Coastguard Worker       Register temp = maybe_temp_loc.AsRegister<Register>();
8038*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8039*795d594fSAndroid Build Coastguard Worker       __ movl(temp, Address(obj, class_offset));
8040*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(temp);
8041*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = temp->iftable_
8042*795d594fSAndroid Build Coastguard Worker       __ movl(temp, Address(temp, iftable_offset));
8043*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(temp);
8044*795d594fSAndroid Build Coastguard Worker       // Load the size of the `IfTable`. The `Class::iftable_` is never null.
8045*795d594fSAndroid Build Coastguard Worker       __ movl(out, Address(temp, array_length_offset));
8046*795d594fSAndroid Build Coastguard Worker       // Maybe poison the `cls` for direct comparison with memory.
8047*795d594fSAndroid Build Coastguard Worker       __ MaybePoisonHeapReference(cls.AsRegister<Register>());
8048*795d594fSAndroid Build Coastguard Worker       // Loop through the iftable and check if any class matches.
8049*795d594fSAndroid Build Coastguard Worker       NearLabel loop, end;
8050*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
8051*795d594fSAndroid Build Coastguard Worker       // Check if we still have an entry to compare.
8052*795d594fSAndroid Build Coastguard Worker       __ subl(out, Immediate(2));
8053*795d594fSAndroid Build Coastguard Worker       __ j(kNegative, (zero.IsLinked() && !kPoisonHeapReferences) ? &zero : &end);
8054*795d594fSAndroid Build Coastguard Worker       // Go to next interface if the classes do not match.
8055*795d594fSAndroid Build Coastguard Worker       __ cmpl(cls.AsRegister<Register>(),
8056*795d594fSAndroid Build Coastguard Worker               CodeGeneratorX86::ArrayAddress(temp, out_loc, TIMES_4, object_array_data_offset));
8057*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &loop);
8058*795d594fSAndroid Build Coastguard Worker       if (zero.IsLinked()) {
8059*795d594fSAndroid Build Coastguard Worker         __ movl(out, Immediate(1));
8060*795d594fSAndroid Build Coastguard Worker         // If `cls` was poisoned above, unpoison it.
8061*795d594fSAndroid Build Coastguard Worker         __ MaybeUnpoisonHeapReference(cls.AsRegister<Register>());
8062*795d594fSAndroid Build Coastguard Worker         __ jmp(&done);
8063*795d594fSAndroid Build Coastguard Worker         if (kPoisonHeapReferences) {
8064*795d594fSAndroid Build Coastguard Worker           // The false case needs to unpoison the class before jumping to `zero`.
8065*795d594fSAndroid Build Coastguard Worker           __ Bind(&end);
8066*795d594fSAndroid Build Coastguard Worker           __ UnpoisonHeapReference(cls.AsRegister<Register>());
8067*795d594fSAndroid Build Coastguard Worker           __ jmp(&zero);
8068*795d594fSAndroid Build Coastguard Worker         }
8069*795d594fSAndroid Build Coastguard Worker       } else {
8070*795d594fSAndroid Build Coastguard Worker         // To reduce branching, use the fact that the false case branches with a `-2` in `out`.
8071*795d594fSAndroid Build Coastguard Worker         __ movl(out, Immediate(-1));
8072*795d594fSAndroid Build Coastguard Worker         __ Bind(&end);
8073*795d594fSAndroid Build Coastguard Worker         __ addl(out, Immediate(2));
8074*795d594fSAndroid Build Coastguard Worker         // If `cls` was poisoned above, unpoison it.
8075*795d594fSAndroid Build Coastguard Worker         __ MaybeUnpoisonHeapReference(cls.AsRegister<Register>());
8076*795d594fSAndroid Build Coastguard Worker       }
8077*795d594fSAndroid Build Coastguard Worker       break;
8078*795d594fSAndroid Build Coastguard Worker     }
8079*795d594fSAndroid Build Coastguard Worker 
8080*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kUnresolvedCheck: {
8081*795d594fSAndroid Build Coastguard Worker       // Note that we indeed only call on slow path, but we always go
8082*795d594fSAndroid Build Coastguard Worker       // into the slow path for the unresolved check case.
8083*795d594fSAndroid Build Coastguard Worker       //
8084*795d594fSAndroid Build Coastguard Worker       // We cannot directly call the InstanceofNonTrivial runtime
8085*795d594fSAndroid Build Coastguard Worker       // entry point without resorting to a type checking slow path
8086*795d594fSAndroid Build Coastguard Worker       // here (i.e. by calling InvokeRuntime directly), as it would
8087*795d594fSAndroid Build Coastguard Worker       // require to assign fixed registers for the inputs of this
8088*795d594fSAndroid Build Coastguard Worker       // HInstanceOf instruction (following the runtime calling
8089*795d594fSAndroid Build Coastguard Worker       // convention), which might be cluttered by the potential first
8090*795d594fSAndroid Build Coastguard Worker       // read barrier emission at the beginning of this method.
8091*795d594fSAndroid Build Coastguard Worker       //
8092*795d594fSAndroid Build Coastguard Worker       // TODO: Introduce a new runtime entry point taking the object
8093*795d594fSAndroid Build Coastguard Worker       // to test (instead of its class) as argument, and let it deal
8094*795d594fSAndroid Build Coastguard Worker       // with the read barrier issues. This will let us refactor this
8095*795d594fSAndroid Build Coastguard Worker       // case of the `switch` code as it was previously (with a direct
8096*795d594fSAndroid Build Coastguard Worker       // call to the runtime not using a type checking slow path).
8097*795d594fSAndroid Build Coastguard Worker       // This should also be beneficial for the other cases above.
8098*795d594fSAndroid Build Coastguard Worker       DCHECK(locations->OnlyCallsOnSlowPath());
8099*795d594fSAndroid Build Coastguard Worker       slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
8100*795d594fSAndroid Build Coastguard Worker           instruction, /* is_fatal= */ false);
8101*795d594fSAndroid Build Coastguard Worker       codegen_->AddSlowPath(slow_path);
8102*795d594fSAndroid Build Coastguard Worker       __ jmp(slow_path->GetEntryLabel());
8103*795d594fSAndroid Build Coastguard Worker       break;
8104*795d594fSAndroid Build Coastguard Worker     }
8105*795d594fSAndroid Build Coastguard Worker 
8106*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kBitstringCheck: {
8107*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8108*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8109*795d594fSAndroid Build Coastguard Worker                                         out_loc,
8110*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8111*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8112*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8113*795d594fSAndroid Build Coastguard Worker 
8114*795d594fSAndroid Build Coastguard Worker       GenerateBitstringTypeCheckCompare(instruction, out);
8115*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &zero);
8116*795d594fSAndroid Build Coastguard Worker       __ movl(out, Immediate(1));
8117*795d594fSAndroid Build Coastguard Worker       __ jmp(&done);
8118*795d594fSAndroid Build Coastguard Worker       break;
8119*795d594fSAndroid Build Coastguard Worker     }
8120*795d594fSAndroid Build Coastguard Worker   }
8121*795d594fSAndroid Build Coastguard Worker 
8122*795d594fSAndroid Build Coastguard Worker   if (zero.IsLinked()) {
8123*795d594fSAndroid Build Coastguard Worker     __ Bind(&zero);
8124*795d594fSAndroid Build Coastguard Worker     __ xorl(out, out);
8125*795d594fSAndroid Build Coastguard Worker   }
8126*795d594fSAndroid Build Coastguard Worker 
8127*795d594fSAndroid Build Coastguard Worker   if (done.IsLinked()) {
8128*795d594fSAndroid Build Coastguard Worker     __ Bind(&done);
8129*795d594fSAndroid Build Coastguard Worker   }
8130*795d594fSAndroid Build Coastguard Worker 
8131*795d594fSAndroid Build Coastguard Worker   if (slow_path != nullptr) {
8132*795d594fSAndroid Build Coastguard Worker     __ Bind(slow_path->GetExitLabel());
8133*795d594fSAndroid Build Coastguard Worker   }
8134*795d594fSAndroid Build Coastguard Worker }
8135*795d594fSAndroid Build Coastguard Worker 
VisitCheckCast(HCheckCast * instruction)8136*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
8137*795d594fSAndroid Build Coastguard Worker   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
8138*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = codegen_->GetCheckCastCallKind(instruction);
8139*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
8140*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
8141*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8142*795d594fSAndroid Build Coastguard Worker   if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
8143*795d594fSAndroid Build Coastguard Worker     // Require a register for the interface check since there is a loop that compares the class to
8144*795d594fSAndroid Build Coastguard Worker     // a memory address.
8145*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::RequiresRegister());
8146*795d594fSAndroid Build Coastguard Worker   } else if (type_check_kind == TypeCheckKind::kBitstringCheck) {
8147*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)));
8148*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)));
8149*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)));
8150*795d594fSAndroid Build Coastguard Worker   } else {
8151*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(1, Location::Any());
8152*795d594fSAndroid Build Coastguard Worker   }
8153*795d594fSAndroid Build Coastguard Worker   locations->AddRegisterTemps(NumberOfCheckCastTemps(codegen_->EmitReadBarrier(), type_check_kind));
8154*795d594fSAndroid Build Coastguard Worker }
8155*795d594fSAndroid Build Coastguard Worker 
VisitCheckCast(HCheckCast * instruction)8156*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
8157*795d594fSAndroid Build Coastguard Worker   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
8158*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
8159*795d594fSAndroid Build Coastguard Worker   Location obj_loc = locations->InAt(0);
8160*795d594fSAndroid Build Coastguard Worker   Register obj = obj_loc.AsRegister<Register>();
8161*795d594fSAndroid Build Coastguard Worker   Location cls = locations->InAt(1);
8162*795d594fSAndroid Build Coastguard Worker   Location temp_loc = locations->GetTemp(0);
8163*795d594fSAndroid Build Coastguard Worker   Register temp = temp_loc.AsRegister<Register>();
8164*795d594fSAndroid Build Coastguard Worker   const size_t num_temps = NumberOfCheckCastTemps(codegen_->EmitReadBarrier(), type_check_kind);
8165*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(num_temps, 1u);
8166*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(num_temps, 2u);
8167*795d594fSAndroid Build Coastguard Worker   Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
8168*795d594fSAndroid Build Coastguard Worker   const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
8169*795d594fSAndroid Build Coastguard Worker   const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
8170*795d594fSAndroid Build Coastguard Worker   const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
8171*795d594fSAndroid Build Coastguard Worker   const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
8172*795d594fSAndroid Build Coastguard Worker   const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
8173*795d594fSAndroid Build Coastguard Worker   const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
8174*795d594fSAndroid Build Coastguard Worker   const uint32_t object_array_data_offset =
8175*795d594fSAndroid Build Coastguard Worker       mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
8176*795d594fSAndroid Build Coastguard Worker 
8177*795d594fSAndroid Build Coastguard Worker   bool is_type_check_slow_path_fatal = codegen_->IsTypeCheckSlowPathFatal(instruction);
8178*795d594fSAndroid Build Coastguard Worker   SlowPathCode* type_check_slow_path =
8179*795d594fSAndroid Build Coastguard Worker       new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
8180*795d594fSAndroid Build Coastguard Worker           instruction, is_type_check_slow_path_fatal);
8181*795d594fSAndroid Build Coastguard Worker   codegen_->AddSlowPath(type_check_slow_path);
8182*795d594fSAndroid Build Coastguard Worker 
8183*795d594fSAndroid Build Coastguard Worker   NearLabel done;
8184*795d594fSAndroid Build Coastguard Worker   // Avoid null check if we know obj is not null.
8185*795d594fSAndroid Build Coastguard Worker   if (instruction->MustDoNullCheck()) {
8186*795d594fSAndroid Build Coastguard Worker     __ testl(obj, obj);
8187*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, &done);
8188*795d594fSAndroid Build Coastguard Worker   }
8189*795d594fSAndroid Build Coastguard Worker 
8190*795d594fSAndroid Build Coastguard Worker   switch (type_check_kind) {
8191*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kExactCheck:
8192*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayCheck: {
8193*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8194*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8195*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8196*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8197*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8198*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8199*795d594fSAndroid Build Coastguard Worker 
8200*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
8201*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, cls.AsRegister<Register>());
8202*795d594fSAndroid Build Coastguard Worker       } else {
8203*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
8204*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
8205*795d594fSAndroid Build Coastguard Worker       }
8206*795d594fSAndroid Build Coastguard Worker       // Jump to slow path for throwing the exception or doing a
8207*795d594fSAndroid Build Coastguard Worker       // more involved array check.
8208*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
8209*795d594fSAndroid Build Coastguard Worker       break;
8210*795d594fSAndroid Build Coastguard Worker     }
8211*795d594fSAndroid Build Coastguard Worker 
8212*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kAbstractClassCheck: {
8213*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8214*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8215*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8216*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8217*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8218*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8219*795d594fSAndroid Build Coastguard Worker 
8220*795d594fSAndroid Build Coastguard Worker       // If the class is abstract, we eagerly fetch the super class of the
8221*795d594fSAndroid Build Coastguard Worker       // object to avoid doing a comparison we know will fail.
8222*795d594fSAndroid Build Coastguard Worker       NearLabel loop;
8223*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
8224*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = temp->super_class_
8225*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
8226*795d594fSAndroid Build Coastguard Worker                                        temp_loc,
8227*795d594fSAndroid Build Coastguard Worker                                        super_offset,
8228*795d594fSAndroid Build Coastguard Worker                                        maybe_temp2_loc,
8229*795d594fSAndroid Build Coastguard Worker                                        kWithoutReadBarrier);
8230*795d594fSAndroid Build Coastguard Worker 
8231*795d594fSAndroid Build Coastguard Worker       // If the class reference currently in `temp` is null, jump to the slow path to throw the
8232*795d594fSAndroid Build Coastguard Worker       // exception.
8233*795d594fSAndroid Build Coastguard Worker       __ testl(temp, temp);
8234*795d594fSAndroid Build Coastguard Worker       __ j(kZero, type_check_slow_path->GetEntryLabel());
8235*795d594fSAndroid Build Coastguard Worker 
8236*795d594fSAndroid Build Coastguard Worker       // Otherwise, compare the classes
8237*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
8238*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, cls.AsRegister<Register>());
8239*795d594fSAndroid Build Coastguard Worker       } else {
8240*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
8241*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
8242*795d594fSAndroid Build Coastguard Worker       }
8243*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &loop);
8244*795d594fSAndroid Build Coastguard Worker       break;
8245*795d594fSAndroid Build Coastguard Worker     }
8246*795d594fSAndroid Build Coastguard Worker 
8247*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kClassHierarchyCheck: {
8248*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8249*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8250*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8251*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8252*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8253*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8254*795d594fSAndroid Build Coastguard Worker 
8255*795d594fSAndroid Build Coastguard Worker       // Walk over the class hierarchy to find a match.
8256*795d594fSAndroid Build Coastguard Worker       NearLabel loop;
8257*795d594fSAndroid Build Coastguard Worker       __ Bind(&loop);
8258*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
8259*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, cls.AsRegister<Register>());
8260*795d594fSAndroid Build Coastguard Worker       } else {
8261*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
8262*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
8263*795d594fSAndroid Build Coastguard Worker       }
8264*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &done);
8265*795d594fSAndroid Build Coastguard Worker 
8266*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = temp->super_class_
8267*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
8268*795d594fSAndroid Build Coastguard Worker                                        temp_loc,
8269*795d594fSAndroid Build Coastguard Worker                                        super_offset,
8270*795d594fSAndroid Build Coastguard Worker                                        maybe_temp2_loc,
8271*795d594fSAndroid Build Coastguard Worker                                        kWithoutReadBarrier);
8272*795d594fSAndroid Build Coastguard Worker 
8273*795d594fSAndroid Build Coastguard Worker       // If the class reference currently in `temp` is not null, jump
8274*795d594fSAndroid Build Coastguard Worker       // back at the beginning of the loop.
8275*795d594fSAndroid Build Coastguard Worker       __ testl(temp, temp);
8276*795d594fSAndroid Build Coastguard Worker       __ j(kNotZero, &loop);
8277*795d594fSAndroid Build Coastguard Worker       // Otherwise, jump to the slow path to throw the exception.;
8278*795d594fSAndroid Build Coastguard Worker       __ jmp(type_check_slow_path->GetEntryLabel());
8279*795d594fSAndroid Build Coastguard Worker       break;
8280*795d594fSAndroid Build Coastguard Worker     }
8281*795d594fSAndroid Build Coastguard Worker 
8282*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kArrayObjectCheck: {
8283*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8284*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8285*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8286*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8287*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8288*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8289*795d594fSAndroid Build Coastguard Worker 
8290*795d594fSAndroid Build Coastguard Worker       // Do an exact check.
8291*795d594fSAndroid Build Coastguard Worker       if (cls.IsRegister()) {
8292*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, cls.AsRegister<Register>());
8293*795d594fSAndroid Build Coastguard Worker       } else {
8294*795d594fSAndroid Build Coastguard Worker         DCHECK(cls.IsStackSlot()) << cls;
8295*795d594fSAndroid Build Coastguard Worker         __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
8296*795d594fSAndroid Build Coastguard Worker       }
8297*795d594fSAndroid Build Coastguard Worker       __ j(kEqual, &done);
8298*795d594fSAndroid Build Coastguard Worker 
8299*795d594fSAndroid Build Coastguard Worker       // Otherwise, we need to check that the object's class is a non-primitive array.
8300*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = temp->component_type_
8301*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
8302*795d594fSAndroid Build Coastguard Worker                                        temp_loc,
8303*795d594fSAndroid Build Coastguard Worker                                        component_offset,
8304*795d594fSAndroid Build Coastguard Worker                                        maybe_temp2_loc,
8305*795d594fSAndroid Build Coastguard Worker                                        kWithoutReadBarrier);
8306*795d594fSAndroid Build Coastguard Worker 
8307*795d594fSAndroid Build Coastguard Worker       // If the component type is null (i.e. the object not an array),  jump to the slow path to
8308*795d594fSAndroid Build Coastguard Worker       // throw the exception. Otherwise proceed with the check.
8309*795d594fSAndroid Build Coastguard Worker       __ testl(temp, temp);
8310*795d594fSAndroid Build Coastguard Worker       __ j(kZero, type_check_slow_path->GetEntryLabel());
8311*795d594fSAndroid Build Coastguard Worker 
8312*795d594fSAndroid Build Coastguard Worker       __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
8313*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
8314*795d594fSAndroid Build Coastguard Worker       break;
8315*795d594fSAndroid Build Coastguard Worker     }
8316*795d594fSAndroid Build Coastguard Worker 
8317*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kUnresolvedCheck:
8318*795d594fSAndroid Build Coastguard Worker       // We always go into the type check slow path for the unresolved check case.
8319*795d594fSAndroid Build Coastguard Worker       // We cannot directly call the CheckCast runtime entry point
8320*795d594fSAndroid Build Coastguard Worker       // without resorting to a type checking slow path here (i.e. by
8321*795d594fSAndroid Build Coastguard Worker       // calling InvokeRuntime directly), as it would require to
8322*795d594fSAndroid Build Coastguard Worker       // assign fixed registers for the inputs of this HInstanceOf
8323*795d594fSAndroid Build Coastguard Worker       // instruction (following the runtime calling convention), which
8324*795d594fSAndroid Build Coastguard Worker       // might be cluttered by the potential first read barrier
8325*795d594fSAndroid Build Coastguard Worker       // emission at the beginning of this method.
8326*795d594fSAndroid Build Coastguard Worker       __ jmp(type_check_slow_path->GetEntryLabel());
8327*795d594fSAndroid Build Coastguard Worker       break;
8328*795d594fSAndroid Build Coastguard Worker 
8329*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kInterfaceCheck: {
8330*795d594fSAndroid Build Coastguard Worker       // Fast path for the interface check. Try to avoid read barriers to improve the fast path.
8331*795d594fSAndroid Build Coastguard Worker       // We can not get false positives by doing this.
8332*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8333*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8334*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8335*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8336*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8337*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8338*795d594fSAndroid Build Coastguard Worker 
8339*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = temp->iftable_
8340*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadOneRegister(instruction,
8341*795d594fSAndroid Build Coastguard Worker                                        temp_loc,
8342*795d594fSAndroid Build Coastguard Worker                                        iftable_offset,
8343*795d594fSAndroid Build Coastguard Worker                                        maybe_temp2_loc,
8344*795d594fSAndroid Build Coastguard Worker                                        kWithoutReadBarrier);
8345*795d594fSAndroid Build Coastguard Worker       // Load the size of the `IfTable`. The `Class::iftable_` is never null.
8346*795d594fSAndroid Build Coastguard Worker       __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
8347*795d594fSAndroid Build Coastguard Worker       // Maybe poison the `cls` for direct comparison with memory.
8348*795d594fSAndroid Build Coastguard Worker       __ MaybePoisonHeapReference(cls.AsRegister<Register>());
8349*795d594fSAndroid Build Coastguard Worker       // Loop through the iftable and check if any class matches.
8350*795d594fSAndroid Build Coastguard Worker       NearLabel start_loop;
8351*795d594fSAndroid Build Coastguard Worker       __ Bind(&start_loop);
8352*795d594fSAndroid Build Coastguard Worker       // Check if we still have an entry to compare.
8353*795d594fSAndroid Build Coastguard Worker       __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2));
8354*795d594fSAndroid Build Coastguard Worker       __ j(kNegative, type_check_slow_path->GetEntryLabel());
8355*795d594fSAndroid Build Coastguard Worker       // Go to next interface if the classes do not match.
8356*795d594fSAndroid Build Coastguard Worker       __ cmpl(cls.AsRegister<Register>(),
8357*795d594fSAndroid Build Coastguard Worker               CodeGeneratorX86::ArrayAddress(temp,
8358*795d594fSAndroid Build Coastguard Worker                                              maybe_temp2_loc,
8359*795d594fSAndroid Build Coastguard Worker                                              TIMES_4,
8360*795d594fSAndroid Build Coastguard Worker                                              object_array_data_offset));
8361*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, &start_loop);
8362*795d594fSAndroid Build Coastguard Worker       // If `cls` was poisoned above, unpoison it.
8363*795d594fSAndroid Build Coastguard Worker       __ MaybeUnpoisonHeapReference(cls.AsRegister<Register>());
8364*795d594fSAndroid Build Coastguard Worker       break;
8365*795d594fSAndroid Build Coastguard Worker     }
8366*795d594fSAndroid Build Coastguard Worker 
8367*795d594fSAndroid Build Coastguard Worker     case TypeCheckKind::kBitstringCheck: {
8368*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Class> */ temp = obj->klass_
8369*795d594fSAndroid Build Coastguard Worker       GenerateReferenceLoadTwoRegisters(instruction,
8370*795d594fSAndroid Build Coastguard Worker                                         temp_loc,
8371*795d594fSAndroid Build Coastguard Worker                                         obj_loc,
8372*795d594fSAndroid Build Coastguard Worker                                         class_offset,
8373*795d594fSAndroid Build Coastguard Worker                                         kWithoutReadBarrier);
8374*795d594fSAndroid Build Coastguard Worker 
8375*795d594fSAndroid Build Coastguard Worker       GenerateBitstringTypeCheckCompare(instruction, temp);
8376*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
8377*795d594fSAndroid Build Coastguard Worker       break;
8378*795d594fSAndroid Build Coastguard Worker     }
8379*795d594fSAndroid Build Coastguard Worker   }
8380*795d594fSAndroid Build Coastguard Worker   __ Bind(&done);
8381*795d594fSAndroid Build Coastguard Worker 
8382*795d594fSAndroid Build Coastguard Worker   __ Bind(type_check_slow_path->GetExitLabel());
8383*795d594fSAndroid Build Coastguard Worker }
8384*795d594fSAndroid Build Coastguard Worker 
VisitMonitorOperation(HMonitorOperation * instruction)8385*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
8386*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8387*795d594fSAndroid Build Coastguard Worker       instruction, LocationSummary::kCallOnMainOnly);
8388*795d594fSAndroid Build Coastguard Worker   InvokeRuntimeCallingConvention calling_convention;
8389*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8390*795d594fSAndroid Build Coastguard Worker }
8391*795d594fSAndroid Build Coastguard Worker 
VisitMonitorOperation(HMonitorOperation * instruction)8392*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
8393*795d594fSAndroid Build Coastguard Worker   codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject
8394*795d594fSAndroid Build Coastguard Worker                                                  : kQuickUnlockObject,
8395*795d594fSAndroid Build Coastguard Worker                           instruction,
8396*795d594fSAndroid Build Coastguard Worker                           instruction->GetDexPc());
8397*795d594fSAndroid Build Coastguard Worker   if (instruction->IsEnter()) {
8398*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
8399*795d594fSAndroid Build Coastguard Worker   } else {
8400*795d594fSAndroid Build Coastguard Worker     CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
8401*795d594fSAndroid Build Coastguard Worker   }
8402*795d594fSAndroid Build Coastguard Worker }
8403*795d594fSAndroid Build Coastguard Worker 
VisitX86AndNot(HX86AndNot * instruction)8404*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86AndNot(HX86AndNot* instruction) {
8405*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
8406*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsIntOrLongType(instruction->GetType())) << instruction->GetType();
8407*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
8408*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8409*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
8410*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8411*795d594fSAndroid Build Coastguard Worker }
8412*795d594fSAndroid Build Coastguard Worker 
VisitX86AndNot(HX86AndNot * instruction)8413*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86AndNot(HX86AndNot* instruction) {
8414*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
8415*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
8416*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
8417*795d594fSAndroid Build Coastguard Worker   Location dest = locations->Out();
8418*795d594fSAndroid Build Coastguard Worker   if (instruction->GetResultType() == DataType::Type::kInt32) {
8419*795d594fSAndroid Build Coastguard Worker     __ andn(dest.AsRegister<Register>(),
8420*795d594fSAndroid Build Coastguard Worker             first.AsRegister<Register>(),
8421*795d594fSAndroid Build Coastguard Worker             second.AsRegister<Register>());
8422*795d594fSAndroid Build Coastguard Worker   } else {
8423*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
8424*795d594fSAndroid Build Coastguard Worker     __ andn(dest.AsRegisterPairLow<Register>(),
8425*795d594fSAndroid Build Coastguard Worker             first.AsRegisterPairLow<Register>(),
8426*795d594fSAndroid Build Coastguard Worker             second.AsRegisterPairLow<Register>());
8427*795d594fSAndroid Build Coastguard Worker     __ andn(dest.AsRegisterPairHigh<Register>(),
8428*795d594fSAndroid Build Coastguard Worker             first.AsRegisterPairHigh<Register>(),
8429*795d594fSAndroid Build Coastguard Worker             second.AsRegisterPairHigh<Register>());
8430*795d594fSAndroid Build Coastguard Worker   }
8431*795d594fSAndroid Build Coastguard Worker }
8432*795d594fSAndroid Build Coastguard Worker 
VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit * instruction)8433*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit* instruction) {
8434*795d594fSAndroid Build Coastguard Worker   DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
8435*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->GetType() == DataType::Type::kInt32) << instruction->GetType();
8436*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
8437*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8438*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8439*795d594fSAndroid Build Coastguard Worker }
8440*795d594fSAndroid Build Coastguard Worker 
VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit * instruction)8441*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86MaskOrResetLeastSetBit(
8442*795d594fSAndroid Build Coastguard Worker     HX86MaskOrResetLeastSetBit* instruction) {
8443*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
8444*795d594fSAndroid Build Coastguard Worker   Location src = locations->InAt(0);
8445*795d594fSAndroid Build Coastguard Worker   Location dest = locations->Out();
8446*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
8447*795d594fSAndroid Build Coastguard Worker   switch (instruction->GetOpKind()) {
8448*795d594fSAndroid Build Coastguard Worker     case HInstruction::kAnd:
8449*795d594fSAndroid Build Coastguard Worker       __ blsr(dest.AsRegister<Register>(), src.AsRegister<Register>());
8450*795d594fSAndroid Build Coastguard Worker       break;
8451*795d594fSAndroid Build Coastguard Worker     case HInstruction::kXor:
8452*795d594fSAndroid Build Coastguard Worker       __ blsmsk(dest.AsRegister<Register>(), src.AsRegister<Register>());
8453*795d594fSAndroid Build Coastguard Worker       break;
8454*795d594fSAndroid Build Coastguard Worker     default:
8455*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable";
8456*795d594fSAndroid Build Coastguard Worker   }
8457*795d594fSAndroid Build Coastguard Worker }
8458*795d594fSAndroid Build Coastguard Worker 
VisitAnd(HAnd * instruction)8459*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
VisitOr(HOr * instruction)8460*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
VisitXor(HXor * instruction)8461*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
8462*795d594fSAndroid Build Coastguard Worker 
HandleBitwiseOperation(HBinaryOperation * instruction)8463*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
8464*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
8465*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
8466*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction->GetResultType() == DataType::Type::kInt32
8467*795d594fSAndroid Build Coastguard Worker          || instruction->GetResultType() == DataType::Type::kInt64);
8468*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8469*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::Any());
8470*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::SameAsFirstInput());
8471*795d594fSAndroid Build Coastguard Worker }
8472*795d594fSAndroid Build Coastguard Worker 
VisitAnd(HAnd * instruction)8473*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
8474*795d594fSAndroid Build Coastguard Worker   HandleBitwiseOperation(instruction);
8475*795d594fSAndroid Build Coastguard Worker }
8476*795d594fSAndroid Build Coastguard Worker 
VisitOr(HOr * instruction)8477*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
8478*795d594fSAndroid Build Coastguard Worker   HandleBitwiseOperation(instruction);
8479*795d594fSAndroid Build Coastguard Worker }
8480*795d594fSAndroid Build Coastguard Worker 
VisitXor(HXor * instruction)8481*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
8482*795d594fSAndroid Build Coastguard Worker   HandleBitwiseOperation(instruction);
8483*795d594fSAndroid Build Coastguard Worker }
8484*795d594fSAndroid Build Coastguard Worker 
HandleBitwiseOperation(HBinaryOperation * instruction)8485*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
8486*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = instruction->GetLocations();
8487*795d594fSAndroid Build Coastguard Worker   Location first = locations->InAt(0);
8488*795d594fSAndroid Build Coastguard Worker   Location second = locations->InAt(1);
8489*795d594fSAndroid Build Coastguard Worker   DCHECK(first.Equals(locations->Out()));
8490*795d594fSAndroid Build Coastguard Worker 
8491*795d594fSAndroid Build Coastguard Worker   if (instruction->GetResultType() == DataType::Type::kInt32) {
8492*795d594fSAndroid Build Coastguard Worker     if (second.IsRegister()) {
8493*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8494*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
8495*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8496*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
8497*795d594fSAndroid Build Coastguard Worker       } else {
8498*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8499*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
8500*795d594fSAndroid Build Coastguard Worker       }
8501*795d594fSAndroid Build Coastguard Worker     } else if (second.IsConstant()) {
8502*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8503*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegister<Register>(),
8504*795d594fSAndroid Build Coastguard Worker                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
8505*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8506*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegister<Register>(),
8507*795d594fSAndroid Build Coastguard Worker                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
8508*795d594fSAndroid Build Coastguard Worker       } else {
8509*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8510*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegister<Register>(),
8511*795d594fSAndroid Build Coastguard Worker                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
8512*795d594fSAndroid Build Coastguard Worker       }
8513*795d594fSAndroid Build Coastguard Worker     } else {
8514*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8515*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
8516*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8517*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
8518*795d594fSAndroid Build Coastguard Worker       } else {
8519*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8520*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
8521*795d594fSAndroid Build Coastguard Worker       }
8522*795d594fSAndroid Build Coastguard Worker     }
8523*795d594fSAndroid Build Coastguard Worker   } else {
8524*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
8525*795d594fSAndroid Build Coastguard Worker     if (second.IsRegisterPair()) {
8526*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8527*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8528*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8529*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8530*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8531*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8532*795d594fSAndroid Build Coastguard Worker       } else {
8533*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8534*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8535*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8536*795d594fSAndroid Build Coastguard Worker       }
8537*795d594fSAndroid Build Coastguard Worker     } else if (second.IsDoubleStackSlot()) {
8538*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8539*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8540*795d594fSAndroid Build Coastguard Worker         __ andl(first.AsRegisterPairHigh<Register>(),
8541*795d594fSAndroid Build Coastguard Worker                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8542*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8543*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8544*795d594fSAndroid Build Coastguard Worker         __ orl(first.AsRegisterPairHigh<Register>(),
8545*795d594fSAndroid Build Coastguard Worker                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8546*795d594fSAndroid Build Coastguard Worker       } else {
8547*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8548*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8549*795d594fSAndroid Build Coastguard Worker         __ xorl(first.AsRegisterPairHigh<Register>(),
8550*795d594fSAndroid Build Coastguard Worker                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8551*795d594fSAndroid Build Coastguard Worker       }
8552*795d594fSAndroid Build Coastguard Worker     } else {
8553*795d594fSAndroid Build Coastguard Worker       DCHECK(second.IsConstant()) << second;
8554*795d594fSAndroid Build Coastguard Worker       int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
8555*795d594fSAndroid Build Coastguard Worker       int32_t low_value = Low32Bits(value);
8556*795d594fSAndroid Build Coastguard Worker       int32_t high_value = High32Bits(value);
8557*795d594fSAndroid Build Coastguard Worker       Immediate low(low_value);
8558*795d594fSAndroid Build Coastguard Worker       Immediate high(high_value);
8559*795d594fSAndroid Build Coastguard Worker       Register first_low = first.AsRegisterPairLow<Register>();
8560*795d594fSAndroid Build Coastguard Worker       Register first_high = first.AsRegisterPairHigh<Register>();
8561*795d594fSAndroid Build Coastguard Worker       if (instruction->IsAnd()) {
8562*795d594fSAndroid Build Coastguard Worker         if (low_value == 0) {
8563*795d594fSAndroid Build Coastguard Worker           __ xorl(first_low, first_low);
8564*795d594fSAndroid Build Coastguard Worker         } else if (low_value != -1) {
8565*795d594fSAndroid Build Coastguard Worker           __ andl(first_low, low);
8566*795d594fSAndroid Build Coastguard Worker         }
8567*795d594fSAndroid Build Coastguard Worker         if (high_value == 0) {
8568*795d594fSAndroid Build Coastguard Worker           __ xorl(first_high, first_high);
8569*795d594fSAndroid Build Coastguard Worker         } else if (high_value != -1) {
8570*795d594fSAndroid Build Coastguard Worker           __ andl(first_high, high);
8571*795d594fSAndroid Build Coastguard Worker         }
8572*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsOr()) {
8573*795d594fSAndroid Build Coastguard Worker         if (low_value != 0) {
8574*795d594fSAndroid Build Coastguard Worker           __ orl(first_low, low);
8575*795d594fSAndroid Build Coastguard Worker         }
8576*795d594fSAndroid Build Coastguard Worker         if (high_value != 0) {
8577*795d594fSAndroid Build Coastguard Worker           __ orl(first_high, high);
8578*795d594fSAndroid Build Coastguard Worker         }
8579*795d594fSAndroid Build Coastguard Worker       } else {
8580*795d594fSAndroid Build Coastguard Worker         DCHECK(instruction->IsXor());
8581*795d594fSAndroid Build Coastguard Worker         if (low_value != 0) {
8582*795d594fSAndroid Build Coastguard Worker           __ xorl(first_low, low);
8583*795d594fSAndroid Build Coastguard Worker         }
8584*795d594fSAndroid Build Coastguard Worker         if (high_value != 0) {
8585*795d594fSAndroid Build Coastguard Worker           __ xorl(first_high, high);
8586*795d594fSAndroid Build Coastguard Worker         }
8587*795d594fSAndroid Build Coastguard Worker       }
8588*795d594fSAndroid Build Coastguard Worker     }
8589*795d594fSAndroid Build Coastguard Worker   }
8590*795d594fSAndroid Build Coastguard Worker }
8591*795d594fSAndroid Build Coastguard Worker 
GenerateReferenceLoadOneRegister(HInstruction * instruction,Location out,uint32_t offset,Location maybe_temp,ReadBarrierOption read_barrier_option)8592*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateReferenceLoadOneRegister(
8593*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction,
8594*795d594fSAndroid Build Coastguard Worker     Location out,
8595*795d594fSAndroid Build Coastguard Worker     uint32_t offset,
8596*795d594fSAndroid Build Coastguard Worker     Location maybe_temp,
8597*795d594fSAndroid Build Coastguard Worker     ReadBarrierOption read_barrier_option) {
8598*795d594fSAndroid Build Coastguard Worker   Register out_reg = out.AsRegister<Register>();
8599*795d594fSAndroid Build Coastguard Worker   if (read_barrier_option == kWithReadBarrier) {
8600*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen_->EmitReadBarrier());
8601*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
8602*795d594fSAndroid Build Coastguard Worker       // Load with fast path based Baker's read barrier.
8603*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Object> */ out = *(out + offset)
8604*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(
8605*795d594fSAndroid Build Coastguard Worker           instruction, out, out_reg, offset, /* needs_null_check= */ false);
8606*795d594fSAndroid Build Coastguard Worker     } else {
8607*795d594fSAndroid Build Coastguard Worker       // Load with slow path based read barrier.
8608*795d594fSAndroid Build Coastguard Worker       // Save the value of `out` into `maybe_temp` before overwriting it
8609*795d594fSAndroid Build Coastguard Worker       // in the following move operation, as we will need it for the
8610*795d594fSAndroid Build Coastguard Worker       // read barrier below.
8611*795d594fSAndroid Build Coastguard Worker       DCHECK(maybe_temp.IsRegister()) << maybe_temp;
8612*795d594fSAndroid Build Coastguard Worker       __ movl(maybe_temp.AsRegister<Register>(), out_reg);
8613*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Object> */ out = *(out + offset)
8614*795d594fSAndroid Build Coastguard Worker       __ movl(out_reg, Address(out_reg, offset));
8615*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
8616*795d594fSAndroid Build Coastguard Worker     }
8617*795d594fSAndroid Build Coastguard Worker   } else {
8618*795d594fSAndroid Build Coastguard Worker     // Plain load with no read barrier.
8619*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Object> */ out = *(out + offset)
8620*795d594fSAndroid Build Coastguard Worker     __ movl(out_reg, Address(out_reg, offset));
8621*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(out_reg);
8622*795d594fSAndroid Build Coastguard Worker   }
8623*795d594fSAndroid Build Coastguard Worker }
8624*795d594fSAndroid Build Coastguard Worker 
GenerateReferenceLoadTwoRegisters(HInstruction * instruction,Location out,Location obj,uint32_t offset,ReadBarrierOption read_barrier_option)8625*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateReferenceLoadTwoRegisters(
8626*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction,
8627*795d594fSAndroid Build Coastguard Worker     Location out,
8628*795d594fSAndroid Build Coastguard Worker     Location obj,
8629*795d594fSAndroid Build Coastguard Worker     uint32_t offset,
8630*795d594fSAndroid Build Coastguard Worker     ReadBarrierOption read_barrier_option) {
8631*795d594fSAndroid Build Coastguard Worker   Register out_reg = out.AsRegister<Register>();
8632*795d594fSAndroid Build Coastguard Worker   Register obj_reg = obj.AsRegister<Register>();
8633*795d594fSAndroid Build Coastguard Worker   if (read_barrier_option == kWithReadBarrier) {
8634*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen_->EmitReadBarrier());
8635*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
8636*795d594fSAndroid Build Coastguard Worker       // Load with fast path based Baker's read barrier.
8637*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Object> */ out = *(obj + offset)
8638*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateFieldLoadWithBakerReadBarrier(
8639*795d594fSAndroid Build Coastguard Worker           instruction, out, obj_reg, offset, /* needs_null_check= */ false);
8640*795d594fSAndroid Build Coastguard Worker     } else {
8641*795d594fSAndroid Build Coastguard Worker       // Load with slow path based read barrier.
8642*795d594fSAndroid Build Coastguard Worker       // /* HeapReference<Object> */ out = *(obj + offset)
8643*795d594fSAndroid Build Coastguard Worker       __ movl(out_reg, Address(obj_reg, offset));
8644*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
8645*795d594fSAndroid Build Coastguard Worker     }
8646*795d594fSAndroid Build Coastguard Worker   } else {
8647*795d594fSAndroid Build Coastguard Worker     // Plain load with no read barrier.
8648*795d594fSAndroid Build Coastguard Worker     // /* HeapReference<Object> */ out = *(obj + offset)
8649*795d594fSAndroid Build Coastguard Worker     __ movl(out_reg, Address(obj_reg, offset));
8650*795d594fSAndroid Build Coastguard Worker     __ MaybeUnpoisonHeapReference(out_reg);
8651*795d594fSAndroid Build Coastguard Worker   }
8652*795d594fSAndroid Build Coastguard Worker }
8653*795d594fSAndroid Build Coastguard Worker 
GenerateGcRootFieldLoad(HInstruction * instruction,Location root,const Address & address,Label * fixup_label,ReadBarrierOption read_barrier_option)8654*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenerateGcRootFieldLoad(
8655*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction,
8656*795d594fSAndroid Build Coastguard Worker     Location root,
8657*795d594fSAndroid Build Coastguard Worker     const Address& address,
8658*795d594fSAndroid Build Coastguard Worker     Label* fixup_label,
8659*795d594fSAndroid Build Coastguard Worker     ReadBarrierOption read_barrier_option) {
8660*795d594fSAndroid Build Coastguard Worker   Register root_reg = root.AsRegister<Register>();
8661*795d594fSAndroid Build Coastguard Worker   if (read_barrier_option == kWithReadBarrier) {
8662*795d594fSAndroid Build Coastguard Worker     DCHECK(codegen_->EmitReadBarrier());
8663*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
8664*795d594fSAndroid Build Coastguard Worker       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
8665*795d594fSAndroid Build Coastguard Worker       // Baker's read barrier are used:
8666*795d594fSAndroid Build Coastguard Worker       //
8667*795d594fSAndroid Build Coastguard Worker       //   root = obj.field;
8668*795d594fSAndroid Build Coastguard Worker       //   temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8669*795d594fSAndroid Build Coastguard Worker       //   if (temp != null) {
8670*795d594fSAndroid Build Coastguard Worker       //     root = temp(root)
8671*795d594fSAndroid Build Coastguard Worker       //   }
8672*795d594fSAndroid Build Coastguard Worker 
8673*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::Object> */ root = *address
8674*795d594fSAndroid Build Coastguard Worker       __ movl(root_reg, address);
8675*795d594fSAndroid Build Coastguard Worker       if (fixup_label != nullptr) {
8676*795d594fSAndroid Build Coastguard Worker         __ Bind(fixup_label);
8677*795d594fSAndroid Build Coastguard Worker       }
8678*795d594fSAndroid Build Coastguard Worker       static_assert(
8679*795d594fSAndroid Build Coastguard Worker           sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
8680*795d594fSAndroid Build Coastguard Worker           "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
8681*795d594fSAndroid Build Coastguard Worker           "have different sizes.");
8682*795d594fSAndroid Build Coastguard Worker       static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
8683*795d594fSAndroid Build Coastguard Worker                     "art::mirror::CompressedReference<mirror::Object> and int32_t "
8684*795d594fSAndroid Build Coastguard Worker                     "have different sizes.");
8685*795d594fSAndroid Build Coastguard Worker 
8686*795d594fSAndroid Build Coastguard Worker       // Slow path marking the GC root `root`.
8687*795d594fSAndroid Build Coastguard Worker       SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) ReadBarrierMarkSlowPathX86(
8688*795d594fSAndroid Build Coastguard Worker           instruction, root, /* unpoison_ref_before_marking= */ false);
8689*795d594fSAndroid Build Coastguard Worker       codegen_->AddSlowPath(slow_path);
8690*795d594fSAndroid Build Coastguard Worker 
8691*795d594fSAndroid Build Coastguard Worker       // Test the entrypoint (`Thread::Current()->pReadBarrierMarkReg ## root.reg()`).
8692*795d594fSAndroid Build Coastguard Worker       const int32_t entry_point_offset =
8693*795d594fSAndroid Build Coastguard Worker           Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(root.reg());
8694*795d594fSAndroid Build Coastguard Worker       __ fs()->cmpl(Address::Absolute(entry_point_offset), Immediate(0));
8695*795d594fSAndroid Build Coastguard Worker       // The entrypoint is null when the GC is not marking.
8696*795d594fSAndroid Build Coastguard Worker       __ j(kNotEqual, slow_path->GetEntryLabel());
8697*795d594fSAndroid Build Coastguard Worker       __ Bind(slow_path->GetExitLabel());
8698*795d594fSAndroid Build Coastguard Worker     } else {
8699*795d594fSAndroid Build Coastguard Worker       // GC root loaded through a slow path for read barriers other
8700*795d594fSAndroid Build Coastguard Worker       // than Baker's.
8701*795d594fSAndroid Build Coastguard Worker       // /* GcRoot<mirror::Object>* */ root = address
8702*795d594fSAndroid Build Coastguard Worker       __ leal(root_reg, address);
8703*795d594fSAndroid Build Coastguard Worker       if (fixup_label != nullptr) {
8704*795d594fSAndroid Build Coastguard Worker         __ Bind(fixup_label);
8705*795d594fSAndroid Build Coastguard Worker       }
8706*795d594fSAndroid Build Coastguard Worker       // /* mirror::Object* */ root = root->Read()
8707*795d594fSAndroid Build Coastguard Worker       codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
8708*795d594fSAndroid Build Coastguard Worker     }
8709*795d594fSAndroid Build Coastguard Worker   } else {
8710*795d594fSAndroid Build Coastguard Worker     // Plain GC root load with no read barrier.
8711*795d594fSAndroid Build Coastguard Worker     // /* GcRoot<mirror::Object> */ root = *address
8712*795d594fSAndroid Build Coastguard Worker     __ movl(root_reg, address);
8713*795d594fSAndroid Build Coastguard Worker     if (fixup_label != nullptr) {
8714*795d594fSAndroid Build Coastguard Worker       __ Bind(fixup_label);
8715*795d594fSAndroid Build Coastguard Worker     }
8716*795d594fSAndroid Build Coastguard Worker     // Note that GC roots are not affected by heap poisoning, thus we
8717*795d594fSAndroid Build Coastguard Worker     // do not have to unpoison `root_reg` here.
8718*795d594fSAndroid Build Coastguard Worker   }
8719*795d594fSAndroid Build Coastguard Worker }
8720*795d594fSAndroid Build Coastguard Worker 
GenerateFieldLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t offset,bool needs_null_check)8721*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
8722*795d594fSAndroid Build Coastguard Worker                                                              Location ref,
8723*795d594fSAndroid Build Coastguard Worker                                                              Register obj,
8724*795d594fSAndroid Build Coastguard Worker                                                              uint32_t offset,
8725*795d594fSAndroid Build Coastguard Worker                                                              bool needs_null_check) {
8726*795d594fSAndroid Build Coastguard Worker   DCHECK(EmitBakerReadBarrier());
8727*795d594fSAndroid Build Coastguard Worker 
8728*795d594fSAndroid Build Coastguard Worker   // /* HeapReference<Object> */ ref = *(obj + offset)
8729*795d594fSAndroid Build Coastguard Worker   Address src(obj, offset);
8730*795d594fSAndroid Build Coastguard Worker   GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
8731*795d594fSAndroid Build Coastguard Worker }
8732*795d594fSAndroid Build Coastguard Worker 
GenerateArrayLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,uint32_t data_offset,Location index,bool needs_null_check)8733*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8734*795d594fSAndroid Build Coastguard Worker                                                              Location ref,
8735*795d594fSAndroid Build Coastguard Worker                                                              Register obj,
8736*795d594fSAndroid Build Coastguard Worker                                                              uint32_t data_offset,
8737*795d594fSAndroid Build Coastguard Worker                                                              Location index,
8738*795d594fSAndroid Build Coastguard Worker                                                              bool needs_null_check) {
8739*795d594fSAndroid Build Coastguard Worker   DCHECK(EmitBakerReadBarrier());
8740*795d594fSAndroid Build Coastguard Worker 
8741*795d594fSAndroid Build Coastguard Worker   static_assert(
8742*795d594fSAndroid Build Coastguard Worker       sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8743*795d594fSAndroid Build Coastguard Worker       "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
8744*795d594fSAndroid Build Coastguard Worker   // /* HeapReference<Object> */ ref =
8745*795d594fSAndroid Build Coastguard Worker   //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
8746*795d594fSAndroid Build Coastguard Worker   Address src = CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset);
8747*795d594fSAndroid Build Coastguard Worker   GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
8748*795d594fSAndroid Build Coastguard Worker }
8749*795d594fSAndroid Build Coastguard Worker 
GenerateReferenceLoadWithBakerReadBarrier(HInstruction * instruction,Location ref,Register obj,const Address & src,bool needs_null_check,bool always_update_field,Register * temp)8750*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8751*795d594fSAndroid Build Coastguard Worker                                                                  Location ref,
8752*795d594fSAndroid Build Coastguard Worker                                                                  Register obj,
8753*795d594fSAndroid Build Coastguard Worker                                                                  const Address& src,
8754*795d594fSAndroid Build Coastguard Worker                                                                  bool needs_null_check,
8755*795d594fSAndroid Build Coastguard Worker                                                                  bool always_update_field,
8756*795d594fSAndroid Build Coastguard Worker                                                                  Register* temp) {
8757*795d594fSAndroid Build Coastguard Worker   DCHECK(EmitBakerReadBarrier());
8758*795d594fSAndroid Build Coastguard Worker 
8759*795d594fSAndroid Build Coastguard Worker   // In slow path based read barriers, the read barrier call is
8760*795d594fSAndroid Build Coastguard Worker   // inserted after the original load. However, in fast path based
8761*795d594fSAndroid Build Coastguard Worker   // Baker's read barriers, we need to perform the load of
8762*795d594fSAndroid Build Coastguard Worker   // mirror::Object::monitor_ *before* the original reference load.
8763*795d594fSAndroid Build Coastguard Worker   // This load-load ordering is required by the read barrier.
8764*795d594fSAndroid Build Coastguard Worker   // The fast path/slow path (for Baker's algorithm) should look like:
8765*795d594fSAndroid Build Coastguard Worker   //
8766*795d594fSAndroid Build Coastguard Worker   //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8767*795d594fSAndroid Build Coastguard Worker   //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
8768*795d594fSAndroid Build Coastguard Worker   //   HeapReference<Object> ref = *src;  // Original reference load.
8769*795d594fSAndroid Build Coastguard Worker   //   bool is_gray = (rb_state == ReadBarrier::GrayState());
8770*795d594fSAndroid Build Coastguard Worker   //   if (is_gray) {
8771*795d594fSAndroid Build Coastguard Worker   //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
8772*795d594fSAndroid Build Coastguard Worker   //   }
8773*795d594fSAndroid Build Coastguard Worker   //
8774*795d594fSAndroid Build Coastguard Worker   // Note: the original implementation in ReadBarrier::Barrier is
8775*795d594fSAndroid Build Coastguard Worker   // slightly more complex as:
8776*795d594fSAndroid Build Coastguard Worker   // - it implements the load-load fence using a data dependency on
8777*795d594fSAndroid Build Coastguard Worker   //   the high-bits of rb_state, which are expected to be all zeroes
8778*795d594fSAndroid Build Coastguard Worker   //   (we use CodeGeneratorX86::GenerateMemoryBarrier instead here,
8779*795d594fSAndroid Build Coastguard Worker   //   which is a no-op thanks to the x86 memory model);
8780*795d594fSAndroid Build Coastguard Worker   // - it performs additional checks that we do not do here for
8781*795d594fSAndroid Build Coastguard Worker   //   performance reasons.
8782*795d594fSAndroid Build Coastguard Worker 
8783*795d594fSAndroid Build Coastguard Worker   Register ref_reg = ref.AsRegister<Register>();
8784*795d594fSAndroid Build Coastguard Worker   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
8785*795d594fSAndroid Build Coastguard Worker 
8786*795d594fSAndroid Build Coastguard Worker   // Given the numeric representation, it's enough to check the low bit of the rb_state.
8787*795d594fSAndroid Build Coastguard Worker   static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
8788*795d594fSAndroid Build Coastguard Worker   static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
8789*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
8790*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
8791*795d594fSAndroid Build Coastguard Worker   constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
8792*795d594fSAndroid Build Coastguard Worker 
8793*795d594fSAndroid Build Coastguard Worker   // if (rb_state == ReadBarrier::GrayState())
8794*795d594fSAndroid Build Coastguard Worker   //   ref = ReadBarrier::Mark(ref);
8795*795d594fSAndroid Build Coastguard Worker   // At this point, just do the "if" and make sure that flags are preserved until the branch.
8796*795d594fSAndroid Build Coastguard Worker   __ testb(Address(obj, monitor_offset + gray_byte_position), Immediate(test_value));
8797*795d594fSAndroid Build Coastguard Worker   if (needs_null_check) {
8798*795d594fSAndroid Build Coastguard Worker     MaybeRecordImplicitNullCheck(instruction);
8799*795d594fSAndroid Build Coastguard Worker   }
8800*795d594fSAndroid Build Coastguard Worker 
8801*795d594fSAndroid Build Coastguard Worker   // Load fence to prevent load-load reordering.
8802*795d594fSAndroid Build Coastguard Worker   // Note that this is a no-op, thanks to the x86 memory model.
8803*795d594fSAndroid Build Coastguard Worker   GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
8804*795d594fSAndroid Build Coastguard Worker 
8805*795d594fSAndroid Build Coastguard Worker   // The actual reference load.
8806*795d594fSAndroid Build Coastguard Worker   // /* HeapReference<Object> */ ref = *src
8807*795d594fSAndroid Build Coastguard Worker   __ movl(ref_reg, src);  // Flags are unaffected.
8808*795d594fSAndroid Build Coastguard Worker 
8809*795d594fSAndroid Build Coastguard Worker   // Note: Reference unpoisoning modifies the flags, so we need to delay it after the branch.
8810*795d594fSAndroid Build Coastguard Worker   // Slow path marking the object `ref` when it is gray.
8811*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path;
8812*795d594fSAndroid Build Coastguard Worker   if (always_update_field) {
8813*795d594fSAndroid Build Coastguard Worker     DCHECK(temp != nullptr);
8814*795d594fSAndroid Build Coastguard Worker     slow_path = new (GetScopedAllocator()) ReadBarrierMarkAndUpdateFieldSlowPathX86(
8815*795d594fSAndroid Build Coastguard Worker         instruction, ref, obj, src, /* unpoison_ref_before_marking= */ true, *temp);
8816*795d594fSAndroid Build Coastguard Worker   } else {
8817*795d594fSAndroid Build Coastguard Worker     slow_path = new (GetScopedAllocator()) ReadBarrierMarkSlowPathX86(
8818*795d594fSAndroid Build Coastguard Worker         instruction, ref, /* unpoison_ref_before_marking= */ true);
8819*795d594fSAndroid Build Coastguard Worker   }
8820*795d594fSAndroid Build Coastguard Worker   AddSlowPath(slow_path);
8821*795d594fSAndroid Build Coastguard Worker 
8822*795d594fSAndroid Build Coastguard Worker   // We have done the "if" of the gray bit check above, now branch based on the flags.
8823*795d594fSAndroid Build Coastguard Worker   __ j(kNotZero, slow_path->GetEntryLabel());
8824*795d594fSAndroid Build Coastguard Worker 
8825*795d594fSAndroid Build Coastguard Worker   // Object* ref = ref_addr->AsMirrorPtr()
8826*795d594fSAndroid Build Coastguard Worker   __ MaybeUnpoisonHeapReference(ref_reg);
8827*795d594fSAndroid Build Coastguard Worker 
8828*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
8829*795d594fSAndroid Build Coastguard Worker }
8830*795d594fSAndroid Build Coastguard Worker 
GenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)8831*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateReadBarrierSlow(HInstruction* instruction,
8832*795d594fSAndroid Build Coastguard Worker                                                Location out,
8833*795d594fSAndroid Build Coastguard Worker                                                Location ref,
8834*795d594fSAndroid Build Coastguard Worker                                                Location obj,
8835*795d594fSAndroid Build Coastguard Worker                                                uint32_t offset,
8836*795d594fSAndroid Build Coastguard Worker                                                Location index) {
8837*795d594fSAndroid Build Coastguard Worker   DCHECK(EmitReadBarrier());
8838*795d594fSAndroid Build Coastguard Worker 
8839*795d594fSAndroid Build Coastguard Worker   // Insert a slow path based read barrier *after* the reference load.
8840*795d594fSAndroid Build Coastguard Worker   //
8841*795d594fSAndroid Build Coastguard Worker   // If heap poisoning is enabled, the unpoisoning of the loaded
8842*795d594fSAndroid Build Coastguard Worker   // reference will be carried out by the runtime within the slow
8843*795d594fSAndroid Build Coastguard Worker   // path.
8844*795d594fSAndroid Build Coastguard Worker   //
8845*795d594fSAndroid Build Coastguard Worker   // Note that `ref` currently does not get unpoisoned (when heap
8846*795d594fSAndroid Build Coastguard Worker   // poisoning is enabled), which is alright as the `ref` argument is
8847*795d594fSAndroid Build Coastguard Worker   // not used by the artReadBarrierSlow entry point.
8848*795d594fSAndroid Build Coastguard Worker   //
8849*795d594fSAndroid Build Coastguard Worker   // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
8850*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path = new (GetScopedAllocator())
8851*795d594fSAndroid Build Coastguard Worker       ReadBarrierForHeapReferenceSlowPathX86(instruction, out, ref, obj, offset, index);
8852*795d594fSAndroid Build Coastguard Worker   AddSlowPath(slow_path);
8853*795d594fSAndroid Build Coastguard Worker 
8854*795d594fSAndroid Build Coastguard Worker   __ jmp(slow_path->GetEntryLabel());
8855*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
8856*795d594fSAndroid Build Coastguard Worker }
8857*795d594fSAndroid Build Coastguard Worker 
MaybeGenerateReadBarrierSlow(HInstruction * instruction,Location out,Location ref,Location obj,uint32_t offset,Location index)8858*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8859*795d594fSAndroid Build Coastguard Worker                                                     Location out,
8860*795d594fSAndroid Build Coastguard Worker                                                     Location ref,
8861*795d594fSAndroid Build Coastguard Worker                                                     Location obj,
8862*795d594fSAndroid Build Coastguard Worker                                                     uint32_t offset,
8863*795d594fSAndroid Build Coastguard Worker                                                     Location index) {
8864*795d594fSAndroid Build Coastguard Worker   if (EmitReadBarrier()) {
8865*795d594fSAndroid Build Coastguard Worker     // Baker's read barriers shall be handled by the fast path
8866*795d594fSAndroid Build Coastguard Worker     // (CodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier).
8867*795d594fSAndroid Build Coastguard Worker     DCHECK(!kUseBakerReadBarrier);
8868*795d594fSAndroid Build Coastguard Worker     // If heap poisoning is enabled, unpoisoning will be taken care of
8869*795d594fSAndroid Build Coastguard Worker     // by the runtime within the slow path.
8870*795d594fSAndroid Build Coastguard Worker     GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
8871*795d594fSAndroid Build Coastguard Worker   } else if (kPoisonHeapReferences) {
8872*795d594fSAndroid Build Coastguard Worker     __ UnpoisonHeapReference(out.AsRegister<Register>());
8873*795d594fSAndroid Build Coastguard Worker   }
8874*795d594fSAndroid Build Coastguard Worker }
8875*795d594fSAndroid Build Coastguard Worker 
GenerateReadBarrierForRootSlow(HInstruction * instruction,Location out,Location root)8876*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8877*795d594fSAndroid Build Coastguard Worker                                                       Location out,
8878*795d594fSAndroid Build Coastguard Worker                                                       Location root) {
8879*795d594fSAndroid Build Coastguard Worker   DCHECK(EmitReadBarrier());
8880*795d594fSAndroid Build Coastguard Worker 
8881*795d594fSAndroid Build Coastguard Worker   // Insert a slow path based read barrier *after* the GC root load.
8882*795d594fSAndroid Build Coastguard Worker   //
8883*795d594fSAndroid Build Coastguard Worker   // Note that GC roots are not affected by heap poisoning, so we do
8884*795d594fSAndroid Build Coastguard Worker   // not need to do anything special for this here.
8885*795d594fSAndroid Build Coastguard Worker   SlowPathCode* slow_path =
8886*795d594fSAndroid Build Coastguard Worker       new (GetScopedAllocator()) ReadBarrierForRootSlowPathX86(instruction, out, root);
8887*795d594fSAndroid Build Coastguard Worker   AddSlowPath(slow_path);
8888*795d594fSAndroid Build Coastguard Worker 
8889*795d594fSAndroid Build Coastguard Worker   __ jmp(slow_path->GetEntryLabel());
8890*795d594fSAndroid Build Coastguard Worker   __ Bind(slow_path->GetExitLabel());
8891*795d594fSAndroid Build Coastguard Worker }
8892*795d594fSAndroid Build Coastguard Worker 
VisitBoundType(HBoundType * instruction)8893*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBoundType([[maybe_unused]] HBoundType* instruction) {
8894*795d594fSAndroid Build Coastguard Worker   // Nothing to do, this should be removed during prepare for register allocator.
8895*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
8896*795d594fSAndroid Build Coastguard Worker }
8897*795d594fSAndroid Build Coastguard Worker 
VisitBoundType(HBoundType * instruction)8898*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBoundType([[maybe_unused]] HBoundType* instruction) {
8899*795d594fSAndroid Build Coastguard Worker   // Nothing to do, this should be removed during prepare for register allocator.
8900*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
8901*795d594fSAndroid Build Coastguard Worker }
8902*795d594fSAndroid Build Coastguard Worker 
8903*795d594fSAndroid Build Coastguard Worker // Simple implementation of packed switch - generate cascaded compare/jumps.
VisitPackedSwitch(HPackedSwitch * switch_instr)8904*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8905*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
8906*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8907*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8908*795d594fSAndroid Build Coastguard Worker }
8909*795d594fSAndroid Build Coastguard Worker 
GenPackedSwitchWithCompares(Register value_reg,int32_t lower_bound,uint32_t num_entries,HBasicBlock * switch_block,HBasicBlock * default_block)8910*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::GenPackedSwitchWithCompares(Register value_reg,
8911*795d594fSAndroid Build Coastguard Worker                                                               int32_t lower_bound,
8912*795d594fSAndroid Build Coastguard Worker                                                               uint32_t num_entries,
8913*795d594fSAndroid Build Coastguard Worker                                                               HBasicBlock* switch_block,
8914*795d594fSAndroid Build Coastguard Worker                                                               HBasicBlock* default_block) {
8915*795d594fSAndroid Build Coastguard Worker   // Figure out the correct compare values and jump conditions.
8916*795d594fSAndroid Build Coastguard Worker   // Handle the first compare/branch as a special case because it might
8917*795d594fSAndroid Build Coastguard Worker   // jump to the default case.
8918*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(num_entries, 2u);
8919*795d594fSAndroid Build Coastguard Worker   Condition first_condition;
8920*795d594fSAndroid Build Coastguard Worker   uint32_t index;
8921*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
8922*795d594fSAndroid Build Coastguard Worker   if (lower_bound != 0) {
8923*795d594fSAndroid Build Coastguard Worker     first_condition = kLess;
8924*795d594fSAndroid Build Coastguard Worker     __ cmpl(value_reg, Immediate(lower_bound));
8925*795d594fSAndroid Build Coastguard Worker     __ j(first_condition, codegen_->GetLabelOf(default_block));
8926*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, codegen_->GetLabelOf(successors[0]));
8927*795d594fSAndroid Build Coastguard Worker 
8928*795d594fSAndroid Build Coastguard Worker     index = 1;
8929*795d594fSAndroid Build Coastguard Worker   } else {
8930*795d594fSAndroid Build Coastguard Worker     // Handle all the compare/jumps below.
8931*795d594fSAndroid Build Coastguard Worker     first_condition = kBelow;
8932*795d594fSAndroid Build Coastguard Worker     index = 0;
8933*795d594fSAndroid Build Coastguard Worker   }
8934*795d594fSAndroid Build Coastguard Worker 
8935*795d594fSAndroid Build Coastguard Worker   // Handle the rest of the compare/jumps.
8936*795d594fSAndroid Build Coastguard Worker   for (; index + 1 < num_entries; index += 2) {
8937*795d594fSAndroid Build Coastguard Worker     int32_t compare_to_value = lower_bound + index + 1;
8938*795d594fSAndroid Build Coastguard Worker     __ cmpl(value_reg, Immediate(compare_to_value));
8939*795d594fSAndroid Build Coastguard Worker     // Jump to successors[index] if value < case_value[index].
8940*795d594fSAndroid Build Coastguard Worker     __ j(first_condition, codegen_->GetLabelOf(successors[index]));
8941*795d594fSAndroid Build Coastguard Worker     // Jump to successors[index + 1] if value == case_value[index + 1].
8942*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, codegen_->GetLabelOf(successors[index + 1]));
8943*795d594fSAndroid Build Coastguard Worker   }
8944*795d594fSAndroid Build Coastguard Worker 
8945*795d594fSAndroid Build Coastguard Worker   if (index != num_entries) {
8946*795d594fSAndroid Build Coastguard Worker     // There are an odd number of entries. Handle the last one.
8947*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(index + 1, num_entries);
8948*795d594fSAndroid Build Coastguard Worker     __ cmpl(value_reg, Immediate(lower_bound + index));
8949*795d594fSAndroid Build Coastguard Worker     __ j(kEqual, codegen_->GetLabelOf(successors[index]));
8950*795d594fSAndroid Build Coastguard Worker   }
8951*795d594fSAndroid Build Coastguard Worker 
8952*795d594fSAndroid Build Coastguard Worker   // And the default for any other value.
8953*795d594fSAndroid Build Coastguard Worker   if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
8954*795d594fSAndroid Build Coastguard Worker     __ jmp(codegen_->GetLabelOf(default_block));
8955*795d594fSAndroid Build Coastguard Worker   }
8956*795d594fSAndroid Build Coastguard Worker }
8957*795d594fSAndroid Build Coastguard Worker 
VisitPackedSwitch(HPackedSwitch * switch_instr)8958*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8959*795d594fSAndroid Build Coastguard Worker   int32_t lower_bound = switch_instr->GetStartValue();
8960*795d594fSAndroid Build Coastguard Worker   uint32_t num_entries = switch_instr->GetNumEntries();
8961*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = switch_instr->GetLocations();
8962*795d594fSAndroid Build Coastguard Worker   Register value_reg = locations->InAt(0).AsRegister<Register>();
8963*795d594fSAndroid Build Coastguard Worker 
8964*795d594fSAndroid Build Coastguard Worker   GenPackedSwitchWithCompares(value_reg,
8965*795d594fSAndroid Build Coastguard Worker                               lower_bound,
8966*795d594fSAndroid Build Coastguard Worker                               num_entries,
8967*795d594fSAndroid Build Coastguard Worker                               switch_instr->GetBlock(),
8968*795d594fSAndroid Build Coastguard Worker                               switch_instr->GetDefaultBlock());
8969*795d594fSAndroid Build Coastguard Worker }
8970*795d594fSAndroid Build Coastguard Worker 
VisitX86PackedSwitch(HX86PackedSwitch * switch_instr)8971*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
8972*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
8973*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8974*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
8975*795d594fSAndroid Build Coastguard Worker 
8976*795d594fSAndroid Build Coastguard Worker   // Constant area pointer.
8977*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
8978*795d594fSAndroid Build Coastguard Worker 
8979*795d594fSAndroid Build Coastguard Worker   // And the temporary we need.
8980*795d594fSAndroid Build Coastguard Worker   locations->AddTemp(Location::RequiresRegister());
8981*795d594fSAndroid Build Coastguard Worker }
8982*795d594fSAndroid Build Coastguard Worker 
VisitX86PackedSwitch(HX86PackedSwitch * switch_instr)8983*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
8984*795d594fSAndroid Build Coastguard Worker   int32_t lower_bound = switch_instr->GetStartValue();
8985*795d594fSAndroid Build Coastguard Worker   uint32_t num_entries = switch_instr->GetNumEntries();
8986*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = switch_instr->GetLocations();
8987*795d594fSAndroid Build Coastguard Worker   Register value_reg = locations->InAt(0).AsRegister<Register>();
8988*795d594fSAndroid Build Coastguard Worker   HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8989*795d594fSAndroid Build Coastguard Worker 
8990*795d594fSAndroid Build Coastguard Worker   if (num_entries <= kPackedSwitchJumpTableThreshold) {
8991*795d594fSAndroid Build Coastguard Worker     GenPackedSwitchWithCompares(value_reg,
8992*795d594fSAndroid Build Coastguard Worker                                 lower_bound,
8993*795d594fSAndroid Build Coastguard Worker                                 num_entries,
8994*795d594fSAndroid Build Coastguard Worker                                 switch_instr->GetBlock(),
8995*795d594fSAndroid Build Coastguard Worker                                 default_block);
8996*795d594fSAndroid Build Coastguard Worker     return;
8997*795d594fSAndroid Build Coastguard Worker   }
8998*795d594fSAndroid Build Coastguard Worker 
8999*795d594fSAndroid Build Coastguard Worker   // Optimizing has a jump area.
9000*795d594fSAndroid Build Coastguard Worker   Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
9001*795d594fSAndroid Build Coastguard Worker   Register constant_area = locations->InAt(1).AsRegister<Register>();
9002*795d594fSAndroid Build Coastguard Worker 
9003*795d594fSAndroid Build Coastguard Worker   // Remove the bias, if needed.
9004*795d594fSAndroid Build Coastguard Worker   if (lower_bound != 0) {
9005*795d594fSAndroid Build Coastguard Worker     __ leal(temp_reg, Address(value_reg, -lower_bound));
9006*795d594fSAndroid Build Coastguard Worker     value_reg = temp_reg;
9007*795d594fSAndroid Build Coastguard Worker   }
9008*795d594fSAndroid Build Coastguard Worker 
9009*795d594fSAndroid Build Coastguard Worker   // Is the value in range?
9010*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(num_entries, 1u);
9011*795d594fSAndroid Build Coastguard Worker   __ cmpl(value_reg, Immediate(num_entries - 1));
9012*795d594fSAndroid Build Coastguard Worker   __ j(kAbove, codegen_->GetLabelOf(default_block));
9013*795d594fSAndroid Build Coastguard Worker 
9014*795d594fSAndroid Build Coastguard Worker   // We are in the range of the table.
9015*795d594fSAndroid Build Coastguard Worker   // Load (target-constant_area) from the jump table, indexing by the value.
9016*795d594fSAndroid Build Coastguard Worker   __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
9017*795d594fSAndroid Build Coastguard Worker 
9018*795d594fSAndroid Build Coastguard Worker   // Compute the actual target address by adding in constant_area.
9019*795d594fSAndroid Build Coastguard Worker   __ addl(temp_reg, constant_area);
9020*795d594fSAndroid Build Coastguard Worker 
9021*795d594fSAndroid Build Coastguard Worker   // And jump.
9022*795d594fSAndroid Build Coastguard Worker   __ jmp(temp_reg);
9023*795d594fSAndroid Build Coastguard Worker }
9024*795d594fSAndroid Build Coastguard Worker 
VisitX86ComputeBaseMethodAddress(HX86ComputeBaseMethodAddress * insn)9025*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
9026*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* insn) {
9027*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
9028*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
9029*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
9030*795d594fSAndroid Build Coastguard Worker }
9031*795d594fSAndroid Build Coastguard Worker 
VisitX86ComputeBaseMethodAddress(HX86ComputeBaseMethodAddress * insn)9032*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
9033*795d594fSAndroid Build Coastguard Worker     HX86ComputeBaseMethodAddress* insn) {
9034*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = insn->GetLocations();
9035*795d594fSAndroid Build Coastguard Worker   Register reg = locations->Out().AsRegister<Register>();
9036*795d594fSAndroid Build Coastguard Worker 
9037*795d594fSAndroid Build Coastguard Worker   // Generate call to next instruction.
9038*795d594fSAndroid Build Coastguard Worker   Label next_instruction;
9039*795d594fSAndroid Build Coastguard Worker   __ call(&next_instruction);
9040*795d594fSAndroid Build Coastguard Worker   __ Bind(&next_instruction);
9041*795d594fSAndroid Build Coastguard Worker 
9042*795d594fSAndroid Build Coastguard Worker   // Remember this offset for later use with constant area.
9043*795d594fSAndroid Build Coastguard Worker   codegen_->AddMethodAddressOffset(insn, GetAssembler()->CodeSize());
9044*795d594fSAndroid Build Coastguard Worker 
9045*795d594fSAndroid Build Coastguard Worker   // Grab the return address off the stack.
9046*795d594fSAndroid Build Coastguard Worker   __ popl(reg);
9047*795d594fSAndroid Build Coastguard Worker }
9048*795d594fSAndroid Build Coastguard Worker 
VisitX86LoadFromConstantTable(HX86LoadFromConstantTable * insn)9049*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitX86LoadFromConstantTable(
9050*795d594fSAndroid Build Coastguard Worker     HX86LoadFromConstantTable* insn) {
9051*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
9052*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
9053*795d594fSAndroid Build Coastguard Worker 
9054*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
9055*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
9056*795d594fSAndroid Build Coastguard Worker 
9057*795d594fSAndroid Build Coastguard Worker   // If we don't need to be materialized, we only need the inputs to be set.
9058*795d594fSAndroid Build Coastguard Worker   if (insn->IsEmittedAtUseSite()) {
9059*795d594fSAndroid Build Coastguard Worker     return;
9060*795d594fSAndroid Build Coastguard Worker   }
9061*795d594fSAndroid Build Coastguard Worker 
9062*795d594fSAndroid Build Coastguard Worker   switch (insn->GetType()) {
9063*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
9064*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
9065*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresFpuRegister());
9066*795d594fSAndroid Build Coastguard Worker       break;
9067*795d594fSAndroid Build Coastguard Worker 
9068*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
9069*795d594fSAndroid Build Coastguard Worker       locations->SetOut(Location::RequiresRegister());
9070*795d594fSAndroid Build Coastguard Worker       break;
9071*795d594fSAndroid Build Coastguard Worker 
9072*795d594fSAndroid Build Coastguard Worker     default:
9073*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
9074*795d594fSAndroid Build Coastguard Worker   }
9075*795d594fSAndroid Build Coastguard Worker }
9076*795d594fSAndroid Build Coastguard Worker 
VisitX86LoadFromConstantTable(HX86LoadFromConstantTable * insn)9077*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
9078*795d594fSAndroid Build Coastguard Worker   if (insn->IsEmittedAtUseSite()) {
9079*795d594fSAndroid Build Coastguard Worker     return;
9080*795d594fSAndroid Build Coastguard Worker   }
9081*795d594fSAndroid Build Coastguard Worker 
9082*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = insn->GetLocations();
9083*795d594fSAndroid Build Coastguard Worker   Location out = locations->Out();
9084*795d594fSAndroid Build Coastguard Worker   Register const_area = locations->InAt(0).AsRegister<Register>();
9085*795d594fSAndroid Build Coastguard Worker   HConstant *value = insn->GetConstant();
9086*795d594fSAndroid Build Coastguard Worker 
9087*795d594fSAndroid Build Coastguard Worker   switch (insn->GetType()) {
9088*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat32:
9089*795d594fSAndroid Build Coastguard Worker       __ movss(out.AsFpuRegister<XmmRegister>(),
9090*795d594fSAndroid Build Coastguard Worker                codegen_->LiteralFloatAddress(
9091*795d594fSAndroid Build Coastguard Worker                    value->AsFloatConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
9092*795d594fSAndroid Build Coastguard Worker       break;
9093*795d594fSAndroid Build Coastguard Worker 
9094*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kFloat64:
9095*795d594fSAndroid Build Coastguard Worker       __ movsd(out.AsFpuRegister<XmmRegister>(),
9096*795d594fSAndroid Build Coastguard Worker                codegen_->LiteralDoubleAddress(
9097*795d594fSAndroid Build Coastguard Worker                    value->AsDoubleConstant()->GetValue(),
9098*795d594fSAndroid Build Coastguard Worker                    insn->GetBaseMethodAddress(),
9099*795d594fSAndroid Build Coastguard Worker                    const_area));
9100*795d594fSAndroid Build Coastguard Worker       break;
9101*795d594fSAndroid Build Coastguard Worker 
9102*795d594fSAndroid Build Coastguard Worker     case DataType::Type::kInt32:
9103*795d594fSAndroid Build Coastguard Worker       __ movl(out.AsRegister<Register>(),
9104*795d594fSAndroid Build Coastguard Worker               codegen_->LiteralInt32Address(
9105*795d594fSAndroid Build Coastguard Worker                   value->AsIntConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
9106*795d594fSAndroid Build Coastguard Worker       break;
9107*795d594fSAndroid Build Coastguard Worker 
9108*795d594fSAndroid Build Coastguard Worker     default:
9109*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
9110*795d594fSAndroid Build Coastguard Worker   }
9111*795d594fSAndroid Build Coastguard Worker }
9112*795d594fSAndroid Build Coastguard Worker 
9113*795d594fSAndroid Build Coastguard Worker /**
9114*795d594fSAndroid Build Coastguard Worker  * Class to handle late fixup of offsets into constant area.
9115*795d594fSAndroid Build Coastguard Worker  */
9116*795d594fSAndroid Build Coastguard Worker class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
9117*795d594fSAndroid Build Coastguard Worker  public:
RIPFixup(CodeGeneratorX86 & codegen,HX86ComputeBaseMethodAddress * base_method_address,size_t offset)9118*795d594fSAndroid Build Coastguard Worker   RIPFixup(CodeGeneratorX86& codegen,
9119*795d594fSAndroid Build Coastguard Worker            HX86ComputeBaseMethodAddress* base_method_address,
9120*795d594fSAndroid Build Coastguard Worker            size_t offset)
9121*795d594fSAndroid Build Coastguard Worker       : codegen_(&codegen),
9122*795d594fSAndroid Build Coastguard Worker         base_method_address_(base_method_address),
9123*795d594fSAndroid Build Coastguard Worker         offset_into_constant_area_(offset) {}
9124*795d594fSAndroid Build Coastguard Worker 
9125*795d594fSAndroid Build Coastguard Worker  protected:
SetOffset(size_t offset)9126*795d594fSAndroid Build Coastguard Worker   void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
9127*795d594fSAndroid Build Coastguard Worker 
9128*795d594fSAndroid Build Coastguard Worker   CodeGeneratorX86* codegen_;
9129*795d594fSAndroid Build Coastguard Worker   HX86ComputeBaseMethodAddress* base_method_address_;
9130*795d594fSAndroid Build Coastguard Worker 
9131*795d594fSAndroid Build Coastguard Worker  private:
Process(const MemoryRegion & region,int pos)9132*795d594fSAndroid Build Coastguard Worker   void Process(const MemoryRegion& region, int pos) override {
9133*795d594fSAndroid Build Coastguard Worker     // Patch the correct offset for the instruction.  The place to patch is the
9134*795d594fSAndroid Build Coastguard Worker     // last 4 bytes of the instruction.
9135*795d594fSAndroid Build Coastguard Worker     // The value to patch is the distance from the offset in the constant area
9136*795d594fSAndroid Build Coastguard Worker     // from the address computed by the HX86ComputeBaseMethodAddress instruction.
9137*795d594fSAndroid Build Coastguard Worker     int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
9138*795d594fSAndroid Build Coastguard Worker     int32_t relative_position =
9139*795d594fSAndroid Build Coastguard Worker         constant_offset - codegen_->GetMethodAddressOffset(base_method_address_);
9140*795d594fSAndroid Build Coastguard Worker 
9141*795d594fSAndroid Build Coastguard Worker     // Patch in the right value.
9142*795d594fSAndroid Build Coastguard Worker     region.StoreUnaligned<int32_t>(pos - 4, relative_position);
9143*795d594fSAndroid Build Coastguard Worker   }
9144*795d594fSAndroid Build Coastguard Worker 
9145*795d594fSAndroid Build Coastguard Worker   // Location in constant area that the fixup refers to.
9146*795d594fSAndroid Build Coastguard Worker   int32_t offset_into_constant_area_;
9147*795d594fSAndroid Build Coastguard Worker };
9148*795d594fSAndroid Build Coastguard Worker 
9149*795d594fSAndroid Build Coastguard Worker /**
9150*795d594fSAndroid Build Coastguard Worker  * Class to handle late fixup of offsets to a jump table that will be created in the
9151*795d594fSAndroid Build Coastguard Worker  * constant area.
9152*795d594fSAndroid Build Coastguard Worker  */
9153*795d594fSAndroid Build Coastguard Worker class JumpTableRIPFixup : public RIPFixup {
9154*795d594fSAndroid Build Coastguard Worker  public:
JumpTableRIPFixup(CodeGeneratorX86 & codegen,HX86PackedSwitch * switch_instr)9155*795d594fSAndroid Build Coastguard Worker   JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
9156*795d594fSAndroid Build Coastguard Worker       : RIPFixup(codegen, switch_instr->GetBaseMethodAddress(), static_cast<size_t>(-1)),
9157*795d594fSAndroid Build Coastguard Worker         switch_instr_(switch_instr) {}
9158*795d594fSAndroid Build Coastguard Worker 
CreateJumpTable()9159*795d594fSAndroid Build Coastguard Worker   void CreateJumpTable() {
9160*795d594fSAndroid Build Coastguard Worker     X86Assembler* assembler = codegen_->GetAssembler();
9161*795d594fSAndroid Build Coastguard Worker 
9162*795d594fSAndroid Build Coastguard Worker     // Ensure that the reference to the jump table has the correct offset.
9163*795d594fSAndroid Build Coastguard Worker     const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
9164*795d594fSAndroid Build Coastguard Worker     SetOffset(offset_in_constant_table);
9165*795d594fSAndroid Build Coastguard Worker 
9166*795d594fSAndroid Build Coastguard Worker     // The label values in the jump table are computed relative to the
9167*795d594fSAndroid Build Coastguard Worker     // instruction addressing the constant area.
9168*795d594fSAndroid Build Coastguard Worker     const int32_t relative_offset = codegen_->GetMethodAddressOffset(base_method_address_);
9169*795d594fSAndroid Build Coastguard Worker 
9170*795d594fSAndroid Build Coastguard Worker     // Populate the jump table with the correct values for the jump table.
9171*795d594fSAndroid Build Coastguard Worker     int32_t num_entries = switch_instr_->GetNumEntries();
9172*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = switch_instr_->GetBlock();
9173*795d594fSAndroid Build Coastguard Worker     const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
9174*795d594fSAndroid Build Coastguard Worker     // The value that we want is the target offset - the position of the table.
9175*795d594fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < num_entries; i++) {
9176*795d594fSAndroid Build Coastguard Worker       HBasicBlock* b = successors[i];
9177*795d594fSAndroid Build Coastguard Worker       Label* l = codegen_->GetLabelOf(b);
9178*795d594fSAndroid Build Coastguard Worker       DCHECK(l->IsBound());
9179*795d594fSAndroid Build Coastguard Worker       int32_t offset_to_block = l->Position() - relative_offset;
9180*795d594fSAndroid Build Coastguard Worker       assembler->AppendInt32(offset_to_block);
9181*795d594fSAndroid Build Coastguard Worker     }
9182*795d594fSAndroid Build Coastguard Worker   }
9183*795d594fSAndroid Build Coastguard Worker 
9184*795d594fSAndroid Build Coastguard Worker  private:
9185*795d594fSAndroid Build Coastguard Worker   const HX86PackedSwitch* switch_instr_;
9186*795d594fSAndroid Build Coastguard Worker };
9187*795d594fSAndroid Build Coastguard Worker 
Finalize()9188*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Finalize() {
9189*795d594fSAndroid Build Coastguard Worker   // Generate the constant area if needed.
9190*795d594fSAndroid Build Coastguard Worker   X86Assembler* assembler = GetAssembler();
9191*795d594fSAndroid Build Coastguard Worker 
9192*795d594fSAndroid Build Coastguard Worker   if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
9193*795d594fSAndroid Build Coastguard Worker     // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
9194*795d594fSAndroid Build Coastguard Worker     // byte values.
9195*795d594fSAndroid Build Coastguard Worker     assembler->Align(4, 0);
9196*795d594fSAndroid Build Coastguard Worker     constant_area_start_ = assembler->CodeSize();
9197*795d594fSAndroid Build Coastguard Worker 
9198*795d594fSAndroid Build Coastguard Worker     // Populate any jump tables.
9199*795d594fSAndroid Build Coastguard Worker     for (JumpTableRIPFixup* jump_table : fixups_to_jump_tables_) {
9200*795d594fSAndroid Build Coastguard Worker       jump_table->CreateJumpTable();
9201*795d594fSAndroid Build Coastguard Worker     }
9202*795d594fSAndroid Build Coastguard Worker 
9203*795d594fSAndroid Build Coastguard Worker     // And now add the constant area to the generated code.
9204*795d594fSAndroid Build Coastguard Worker     assembler->AddConstantArea();
9205*795d594fSAndroid Build Coastguard Worker   }
9206*795d594fSAndroid Build Coastguard Worker 
9207*795d594fSAndroid Build Coastguard Worker   // And finish up.
9208*795d594fSAndroid Build Coastguard Worker   CodeGenerator::Finalize();
9209*795d594fSAndroid Build Coastguard Worker }
9210*795d594fSAndroid Build Coastguard Worker 
LiteralDoubleAddress(double v,HX86ComputeBaseMethodAddress * method_base,Register reg)9211*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::LiteralDoubleAddress(double v,
9212*795d594fSAndroid Build Coastguard Worker                                                HX86ComputeBaseMethodAddress* method_base,
9213*795d594fSAndroid Build Coastguard Worker                                                Register reg) {
9214*795d594fSAndroid Build Coastguard Worker   AssemblerFixup* fixup =
9215*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddDouble(v));
9216*795d594fSAndroid Build Coastguard Worker   return Address(reg, kPlaceholder32BitOffset, fixup);
9217*795d594fSAndroid Build Coastguard Worker }
9218*795d594fSAndroid Build Coastguard Worker 
LiteralFloatAddress(float v,HX86ComputeBaseMethodAddress * method_base,Register reg)9219*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::LiteralFloatAddress(float v,
9220*795d594fSAndroid Build Coastguard Worker                                               HX86ComputeBaseMethodAddress* method_base,
9221*795d594fSAndroid Build Coastguard Worker                                               Register reg) {
9222*795d594fSAndroid Build Coastguard Worker   AssemblerFixup* fixup =
9223*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddFloat(v));
9224*795d594fSAndroid Build Coastguard Worker   return Address(reg, kPlaceholder32BitOffset, fixup);
9225*795d594fSAndroid Build Coastguard Worker }
9226*795d594fSAndroid Build Coastguard Worker 
LiteralInt32Address(int32_t v,HX86ComputeBaseMethodAddress * method_base,Register reg)9227*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::LiteralInt32Address(int32_t v,
9228*795d594fSAndroid Build Coastguard Worker                                               HX86ComputeBaseMethodAddress* method_base,
9229*795d594fSAndroid Build Coastguard Worker                                               Register reg) {
9230*795d594fSAndroid Build Coastguard Worker   AssemblerFixup* fixup =
9231*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddInt32(v));
9232*795d594fSAndroid Build Coastguard Worker   return Address(reg, kPlaceholder32BitOffset, fixup);
9233*795d594fSAndroid Build Coastguard Worker }
9234*795d594fSAndroid Build Coastguard Worker 
LiteralInt64Address(int64_t v,HX86ComputeBaseMethodAddress * method_base,Register reg)9235*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::LiteralInt64Address(int64_t v,
9236*795d594fSAndroid Build Coastguard Worker                                               HX86ComputeBaseMethodAddress* method_base,
9237*795d594fSAndroid Build Coastguard Worker                                               Register reg) {
9238*795d594fSAndroid Build Coastguard Worker   AssemblerFixup* fixup =
9239*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddInt64(v));
9240*795d594fSAndroid Build Coastguard Worker   return Address(reg, kPlaceholder32BitOffset, fixup);
9241*795d594fSAndroid Build Coastguard Worker }
9242*795d594fSAndroid Build Coastguard Worker 
Load32BitValue(Register dest,int32_t value)9243*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Load32BitValue(Register dest, int32_t value) {
9244*795d594fSAndroid Build Coastguard Worker   if (value == 0) {
9245*795d594fSAndroid Build Coastguard Worker     __ xorl(dest, dest);
9246*795d594fSAndroid Build Coastguard Worker   } else {
9247*795d594fSAndroid Build Coastguard Worker     __ movl(dest, Immediate(value));
9248*795d594fSAndroid Build Coastguard Worker   }
9249*795d594fSAndroid Build Coastguard Worker }
9250*795d594fSAndroid Build Coastguard Worker 
Compare32BitValue(Register dest,int32_t value)9251*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::Compare32BitValue(Register dest, int32_t value) {
9252*795d594fSAndroid Build Coastguard Worker   if (value == 0) {
9253*795d594fSAndroid Build Coastguard Worker     __ testl(dest, dest);
9254*795d594fSAndroid Build Coastguard Worker   } else {
9255*795d594fSAndroid Build Coastguard Worker     __ cmpl(dest, Immediate(value));
9256*795d594fSAndroid Build Coastguard Worker   }
9257*795d594fSAndroid Build Coastguard Worker }
9258*795d594fSAndroid Build Coastguard Worker 
GenerateIntCompare(Location lhs,Location rhs)9259*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
9260*795d594fSAndroid Build Coastguard Worker   Register lhs_reg = lhs.AsRegister<Register>();
9261*795d594fSAndroid Build Coastguard Worker   GenerateIntCompare(lhs_reg, rhs);
9262*795d594fSAndroid Build Coastguard Worker }
9263*795d594fSAndroid Build Coastguard Worker 
GenerateIntCompare(Register lhs,Location rhs)9264*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::GenerateIntCompare(Register lhs, Location rhs) {
9265*795d594fSAndroid Build Coastguard Worker   if (rhs.IsConstant()) {
9266*795d594fSAndroid Build Coastguard Worker     int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
9267*795d594fSAndroid Build Coastguard Worker     Compare32BitValue(lhs, value);
9268*795d594fSAndroid Build Coastguard Worker   } else if (rhs.IsStackSlot()) {
9269*795d594fSAndroid Build Coastguard Worker     __ cmpl(lhs, Address(ESP, rhs.GetStackIndex()));
9270*795d594fSAndroid Build Coastguard Worker   } else {
9271*795d594fSAndroid Build Coastguard Worker     __ cmpl(lhs, rhs.AsRegister<Register>());
9272*795d594fSAndroid Build Coastguard Worker   }
9273*795d594fSAndroid Build Coastguard Worker }
9274*795d594fSAndroid Build Coastguard Worker 
ArrayAddress(Register obj,Location index,ScaleFactor scale,uint32_t data_offset)9275*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::ArrayAddress(Register obj,
9276*795d594fSAndroid Build Coastguard Worker                                        Location index,
9277*795d594fSAndroid Build Coastguard Worker                                        ScaleFactor scale,
9278*795d594fSAndroid Build Coastguard Worker                                        uint32_t data_offset) {
9279*795d594fSAndroid Build Coastguard Worker   return index.IsConstant()
9280*795d594fSAndroid Build Coastguard Worker       ? Address(obj, (index.GetConstant()->AsIntConstant()->GetValue() << scale) + data_offset)
9281*795d594fSAndroid Build Coastguard Worker       : Address(obj, index.AsRegister<Register>(), scale, data_offset);
9282*795d594fSAndroid Build Coastguard Worker }
9283*795d594fSAndroid Build Coastguard Worker 
LiteralCaseTable(HX86PackedSwitch * switch_instr,Register reg,Register value)9284*795d594fSAndroid Build Coastguard Worker Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
9285*795d594fSAndroid Build Coastguard Worker                                            Register reg,
9286*795d594fSAndroid Build Coastguard Worker                                            Register value) {
9287*795d594fSAndroid Build Coastguard Worker   // Create a fixup to be used to create and address the jump table.
9288*795d594fSAndroid Build Coastguard Worker   JumpTableRIPFixup* table_fixup =
9289*795d594fSAndroid Build Coastguard Worker       new (GetGraph()->GetAllocator()) JumpTableRIPFixup(*this, switch_instr);
9290*795d594fSAndroid Build Coastguard Worker 
9291*795d594fSAndroid Build Coastguard Worker   // We have to populate the jump tables.
9292*795d594fSAndroid Build Coastguard Worker   fixups_to_jump_tables_.push_back(table_fixup);
9293*795d594fSAndroid Build Coastguard Worker 
9294*795d594fSAndroid Build Coastguard Worker   // We want a scaled address, as we are extracting the correct offset from the table.
9295*795d594fSAndroid Build Coastguard Worker   return Address(reg, value, TIMES_4, kPlaceholder32BitOffset, table_fixup);
9296*795d594fSAndroid Build Coastguard Worker }
9297*795d594fSAndroid Build Coastguard Worker 
9298*795d594fSAndroid Build Coastguard Worker // TODO: target as memory.
MoveFromReturnRegister(Location target,DataType::Type type)9299*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::MoveFromReturnRegister(Location target, DataType::Type type) {
9300*795d594fSAndroid Build Coastguard Worker   if (!target.IsValid()) {
9301*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(type, DataType::Type::kVoid);
9302*795d594fSAndroid Build Coastguard Worker     return;
9303*795d594fSAndroid Build Coastguard Worker   }
9304*795d594fSAndroid Build Coastguard Worker 
9305*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(type, DataType::Type::kVoid);
9306*795d594fSAndroid Build Coastguard Worker 
9307*795d594fSAndroid Build Coastguard Worker   Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
9308*795d594fSAndroid Build Coastguard Worker   if (target.Equals(return_loc)) {
9309*795d594fSAndroid Build Coastguard Worker     return;
9310*795d594fSAndroid Build Coastguard Worker   }
9311*795d594fSAndroid Build Coastguard Worker 
9312*795d594fSAndroid Build Coastguard Worker   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
9313*795d594fSAndroid Build Coastguard Worker   //       with the else branch.
9314*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kInt64) {
9315*795d594fSAndroid Build Coastguard Worker     HParallelMove parallel_move(GetGraph()->GetAllocator());
9316*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), DataType::Type::kInt32, nullptr);
9317*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), DataType::Type::kInt32, nullptr);
9318*795d594fSAndroid Build Coastguard Worker     GetMoveResolver()->EmitNativeCode(&parallel_move);
9319*795d594fSAndroid Build Coastguard Worker   } else {
9320*795d594fSAndroid Build Coastguard Worker     // Let the parallel move resolver take care of all of this.
9321*795d594fSAndroid Build Coastguard Worker     HParallelMove parallel_move(GetGraph()->GetAllocator());
9322*795d594fSAndroid Build Coastguard Worker     parallel_move.AddMove(return_loc, target, type, nullptr);
9323*795d594fSAndroid Build Coastguard Worker     GetMoveResolver()->EmitNativeCode(&parallel_move);
9324*795d594fSAndroid Build Coastguard Worker   }
9325*795d594fSAndroid Build Coastguard Worker }
9326*795d594fSAndroid Build Coastguard Worker 
PatchJitRootUse(uint8_t * code,const uint8_t * roots_data,const PatchInfo<Label> & info,uint64_t index_in_table) const9327*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::PatchJitRootUse(uint8_t* code,
9328*795d594fSAndroid Build Coastguard Worker                                        const uint8_t* roots_data,
9329*795d594fSAndroid Build Coastguard Worker                                        const PatchInfo<Label>& info,
9330*795d594fSAndroid Build Coastguard Worker                                        uint64_t index_in_table) const {
9331*795d594fSAndroid Build Coastguard Worker   uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
9332*795d594fSAndroid Build Coastguard Worker   uintptr_t address =
9333*795d594fSAndroid Build Coastguard Worker       reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
9334*795d594fSAndroid Build Coastguard Worker   using unaligned_uint32_t __attribute__((__aligned__(1))) = uint32_t;
9335*795d594fSAndroid Build Coastguard Worker   reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
9336*795d594fSAndroid Build Coastguard Worker       dchecked_integral_cast<uint32_t>(address);
9337*795d594fSAndroid Build Coastguard Worker }
9338*795d594fSAndroid Build Coastguard Worker 
EmitJitRootPatches(uint8_t * code,const uint8_t * roots_data)9339*795d594fSAndroid Build Coastguard Worker void CodeGeneratorX86::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
9340*795d594fSAndroid Build Coastguard Worker   for (const PatchInfo<Label>& info : jit_string_patches_) {
9341*795d594fSAndroid Build Coastguard Worker     StringReference string_reference(info.target_dex_file, dex::StringIndex(info.offset_or_index));
9342*795d594fSAndroid Build Coastguard Worker     uint64_t index_in_table = GetJitStringRootIndex(string_reference);
9343*795d594fSAndroid Build Coastguard Worker     PatchJitRootUse(code, roots_data, info, index_in_table);
9344*795d594fSAndroid Build Coastguard Worker   }
9345*795d594fSAndroid Build Coastguard Worker 
9346*795d594fSAndroid Build Coastguard Worker   for (const PatchInfo<Label>& info : jit_class_patches_) {
9347*795d594fSAndroid Build Coastguard Worker     TypeReference type_reference(info.target_dex_file, dex::TypeIndex(info.offset_or_index));
9348*795d594fSAndroid Build Coastguard Worker     uint64_t index_in_table = GetJitClassRootIndex(type_reference);
9349*795d594fSAndroid Build Coastguard Worker     PatchJitRootUse(code, roots_data, info, index_in_table);
9350*795d594fSAndroid Build Coastguard Worker   }
9351*795d594fSAndroid Build Coastguard Worker }
9352*795d594fSAndroid Build Coastguard Worker 
VisitIntermediateAddress(HIntermediateAddress * instruction)9353*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitIntermediateAddress(
9354*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HIntermediateAddress* instruction) {
9355*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
9356*795d594fSAndroid Build Coastguard Worker }
9357*795d594fSAndroid Build Coastguard Worker 
VisitIntermediateAddress(HIntermediateAddress * instruction)9358*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitIntermediateAddress(
9359*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HIntermediateAddress* instruction) {
9360*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
9361*795d594fSAndroid Build Coastguard Worker }
9362*795d594fSAndroid Build Coastguard Worker 
CpuHasAvxFeatureFlag()9363*795d594fSAndroid Build Coastguard Worker bool LocationsBuilderX86::CpuHasAvxFeatureFlag() {
9364*795d594fSAndroid Build Coastguard Worker   return codegen_->GetInstructionSetFeatures().HasAVX();
9365*795d594fSAndroid Build Coastguard Worker }
CpuHasAvx2FeatureFlag()9366*795d594fSAndroid Build Coastguard Worker bool LocationsBuilderX86::CpuHasAvx2FeatureFlag() {
9367*795d594fSAndroid Build Coastguard Worker   return codegen_->GetInstructionSetFeatures().HasAVX2();
9368*795d594fSAndroid Build Coastguard Worker }
CpuHasAvxFeatureFlag()9369*795d594fSAndroid Build Coastguard Worker bool InstructionCodeGeneratorX86::CpuHasAvxFeatureFlag() {
9370*795d594fSAndroid Build Coastguard Worker   return codegen_->GetInstructionSetFeatures().HasAVX();
9371*795d594fSAndroid Build Coastguard Worker }
CpuHasAvx2FeatureFlag()9372*795d594fSAndroid Build Coastguard Worker bool InstructionCodeGeneratorX86::CpuHasAvx2FeatureFlag() {
9373*795d594fSAndroid Build Coastguard Worker   return codegen_->GetInstructionSetFeatures().HasAVX2();
9374*795d594fSAndroid Build Coastguard Worker }
9375*795d594fSAndroid Build Coastguard Worker 
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instruction)9376*795d594fSAndroid Build Coastguard Worker void LocationsBuilderX86::VisitBitwiseNegatedRight(
9377*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HBitwiseNegatedRight* instruction) {
9378*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unimplemented";
9379*795d594fSAndroid Build Coastguard Worker }
9380*795d594fSAndroid Build Coastguard Worker 
VisitBitwiseNegatedRight(HBitwiseNegatedRight * instruction)9381*795d594fSAndroid Build Coastguard Worker void InstructionCodeGeneratorX86::VisitBitwiseNegatedRight(
9382*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] HBitwiseNegatedRight* instruction) {
9383*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unimplemented";
9384*795d594fSAndroid Build Coastguard Worker }
9385*795d594fSAndroid Build Coastguard Worker 
9386*795d594fSAndroid Build Coastguard Worker #undef __
9387*795d594fSAndroid Build Coastguard Worker 
9388*795d594fSAndroid Build Coastguard Worker }  // namespace x86
9389*795d594fSAndroid Build Coastguard Worker }  // namespace art
9390