1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "code_generator_x86.h"
18 
19 #include "art_method.h"
20 #include "code_generator_utils.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "entrypoints/quick/quick_entrypoints_enum.h"
23 #include "gc/accounting/card_table.h"
24 #include "intrinsics.h"
25 #include "intrinsics_x86.h"
26 #include "mirror/array-inl.h"
27 #include "mirror/class-inl.h"
28 #include "thread.h"
29 #include "utils/assembler.h"
30 #include "utils/stack_checks.h"
31 #include "utils/x86/assembler_x86.h"
32 #include "utils/x86/managed_register_x86.h"
33 
34 namespace art {
35 
36 namespace x86 {
37 
38 static constexpr int kCurrentMethodStackOffset = 0;
39 
40 static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
41 
42 static constexpr int kC2ConditionMask = 0x400;
43 
44 static constexpr int kFakeReturnRegister = Register(8);
45 
46 #define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
47 
48 class NullCheckSlowPathX86 : public SlowPathCodeX86 {
49  public:
NullCheckSlowPathX86(HNullCheck * instruction)50   explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
51 
EmitNativeCode(CodeGenerator * codegen)52   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
53     __ Bind(GetEntryLabel());
54     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
55     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
56   }
57 
58  private:
59   HNullCheck* const instruction_;
60   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
61 };
62 
63 class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
64  public:
DivZeroCheckSlowPathX86(HDivZeroCheck * instruction)65   explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
66 
EmitNativeCode(CodeGenerator * codegen)67   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
68     __ Bind(GetEntryLabel());
69     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
70     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
71   }
72 
73  private:
74   HDivZeroCheck* const instruction_;
75   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
76 };
77 
78 class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
79  public:
DivRemMinusOneSlowPathX86(Register reg,bool is_div)80   explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
81 
EmitNativeCode(CodeGenerator * codegen)82   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
83     __ Bind(GetEntryLabel());
84     if (is_div_) {
85       __ negl(reg_);
86     } else {
87       __ movl(reg_, Immediate(0));
88     }
89     __ jmp(GetExitLabel());
90   }
91 
92  private:
93   Register reg_;
94   bool is_div_;
95   DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
96 };
97 
98 class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
99  public:
BoundsCheckSlowPathX86(HBoundsCheck * instruction,Location index_location,Location length_location)100   BoundsCheckSlowPathX86(HBoundsCheck* instruction,
101                          Location index_location,
102                          Location length_location)
103       : instruction_(instruction),
104         index_location_(index_location),
105         length_location_(length_location) {}
106 
EmitNativeCode(CodeGenerator * codegen)107   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
108     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
109     __ Bind(GetEntryLabel());
110     // We're moving two locations to locations that could overlap, so we need a parallel
111     // move resolver.
112     InvokeRuntimeCallingConvention calling_convention;
113     x86_codegen->EmitParallelMoves(
114         index_location_,
115         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
116         Primitive::kPrimInt,
117         length_location_,
118         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
119         Primitive::kPrimInt);
120     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
121     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
122   }
123 
124  private:
125   HBoundsCheck* const instruction_;
126   const Location index_location_;
127   const Location length_location_;
128 
129   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
130 };
131 
132 class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
133  public:
SuspendCheckSlowPathX86(HSuspendCheck * instruction,HBasicBlock * successor)134   SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
135       : instruction_(instruction), successor_(successor) {}
136 
EmitNativeCode(CodeGenerator * codegen)137   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
138     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
139     __ Bind(GetEntryLabel());
140     SaveLiveRegisters(codegen, instruction_->GetLocations());
141     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
142     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
143     RestoreLiveRegisters(codegen, instruction_->GetLocations());
144     if (successor_ == nullptr) {
145       __ jmp(GetReturnLabel());
146     } else {
147       __ jmp(x86_codegen->GetLabelOf(successor_));
148     }
149   }
150 
GetReturnLabel()151   Label* GetReturnLabel() {
152     DCHECK(successor_ == nullptr);
153     return &return_label_;
154   }
155 
GetSuccessor() const156   HBasicBlock* GetSuccessor() const {
157     return successor_;
158   }
159 
160  private:
161   HSuspendCheck* const instruction_;
162   HBasicBlock* const successor_;
163   Label return_label_;
164 
165   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
166 };
167 
168 class LoadStringSlowPathX86 : public SlowPathCodeX86 {
169  public:
LoadStringSlowPathX86(HLoadString * instruction)170   explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
171 
EmitNativeCode(CodeGenerator * codegen)172   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
173     LocationSummary* locations = instruction_->GetLocations();
174     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
175 
176     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
177     __ Bind(GetEntryLabel());
178     SaveLiveRegisters(codegen, locations);
179 
180     InvokeRuntimeCallingConvention calling_convention;
181     __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
182     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
183     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
184     x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
185     RestoreLiveRegisters(codegen, locations);
186 
187     __ jmp(GetExitLabel());
188   }
189 
190  private:
191   HLoadString* const instruction_;
192 
193   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
194 };
195 
196 class LoadClassSlowPathX86 : public SlowPathCodeX86 {
197  public:
LoadClassSlowPathX86(HLoadClass * cls,HInstruction * at,uint32_t dex_pc,bool do_clinit)198   LoadClassSlowPathX86(HLoadClass* cls,
199                        HInstruction* at,
200                        uint32_t dex_pc,
201                        bool do_clinit)
202       : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
203     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
204   }
205 
EmitNativeCode(CodeGenerator * codegen)206   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
207     LocationSummary* locations = at_->GetLocations();
208     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
209     __ Bind(GetEntryLabel());
210     SaveLiveRegisters(codegen, locations);
211 
212     InvokeRuntimeCallingConvention calling_convention;
213     __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
214     __ fs()->call(Address::Absolute(do_clinit_
215         ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
216         : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
217     RecordPcInfo(codegen, at_, dex_pc_);
218 
219     // Move the class to the desired location.
220     Location out = locations->Out();
221     if (out.IsValid()) {
222       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
223       x86_codegen->Move32(out, Location::RegisterLocation(EAX));
224     }
225 
226     RestoreLiveRegisters(codegen, locations);
227     __ jmp(GetExitLabel());
228   }
229 
230  private:
231   // The class this slow path will load.
232   HLoadClass* const cls_;
233 
234   // The instruction where this slow path is happening.
235   // (Might be the load class or an initialization check).
236   HInstruction* const at_;
237 
238   // The dex PC of `at_`.
239   const uint32_t dex_pc_;
240 
241   // Whether to initialize the class.
242   const bool do_clinit_;
243 
244   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
245 };
246 
247 class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
248  public:
TypeCheckSlowPathX86(HInstruction * instruction,Location class_to_check,Location object_class,uint32_t dex_pc)249   TypeCheckSlowPathX86(HInstruction* instruction,
250                        Location class_to_check,
251                        Location object_class,
252                        uint32_t dex_pc)
253       : instruction_(instruction),
254         class_to_check_(class_to_check),
255         object_class_(object_class),
256         dex_pc_(dex_pc) {}
257 
EmitNativeCode(CodeGenerator * codegen)258   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
259     LocationSummary* locations = instruction_->GetLocations();
260     DCHECK(instruction_->IsCheckCast()
261            || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
262 
263     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
264     __ Bind(GetEntryLabel());
265     SaveLiveRegisters(codegen, locations);
266 
267     // We're moving two locations to locations that could overlap, so we need a parallel
268     // move resolver.
269     InvokeRuntimeCallingConvention calling_convention;
270     x86_codegen->EmitParallelMoves(
271         class_to_check_,
272         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
273         Primitive::kPrimNot,
274         object_class_,
275         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
276         Primitive::kPrimNot);
277 
278     if (instruction_->IsInstanceOf()) {
279       __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
280                                                               pInstanceofNonTrivial)));
281     } else {
282       DCHECK(instruction_->IsCheckCast());
283       __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
284     }
285 
286     RecordPcInfo(codegen, instruction_, dex_pc_);
287     if (instruction_->IsInstanceOf()) {
288       x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
289     }
290     RestoreLiveRegisters(codegen, locations);
291 
292     __ jmp(GetExitLabel());
293   }
294 
295  private:
296   HInstruction* const instruction_;
297   const Location class_to_check_;
298   const Location object_class_;
299   const uint32_t dex_pc_;
300 
301   DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
302 };
303 
304 class DeoptimizationSlowPathX86 : public SlowPathCodeX86 {
305  public:
DeoptimizationSlowPathX86(HInstruction * instruction)306   explicit DeoptimizationSlowPathX86(HInstruction* instruction)
307     : instruction_(instruction) {}
308 
EmitNativeCode(CodeGenerator * codegen)309   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
310     __ Bind(GetEntryLabel());
311     SaveLiveRegisters(codegen, instruction_->GetLocations());
312     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeoptimize)));
313     // No need to restore live registers.
314     DCHECK(instruction_->IsDeoptimize());
315     HDeoptimize* deoptimize = instruction_->AsDeoptimize();
316     uint32_t dex_pc = deoptimize->GetDexPc();
317     codegen->RecordPcInfo(instruction_, dex_pc, this);
318   }
319 
320  private:
321   HInstruction* const instruction_;
322   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
323 };
324 
325 #undef __
326 #define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
327 
X86Condition(IfCondition cond)328 inline Condition X86Condition(IfCondition cond) {
329   switch (cond) {
330     case kCondEQ: return kEqual;
331     case kCondNE: return kNotEqual;
332     case kCondLT: return kLess;
333     case kCondLE: return kLessEqual;
334     case kCondGT: return kGreater;
335     case kCondGE: return kGreaterEqual;
336     default:
337       LOG(FATAL) << "Unknown if condition";
338   }
339   return kEqual;
340 }
341 
DumpCoreRegister(std::ostream & stream,int reg) const342 void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
343   stream << X86ManagedRegister::FromCpuRegister(Register(reg));
344 }
345 
DumpFloatingPointRegister(std::ostream & stream,int reg) const346 void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
347   stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
348 }
349 
SaveCoreRegister(size_t stack_index,uint32_t reg_id)350 size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
351   __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
352   return kX86WordSize;
353 }
354 
RestoreCoreRegister(size_t stack_index,uint32_t reg_id)355 size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
356   __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
357   return kX86WordSize;
358 }
359 
SaveFloatingPointRegister(size_t stack_index,uint32_t reg_id)360 size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
361   __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
362   return GetFloatingPointSpillSlotSize();
363 }
364 
RestoreFloatingPointRegister(size_t stack_index,uint32_t reg_id)365 size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
366   __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
367   return GetFloatingPointSpillSlotSize();
368 }
369 
CodeGeneratorX86(HGraph * graph,const X86InstructionSetFeatures & isa_features,const CompilerOptions & compiler_options)370 CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
371                    const X86InstructionSetFeatures& isa_features,
372                    const CompilerOptions& compiler_options)
373     : CodeGenerator(graph,
374                     kNumberOfCpuRegisters,
375                     kNumberOfXmmRegisters,
376                     kNumberOfRegisterPairs,
377                     ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
378                                         arraysize(kCoreCalleeSaves))
379                         | (1 << kFakeReturnRegister),
380                         0,
381                         compiler_options),
382       block_labels_(graph->GetArena(), 0),
383       location_builder_(graph, this),
384       instruction_visitor_(graph, this),
385       move_resolver_(graph->GetArena(), this),
386       isa_features_(isa_features) {
387   // Use a fake return address register to mimic Quick.
388   AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
389 }
390 
AllocateFreeRegister(Primitive::Type type) const391 Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
392   switch (type) {
393     case Primitive::kPrimLong: {
394       size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
395       X86ManagedRegister pair =
396           X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
397       DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
398       DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
399       blocked_core_registers_[pair.AsRegisterPairLow()] = true;
400       blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
401       UpdateBlockedPairRegisters();
402       return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
403     }
404 
405     case Primitive::kPrimByte:
406     case Primitive::kPrimBoolean:
407     case Primitive::kPrimChar:
408     case Primitive::kPrimShort:
409     case Primitive::kPrimInt:
410     case Primitive::kPrimNot: {
411       Register reg = static_cast<Register>(
412           FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
413       // Block all register pairs that contain `reg`.
414       for (int i = 0; i < kNumberOfRegisterPairs; i++) {
415         X86ManagedRegister current =
416             X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
417         if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
418           blocked_register_pairs_[i] = true;
419         }
420       }
421       return Location::RegisterLocation(reg);
422     }
423 
424     case Primitive::kPrimFloat:
425     case Primitive::kPrimDouble: {
426       return Location::FpuRegisterLocation(
427           FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
428     }
429 
430     case Primitive::kPrimVoid:
431       LOG(FATAL) << "Unreachable type " << type;
432   }
433 
434   return Location();
435 }
436 
SetupBlockedRegisters(bool is_baseline) const437 void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
438   // Don't allocate the dalvik style register pair passing.
439   blocked_register_pairs_[ECX_EDX] = true;
440 
441   // Stack register is always reserved.
442   blocked_core_registers_[ESP] = true;
443 
444   if (is_baseline) {
445     blocked_core_registers_[EBP] = true;
446     blocked_core_registers_[ESI] = true;
447     blocked_core_registers_[EDI] = true;
448   }
449 
450   UpdateBlockedPairRegisters();
451 }
452 
UpdateBlockedPairRegisters() const453 void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
454   for (int i = 0; i < kNumberOfRegisterPairs; i++) {
455     X86ManagedRegister current =
456         X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
457     if (blocked_core_registers_[current.AsRegisterPairLow()]
458         || blocked_core_registers_[current.AsRegisterPairHigh()]) {
459       blocked_register_pairs_[i] = true;
460     }
461   }
462 }
463 
InstructionCodeGeneratorX86(HGraph * graph,CodeGeneratorX86 * codegen)464 InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
465       : HGraphVisitor(graph),
466         assembler_(codegen->GetAssembler()),
467         codegen_(codegen) {}
468 
DWARFReg(Register reg)469 static dwarf::Reg DWARFReg(Register reg) {
470   return dwarf::Reg::X86Core(static_cast<int>(reg));
471 }
472 
GenerateFrameEntry()473 void CodeGeneratorX86::GenerateFrameEntry() {
474   __ cfi().SetCurrentCFAOffset(kX86WordSize);  // return address
475   __ Bind(&frame_entry_label_);
476   bool skip_overflow_check =
477       IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
478   DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
479 
480   if (!skip_overflow_check) {
481     __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
482     RecordPcInfo(nullptr, 0);
483   }
484 
485   if (HasEmptyFrame()) {
486     return;
487   }
488 
489   for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
490     Register reg = kCoreCalleeSaves[i];
491     if (allocated_registers_.ContainsCoreRegister(reg)) {
492       __ pushl(reg);
493       __ cfi().AdjustCFAOffset(kX86WordSize);
494       __ cfi().RelOffset(DWARFReg(reg), 0);
495     }
496   }
497 
498   int adjust = GetFrameSize() - FrameEntrySpillSize();
499   __ subl(ESP, Immediate(adjust));
500   __ cfi().AdjustCFAOffset(adjust);
501   __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
502 }
503 
GenerateFrameExit()504 void CodeGeneratorX86::GenerateFrameExit() {
505   __ cfi().RememberState();
506   if (!HasEmptyFrame()) {
507     int adjust = GetFrameSize() - FrameEntrySpillSize();
508     __ addl(ESP, Immediate(adjust));
509     __ cfi().AdjustCFAOffset(-adjust);
510 
511     for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
512       Register reg = kCoreCalleeSaves[i];
513       if (allocated_registers_.ContainsCoreRegister(reg)) {
514         __ popl(reg);
515         __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
516         __ cfi().Restore(DWARFReg(reg));
517       }
518     }
519   }
520   __ ret();
521   __ cfi().RestoreState();
522   __ cfi().DefCFAOffset(GetFrameSize());
523 }
524 
Bind(HBasicBlock * block)525 void CodeGeneratorX86::Bind(HBasicBlock* block) {
526   __ Bind(GetLabelOf(block));
527 }
528 
LoadCurrentMethod(Register reg)529 void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
530   DCHECK(RequiresCurrentMethod());
531   __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
532 }
533 
GetStackLocation(HLoadLocal * load) const534 Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
535   switch (load->GetType()) {
536     case Primitive::kPrimLong:
537     case Primitive::kPrimDouble:
538       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
539 
540     case Primitive::kPrimInt:
541     case Primitive::kPrimNot:
542     case Primitive::kPrimFloat:
543       return Location::StackSlot(GetStackSlot(load->GetLocal()));
544 
545     case Primitive::kPrimBoolean:
546     case Primitive::kPrimByte:
547     case Primitive::kPrimChar:
548     case Primitive::kPrimShort:
549     case Primitive::kPrimVoid:
550       LOG(FATAL) << "Unexpected type " << load->GetType();
551       UNREACHABLE();
552   }
553 
554   LOG(FATAL) << "Unreachable";
555   UNREACHABLE();
556 }
557 
GetNextLocation(Primitive::Type type)558 Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
559   switch (type) {
560     case Primitive::kPrimBoolean:
561     case Primitive::kPrimByte:
562     case Primitive::kPrimChar:
563     case Primitive::kPrimShort:
564     case Primitive::kPrimInt:
565     case Primitive::kPrimNot: {
566       uint32_t index = gp_index_++;
567       stack_index_++;
568       if (index < calling_convention.GetNumberOfRegisters()) {
569         return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
570       } else {
571         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
572       }
573     }
574 
575     case Primitive::kPrimLong: {
576       uint32_t index = gp_index_;
577       gp_index_ += 2;
578       stack_index_ += 2;
579       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
580         X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
581             calling_convention.GetRegisterPairAt(index));
582         return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
583       } else {
584         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
585       }
586     }
587 
588     case Primitive::kPrimFloat: {
589       uint32_t index = float_index_++;
590       stack_index_++;
591       if (index < calling_convention.GetNumberOfFpuRegisters()) {
592         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
593       } else {
594         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
595       }
596     }
597 
598     case Primitive::kPrimDouble: {
599       uint32_t index = float_index_++;
600       stack_index_ += 2;
601       if (index < calling_convention.GetNumberOfFpuRegisters()) {
602         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
603       } else {
604         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
605       }
606     }
607 
608     case Primitive::kPrimVoid:
609       LOG(FATAL) << "Unexpected parameter type " << type;
610       break;
611   }
612   return Location();
613 }
614 
Move32(Location destination,Location source)615 void CodeGeneratorX86::Move32(Location destination, Location source) {
616   if (source.Equals(destination)) {
617     return;
618   }
619   if (destination.IsRegister()) {
620     if (source.IsRegister()) {
621       __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
622     } else if (source.IsFpuRegister()) {
623       __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
624     } else {
625       DCHECK(source.IsStackSlot());
626       __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
627     }
628   } else if (destination.IsFpuRegister()) {
629     if (source.IsRegister()) {
630       __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
631     } else if (source.IsFpuRegister()) {
632       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
633     } else {
634       DCHECK(source.IsStackSlot());
635       __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
636     }
637   } else {
638     DCHECK(destination.IsStackSlot()) << destination;
639     if (source.IsRegister()) {
640       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
641     } else if (source.IsFpuRegister()) {
642       __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
643     } else if (source.IsConstant()) {
644       HConstant* constant = source.GetConstant();
645       int32_t value = GetInt32ValueOf(constant);
646       __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
647     } else {
648       DCHECK(source.IsStackSlot());
649       __ pushl(Address(ESP, source.GetStackIndex()));
650       __ popl(Address(ESP, destination.GetStackIndex()));
651     }
652   }
653 }
654 
Move64(Location destination,Location source)655 void CodeGeneratorX86::Move64(Location destination, Location source) {
656   if (source.Equals(destination)) {
657     return;
658   }
659   if (destination.IsRegisterPair()) {
660     if (source.IsRegisterPair()) {
661       EmitParallelMoves(
662           Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
663           Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
664           Primitive::kPrimInt,
665           Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
666           Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
667           Primitive::kPrimInt);
668     } else if (source.IsFpuRegister()) {
669       LOG(FATAL) << "Unimplemented";
670     } else {
671       // No conflict possible, so just do the moves.
672       DCHECK(source.IsDoubleStackSlot());
673       __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
674       __ movl(destination.AsRegisterPairHigh<Register>(),
675               Address(ESP, source.GetHighStackIndex(kX86WordSize)));
676     }
677   } else if (destination.IsFpuRegister()) {
678     if (source.IsFpuRegister()) {
679       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
680     } else if (source.IsDoubleStackSlot()) {
681       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
682     } else {
683       LOG(FATAL) << "Unimplemented";
684     }
685   } else {
686     DCHECK(destination.IsDoubleStackSlot()) << destination;
687     if (source.IsRegisterPair()) {
688       // No conflict possible, so just do the moves.
689       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
690       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
691               source.AsRegisterPairHigh<Register>());
692     } else if (source.IsFpuRegister()) {
693       __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
694     } else if (source.IsConstant()) {
695       HConstant* constant = source.GetConstant();
696       int64_t value;
697       if (constant->IsLongConstant()) {
698         value = constant->AsLongConstant()->GetValue();
699       } else {
700         DCHECK(constant->IsDoubleConstant());
701         value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
702       }
703       __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
704       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
705     } else {
706       DCHECK(source.IsDoubleStackSlot()) << source;
707       EmitParallelMoves(
708           Location::StackSlot(source.GetStackIndex()),
709           Location::StackSlot(destination.GetStackIndex()),
710           Primitive::kPrimInt,
711           Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
712           Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
713           Primitive::kPrimInt);
714     }
715   }
716 }
717 
Move(HInstruction * instruction,Location location,HInstruction * move_for)718 void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
719   LocationSummary* locations = instruction->GetLocations();
720   if (locations != nullptr && locations->Out().Equals(location)) {
721     return;
722   }
723 
724   if (locations != nullptr && locations->Out().IsConstant()) {
725     HConstant* const_to_move = locations->Out().GetConstant();
726     if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
727       Immediate imm(GetInt32ValueOf(const_to_move));
728       if (location.IsRegister()) {
729         __ movl(location.AsRegister<Register>(), imm);
730       } else if (location.IsStackSlot()) {
731         __ movl(Address(ESP, location.GetStackIndex()), imm);
732       } else {
733         DCHECK(location.IsConstant());
734         DCHECK_EQ(location.GetConstant(), const_to_move);
735       }
736     } else if (const_to_move->IsLongConstant()) {
737       int64_t value = const_to_move->AsLongConstant()->GetValue();
738       if (location.IsRegisterPair()) {
739         __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
740         __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
741       } else if (location.IsDoubleStackSlot()) {
742         __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
743         __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
744                 Immediate(High32Bits(value)));
745       } else {
746         DCHECK(location.IsConstant());
747         DCHECK_EQ(location.GetConstant(), instruction);
748       }
749     }
750   } else if (instruction->IsTemporary()) {
751     Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
752     if (temp_location.IsStackSlot()) {
753       Move32(location, temp_location);
754     } else {
755       DCHECK(temp_location.IsDoubleStackSlot());
756       Move64(location, temp_location);
757     }
758   } else if (instruction->IsLoadLocal()) {
759     int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
760     switch (instruction->GetType()) {
761       case Primitive::kPrimBoolean:
762       case Primitive::kPrimByte:
763       case Primitive::kPrimChar:
764       case Primitive::kPrimShort:
765       case Primitive::kPrimInt:
766       case Primitive::kPrimNot:
767       case Primitive::kPrimFloat:
768         Move32(location, Location::StackSlot(slot));
769         break;
770 
771       case Primitive::kPrimLong:
772       case Primitive::kPrimDouble:
773         Move64(location, Location::DoubleStackSlot(slot));
774         break;
775 
776       default:
777         LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
778     }
779   } else {
780     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
781     switch (instruction->GetType()) {
782       case Primitive::kPrimBoolean:
783       case Primitive::kPrimByte:
784       case Primitive::kPrimChar:
785       case Primitive::kPrimShort:
786       case Primitive::kPrimInt:
787       case Primitive::kPrimNot:
788       case Primitive::kPrimFloat:
789         Move32(location, locations->Out());
790         break;
791 
792       case Primitive::kPrimLong:
793       case Primitive::kPrimDouble:
794         Move64(location, locations->Out());
795         break;
796 
797       default:
798         LOG(FATAL) << "Unexpected type " << instruction->GetType();
799     }
800   }
801 }
802 
VisitGoto(HGoto * got)803 void LocationsBuilderX86::VisitGoto(HGoto* got) {
804   got->SetLocations(nullptr);
805 }
806 
VisitGoto(HGoto * got)807 void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
808   HBasicBlock* successor = got->GetSuccessor();
809   DCHECK(!successor->IsExitBlock());
810 
811   HBasicBlock* block = got->GetBlock();
812   HInstruction* previous = got->GetPrevious();
813 
814   HLoopInformation* info = block->GetLoopInformation();
815   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
816     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
817     return;
818   }
819 
820   if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
821     GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
822   }
823   if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
824     __ jmp(codegen_->GetLabelOf(successor));
825   }
826 }
827 
VisitExit(HExit * exit)828 void LocationsBuilderX86::VisitExit(HExit* exit) {
829   exit->SetLocations(nullptr);
830 }
831 
VisitExit(HExit * exit)832 void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
833   UNUSED(exit);
834 }
835 
GenerateTestAndBranch(HInstruction * instruction,Label * true_target,Label * false_target,Label * always_true_target)836 void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
837                                                         Label* true_target,
838                                                         Label* false_target,
839                                                         Label* always_true_target) {
840   HInstruction* cond = instruction->InputAt(0);
841   if (cond->IsIntConstant()) {
842     // Constant condition, statically compared against 1.
843     int32_t cond_value = cond->AsIntConstant()->GetValue();
844     if (cond_value == 1) {
845       if (always_true_target != nullptr) {
846         __ jmp(always_true_target);
847       }
848       return;
849     } else {
850       DCHECK_EQ(cond_value, 0);
851     }
852   } else {
853     bool materialized =
854         !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
855     // Moves do not affect the eflags register, so if the condition is
856     // evaluated just before the if, we don't need to evaluate it
857     // again.
858     bool eflags_set = cond->IsCondition()
859         && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
860     if (materialized) {
861       if (!eflags_set) {
862         // Materialized condition, compare against 0.
863         Location lhs = instruction->GetLocations()->InAt(0);
864         if (lhs.IsRegister()) {
865           __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
866         } else {
867           __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
868         }
869         __ j(kNotEqual, true_target);
870       } else {
871         __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
872       }
873     } else {
874       Location lhs = cond->GetLocations()->InAt(0);
875       Location rhs = cond->GetLocations()->InAt(1);
876       // LHS is guaranteed to be in a register (see
877       // LocationsBuilderX86::VisitCondition).
878       if (rhs.IsRegister()) {
879         __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
880       } else if (rhs.IsConstant()) {
881         int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
882         if (constant == 0) {
883           __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
884         } else {
885           __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
886         }
887       } else {
888         __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
889       }
890       __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
891     }
892   }
893   if (false_target != nullptr) {
894     __ jmp(false_target);
895   }
896 }
897 
VisitIf(HIf * if_instr)898 void LocationsBuilderX86::VisitIf(HIf* if_instr) {
899   LocationSummary* locations =
900       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
901   HInstruction* cond = if_instr->InputAt(0);
902   if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
903     locations->SetInAt(0, Location::Any());
904   }
905 }
906 
VisitIf(HIf * if_instr)907 void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
908   Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
909   Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
910   Label* always_true_target = true_target;
911   if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
912                                 if_instr->IfTrueSuccessor())) {
913     always_true_target = nullptr;
914   }
915   if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
916                                 if_instr->IfFalseSuccessor())) {
917     false_target = nullptr;
918   }
919   GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
920 }
921 
VisitDeoptimize(HDeoptimize * deoptimize)922 void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
923   LocationSummary* locations = new (GetGraph()->GetArena())
924       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
925   HInstruction* cond = deoptimize->InputAt(0);
926   DCHECK(cond->IsCondition());
927   if (cond->AsCondition()->NeedsMaterialization()) {
928     locations->SetInAt(0, Location::Any());
929   }
930 }
931 
VisitDeoptimize(HDeoptimize * deoptimize)932 void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
933   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena())
934       DeoptimizationSlowPathX86(deoptimize);
935   codegen_->AddSlowPath(slow_path);
936   Label* slow_path_entry = slow_path->GetEntryLabel();
937   GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
938 }
939 
VisitLocal(HLocal * local)940 void LocationsBuilderX86::VisitLocal(HLocal* local) {
941   local->SetLocations(nullptr);
942 }
943 
VisitLocal(HLocal * local)944 void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
945   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
946 }
947 
VisitLoadLocal(HLoadLocal * local)948 void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
949   local->SetLocations(nullptr);
950 }
951 
VisitLoadLocal(HLoadLocal * load)952 void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
953   // Nothing to do, this is driven by the code generator.
954   UNUSED(load);
955 }
956 
VisitStoreLocal(HStoreLocal * store)957 void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
958   LocationSummary* locations =
959       new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
960   switch (store->InputAt(1)->GetType()) {
961     case Primitive::kPrimBoolean:
962     case Primitive::kPrimByte:
963     case Primitive::kPrimChar:
964     case Primitive::kPrimShort:
965     case Primitive::kPrimInt:
966     case Primitive::kPrimNot:
967     case Primitive::kPrimFloat:
968       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
969       break;
970 
971     case Primitive::kPrimLong:
972     case Primitive::kPrimDouble:
973       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
974       break;
975 
976     default:
977       LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
978   }
979   store->SetLocations(locations);
980 }
981 
VisitStoreLocal(HStoreLocal * store)982 void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
983   UNUSED(store);
984 }
985 
VisitCondition(HCondition * comp)986 void LocationsBuilderX86::VisitCondition(HCondition* comp) {
987   LocationSummary* locations =
988       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
989   locations->SetInAt(0, Location::RequiresRegister());
990   locations->SetInAt(1, Location::Any());
991   if (comp->NeedsMaterialization()) {
992     // We need a byte register.
993     locations->SetOut(Location::RegisterLocation(ECX));
994   }
995 }
996 
VisitCondition(HCondition * comp)997 void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
998   if (comp->NeedsMaterialization()) {
999     LocationSummary* locations = comp->GetLocations();
1000     Register reg = locations->Out().AsRegister<Register>();
1001     // Clear register: setcc only sets the low byte.
1002     __ xorl(reg, reg);
1003     Location lhs = locations->InAt(0);
1004     Location rhs = locations->InAt(1);
1005     if (rhs.IsRegister()) {
1006       __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1007     } else if (rhs.IsConstant()) {
1008       int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1009       if (constant == 0) {
1010         __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1011       } else {
1012       __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1013       }
1014     } else {
1015       __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1016     }
1017     __ setb(X86Condition(comp->GetCondition()), reg);
1018   }
1019 }
1020 
VisitEqual(HEqual * comp)1021 void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1022   VisitCondition(comp);
1023 }
1024 
VisitEqual(HEqual * comp)1025 void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1026   VisitCondition(comp);
1027 }
1028 
VisitNotEqual(HNotEqual * comp)1029 void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1030   VisitCondition(comp);
1031 }
1032 
VisitNotEqual(HNotEqual * comp)1033 void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1034   VisitCondition(comp);
1035 }
1036 
VisitLessThan(HLessThan * comp)1037 void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1038   VisitCondition(comp);
1039 }
1040 
VisitLessThan(HLessThan * comp)1041 void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1042   VisitCondition(comp);
1043 }
1044 
VisitLessThanOrEqual(HLessThanOrEqual * comp)1045 void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1046   VisitCondition(comp);
1047 }
1048 
VisitLessThanOrEqual(HLessThanOrEqual * comp)1049 void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1050   VisitCondition(comp);
1051 }
1052 
VisitGreaterThan(HGreaterThan * comp)1053 void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1054   VisitCondition(comp);
1055 }
1056 
VisitGreaterThan(HGreaterThan * comp)1057 void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1058   VisitCondition(comp);
1059 }
1060 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)1061 void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1062   VisitCondition(comp);
1063 }
1064 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)1065 void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1066   VisitCondition(comp);
1067 }
1068 
VisitIntConstant(HIntConstant * constant)1069 void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
1070   LocationSummary* locations =
1071       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1072   locations->SetOut(Location::ConstantLocation(constant));
1073 }
1074 
VisitIntConstant(HIntConstant * constant)1075 void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
1076   // Will be generated at use site.
1077   UNUSED(constant);
1078 }
1079 
VisitNullConstant(HNullConstant * constant)1080 void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1081   LocationSummary* locations =
1082       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1083   locations->SetOut(Location::ConstantLocation(constant));
1084 }
1085 
VisitNullConstant(HNullConstant * constant)1086 void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1087   // Will be generated at use site.
1088   UNUSED(constant);
1089 }
1090 
VisitLongConstant(HLongConstant * constant)1091 void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
1092   LocationSummary* locations =
1093       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1094   locations->SetOut(Location::ConstantLocation(constant));
1095 }
1096 
VisitLongConstant(HLongConstant * constant)1097 void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1098   // Will be generated at use site.
1099   UNUSED(constant);
1100 }
1101 
VisitFloatConstant(HFloatConstant * constant)1102 void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1103   LocationSummary* locations =
1104       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1105   locations->SetOut(Location::ConstantLocation(constant));
1106 }
1107 
VisitFloatConstant(HFloatConstant * constant)1108 void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1109   // Will be generated at use site.
1110   UNUSED(constant);
1111 }
1112 
VisitDoubleConstant(HDoubleConstant * constant)1113 void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1114   LocationSummary* locations =
1115       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1116   locations->SetOut(Location::ConstantLocation(constant));
1117 }
1118 
VisitDoubleConstant(HDoubleConstant * constant)1119 void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1120   // Will be generated at use site.
1121   UNUSED(constant);
1122 }
1123 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)1124 void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1125   memory_barrier->SetLocations(nullptr);
1126 }
1127 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)1128 void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1129   GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1130 }
1131 
VisitReturnVoid(HReturnVoid * ret)1132 void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
1133   ret->SetLocations(nullptr);
1134 }
1135 
VisitReturnVoid(HReturnVoid * ret)1136 void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
1137   UNUSED(ret);
1138   codegen_->GenerateFrameExit();
1139 }
1140 
VisitReturn(HReturn * ret)1141 void LocationsBuilderX86::VisitReturn(HReturn* ret) {
1142   LocationSummary* locations =
1143       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
1144   switch (ret->InputAt(0)->GetType()) {
1145     case Primitive::kPrimBoolean:
1146     case Primitive::kPrimByte:
1147     case Primitive::kPrimChar:
1148     case Primitive::kPrimShort:
1149     case Primitive::kPrimInt:
1150     case Primitive::kPrimNot:
1151       locations->SetInAt(0, Location::RegisterLocation(EAX));
1152       break;
1153 
1154     case Primitive::kPrimLong:
1155       locations->SetInAt(
1156           0, Location::RegisterPairLocation(EAX, EDX));
1157       break;
1158 
1159     case Primitive::kPrimFloat:
1160     case Primitive::kPrimDouble:
1161       locations->SetInAt(
1162           0, Location::FpuRegisterLocation(XMM0));
1163       break;
1164 
1165     default:
1166       LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
1167   }
1168 }
1169 
VisitReturn(HReturn * ret)1170 void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
1171   if (kIsDebugBuild) {
1172     switch (ret->InputAt(0)->GetType()) {
1173       case Primitive::kPrimBoolean:
1174       case Primitive::kPrimByte:
1175       case Primitive::kPrimChar:
1176       case Primitive::kPrimShort:
1177       case Primitive::kPrimInt:
1178       case Primitive::kPrimNot:
1179         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
1180         break;
1181 
1182       case Primitive::kPrimLong:
1183         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1184         DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
1185         break;
1186 
1187       case Primitive::kPrimFloat:
1188       case Primitive::kPrimDouble:
1189         DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
1190         break;
1191 
1192       default:
1193         LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
1194     }
1195   }
1196   codegen_->GenerateFrameExit();
1197 }
1198 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)1199 void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1200   // When we do not run baseline, explicit clinit checks triggered by static
1201   // invokes must have been pruned by art::PrepareForRegisterAllocation.
1202   DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1203 
1204   IntrinsicLocationsBuilderX86 intrinsic(codegen_);
1205   if (intrinsic.TryDispatch(invoke)) {
1206     return;
1207   }
1208 
1209   HandleInvoke(invoke);
1210 }
1211 
TryGenerateIntrinsicCode(HInvoke * invoke,CodeGeneratorX86 * codegen)1212 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1213   if (invoke->GetLocations()->Intrinsified()) {
1214     IntrinsicCodeGeneratorX86 intrinsic(codegen);
1215     intrinsic.Dispatch(invoke);
1216     return true;
1217   }
1218   return false;
1219 }
1220 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)1221 void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1222   // When we do not run baseline, explicit clinit checks triggered by static
1223   // invokes must have been pruned by art::PrepareForRegisterAllocation.
1224   DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1225 
1226   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1227     return;
1228   }
1229 
1230   codegen_->GenerateStaticOrDirectCall(
1231       invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
1232   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1233 }
1234 
VisitInvokeVirtual(HInvokeVirtual * invoke)1235 void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1236   HandleInvoke(invoke);
1237 }
1238 
HandleInvoke(HInvoke * invoke)1239 void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
1240   LocationSummary* locations =
1241       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1242   locations->AddTemp(Location::RegisterLocation(EAX));
1243 
1244   InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
1245   for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
1246     HInstruction* input = invoke->InputAt(i);
1247     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1248   }
1249 
1250   switch (invoke->GetType()) {
1251     case Primitive::kPrimBoolean:
1252     case Primitive::kPrimByte:
1253     case Primitive::kPrimChar:
1254     case Primitive::kPrimShort:
1255     case Primitive::kPrimInt:
1256     case Primitive::kPrimNot:
1257       locations->SetOut(Location::RegisterLocation(EAX));
1258       break;
1259 
1260     case Primitive::kPrimLong:
1261       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1262       break;
1263 
1264     case Primitive::kPrimVoid:
1265       break;
1266 
1267     case Primitive::kPrimDouble:
1268     case Primitive::kPrimFloat:
1269       locations->SetOut(Location::FpuRegisterLocation(XMM0));
1270       break;
1271   }
1272 
1273   invoke->SetLocations(locations);
1274 }
1275 
VisitInvokeVirtual(HInvokeVirtual * invoke)1276 void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1277   Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1278   uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1279       invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
1280   LocationSummary* locations = invoke->GetLocations();
1281   Location receiver = locations->InAt(0);
1282   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1283   // temp = object->GetClass();
1284   if (receiver.IsStackSlot()) {
1285     __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1286     __ movl(temp, Address(temp, class_offset));
1287   } else {
1288     __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
1289   }
1290   codegen_->MaybeRecordImplicitNullCheck(invoke);
1291   // temp = temp->GetMethodAt(method_offset);
1292   __ movl(temp, Address(temp, method_offset));
1293   // call temp->GetEntryPoint();
1294   __ call(Address(
1295       temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
1296 
1297   DCHECK(!codegen_->IsLeafMethod());
1298   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1299 }
1300 
VisitInvokeInterface(HInvokeInterface * invoke)1301 void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1302   HandleInvoke(invoke);
1303   // Add the hidden argument.
1304   invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
1305 }
1306 
VisitInvokeInterface(HInvokeInterface * invoke)1307 void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1308   // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1309   Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1310   uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1311       invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
1312   LocationSummary* locations = invoke->GetLocations();
1313   Location receiver = locations->InAt(0);
1314   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1315 
1316   // Set the hidden argument.
1317   __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
1318   __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
1319 
1320   // temp = object->GetClass();
1321   if (receiver.IsStackSlot()) {
1322     __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1323     __ movl(temp, Address(temp, class_offset));
1324   } else {
1325     __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
1326   }
1327     codegen_->MaybeRecordImplicitNullCheck(invoke);
1328   // temp = temp->GetImtEntryAt(method_offset);
1329   __ movl(temp, Address(temp, method_offset));
1330   // call temp->GetEntryPoint();
1331   __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1332       kX86WordSize).Int32Value()));
1333 
1334   DCHECK(!codegen_->IsLeafMethod());
1335   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1336 }
1337 
VisitNeg(HNeg * neg)1338 void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1339   LocationSummary* locations =
1340       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1341   switch (neg->GetResultType()) {
1342     case Primitive::kPrimInt:
1343     case Primitive::kPrimLong:
1344       locations->SetInAt(0, Location::RequiresRegister());
1345       locations->SetOut(Location::SameAsFirstInput());
1346       break;
1347 
1348     case Primitive::kPrimFloat:
1349       locations->SetInAt(0, Location::RequiresFpuRegister());
1350       locations->SetOut(Location::SameAsFirstInput());
1351       locations->AddTemp(Location::RequiresRegister());
1352       locations->AddTemp(Location::RequiresFpuRegister());
1353       break;
1354 
1355     case Primitive::kPrimDouble:
1356       locations->SetInAt(0, Location::RequiresFpuRegister());
1357       locations->SetOut(Location::SameAsFirstInput());
1358       locations->AddTemp(Location::RequiresFpuRegister());
1359       break;
1360 
1361     default:
1362       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1363   }
1364 }
1365 
VisitNeg(HNeg * neg)1366 void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1367   LocationSummary* locations = neg->GetLocations();
1368   Location out = locations->Out();
1369   Location in = locations->InAt(0);
1370   switch (neg->GetResultType()) {
1371     case Primitive::kPrimInt:
1372       DCHECK(in.IsRegister());
1373       DCHECK(in.Equals(out));
1374       __ negl(out.AsRegister<Register>());
1375       break;
1376 
1377     case Primitive::kPrimLong:
1378       DCHECK(in.IsRegisterPair());
1379       DCHECK(in.Equals(out));
1380       __ negl(out.AsRegisterPairLow<Register>());
1381       // Negation is similar to subtraction from zero.  The least
1382       // significant byte triggers a borrow when it is different from
1383       // zero; to take it into account, add 1 to the most significant
1384       // byte if the carry flag (CF) is set to 1 after the first NEGL
1385       // operation.
1386       __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1387       __ negl(out.AsRegisterPairHigh<Register>());
1388       break;
1389 
1390     case Primitive::kPrimFloat: {
1391       DCHECK(in.Equals(out));
1392       Register constant = locations->GetTemp(0).AsRegister<Register>();
1393       XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1394       // Implement float negation with an exclusive or with value
1395       // 0x80000000 (mask for bit 31, representing the sign of a
1396       // single-precision floating-point number).
1397       __ movl(constant, Immediate(INT32_C(0x80000000)));
1398       __ movd(mask, constant);
1399       __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
1400       break;
1401     }
1402 
1403     case Primitive::kPrimDouble: {
1404       DCHECK(in.Equals(out));
1405       XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1406       // Implement double negation with an exclusive or with value
1407       // 0x8000000000000000 (mask for bit 63, representing the sign of
1408       // a double-precision floating-point number).
1409       __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
1410       __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
1411       break;
1412     }
1413 
1414     default:
1415       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1416   }
1417 }
1418 
VisitTypeConversion(HTypeConversion * conversion)1419 void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
1420   Primitive::Type result_type = conversion->GetResultType();
1421   Primitive::Type input_type = conversion->GetInputType();
1422   DCHECK_NE(result_type, input_type);
1423 
1424   // The float-to-long and double-to-long type conversions rely on a
1425   // call to the runtime.
1426   LocationSummary::CallKind call_kind =
1427       ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1428        && result_type == Primitive::kPrimLong)
1429       ? LocationSummary::kCall
1430       : LocationSummary::kNoCall;
1431   LocationSummary* locations =
1432       new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1433 
1434   // The Java language does not allow treating boolean as an integral type but
1435   // our bit representation makes it safe.
1436 
1437   switch (result_type) {
1438     case Primitive::kPrimByte:
1439       switch (input_type) {
1440         case Primitive::kPrimBoolean:
1441           // Boolean input is a result of code transformations.
1442         case Primitive::kPrimShort:
1443         case Primitive::kPrimInt:
1444         case Primitive::kPrimChar:
1445           // Processing a Dex `int-to-byte' instruction.
1446           locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1447           // Make the output overlap to please the register allocator. This greatly simplifies
1448           // the validation of the linear scan implementation
1449           locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1450           break;
1451 
1452         default:
1453           LOG(FATAL) << "Unexpected type conversion from " << input_type
1454                      << " to " << result_type;
1455       }
1456       break;
1457 
1458     case Primitive::kPrimShort:
1459       switch (input_type) {
1460         case Primitive::kPrimBoolean:
1461           // Boolean input is a result of code transformations.
1462         case Primitive::kPrimByte:
1463         case Primitive::kPrimInt:
1464         case Primitive::kPrimChar:
1465           // Processing a Dex `int-to-short' instruction.
1466           locations->SetInAt(0, Location::Any());
1467           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1468           break;
1469 
1470         default:
1471           LOG(FATAL) << "Unexpected type conversion from " << input_type
1472                      << " to " << result_type;
1473       }
1474       break;
1475 
1476     case Primitive::kPrimInt:
1477       switch (input_type) {
1478         case Primitive::kPrimLong:
1479           // Processing a Dex `long-to-int' instruction.
1480           locations->SetInAt(0, Location::Any());
1481           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1482           break;
1483 
1484         case Primitive::kPrimFloat:
1485           // Processing a Dex `float-to-int' instruction.
1486           locations->SetInAt(0, Location::RequiresFpuRegister());
1487           locations->SetOut(Location::RequiresRegister());
1488           locations->AddTemp(Location::RequiresFpuRegister());
1489           break;
1490 
1491         case Primitive::kPrimDouble:
1492           // Processing a Dex `double-to-int' instruction.
1493           locations->SetInAt(0, Location::RequiresFpuRegister());
1494           locations->SetOut(Location::RequiresRegister());
1495           locations->AddTemp(Location::RequiresFpuRegister());
1496           break;
1497 
1498         default:
1499           LOG(FATAL) << "Unexpected type conversion from " << input_type
1500                      << " to " << result_type;
1501       }
1502       break;
1503 
1504     case Primitive::kPrimLong:
1505       switch (input_type) {
1506         case Primitive::kPrimBoolean:
1507           // Boolean input is a result of code transformations.
1508         case Primitive::kPrimByte:
1509         case Primitive::kPrimShort:
1510         case Primitive::kPrimInt:
1511         case Primitive::kPrimChar:
1512           // Processing a Dex `int-to-long' instruction.
1513           locations->SetInAt(0, Location::RegisterLocation(EAX));
1514           locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1515           break;
1516 
1517         case Primitive::kPrimFloat:
1518         case Primitive::kPrimDouble: {
1519           // Processing a Dex `float-to-long' or 'double-to-long' instruction.
1520           InvokeRuntimeCallingConvention calling_convention;
1521           XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1522           locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1523 
1524           // The runtime helper puts the result in EAX, EDX.
1525           locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1526         }
1527         break;
1528 
1529         default:
1530           LOG(FATAL) << "Unexpected type conversion from " << input_type
1531                      << " to " << result_type;
1532       }
1533       break;
1534 
1535     case Primitive::kPrimChar:
1536       switch (input_type) {
1537         case Primitive::kPrimBoolean:
1538           // Boolean input is a result of code transformations.
1539         case Primitive::kPrimByte:
1540         case Primitive::kPrimShort:
1541         case Primitive::kPrimInt:
1542           // Processing a Dex `int-to-char' instruction.
1543           locations->SetInAt(0, Location::Any());
1544           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1545           break;
1546 
1547         default:
1548           LOG(FATAL) << "Unexpected type conversion from " << input_type
1549                      << " to " << result_type;
1550       }
1551       break;
1552 
1553     case Primitive::kPrimFloat:
1554       switch (input_type) {
1555         case Primitive::kPrimBoolean:
1556           // Boolean input is a result of code transformations.
1557         case Primitive::kPrimByte:
1558         case Primitive::kPrimShort:
1559         case Primitive::kPrimInt:
1560         case Primitive::kPrimChar:
1561           // Processing a Dex `int-to-float' instruction.
1562           locations->SetInAt(0, Location::RequiresRegister());
1563           locations->SetOut(Location::RequiresFpuRegister());
1564           break;
1565 
1566         case Primitive::kPrimLong:
1567           // Processing a Dex `long-to-float' instruction.
1568           locations->SetInAt(0, Location::Any());
1569           locations->SetOut(Location::Any());
1570           break;
1571 
1572         case Primitive::kPrimDouble:
1573           // Processing a Dex `double-to-float' instruction.
1574           locations->SetInAt(0, Location::RequiresFpuRegister());
1575           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1576           break;
1577 
1578         default:
1579           LOG(FATAL) << "Unexpected type conversion from " << input_type
1580                      << " to " << result_type;
1581       };
1582       break;
1583 
1584     case Primitive::kPrimDouble:
1585       switch (input_type) {
1586         case Primitive::kPrimBoolean:
1587           // Boolean input is a result of code transformations.
1588         case Primitive::kPrimByte:
1589         case Primitive::kPrimShort:
1590         case Primitive::kPrimInt:
1591         case Primitive::kPrimChar:
1592           // Processing a Dex `int-to-double' instruction.
1593           locations->SetInAt(0, Location::RequiresRegister());
1594           locations->SetOut(Location::RequiresFpuRegister());
1595           break;
1596 
1597         case Primitive::kPrimLong:
1598           // Processing a Dex `long-to-double' instruction.
1599           locations->SetInAt(0, Location::Any());
1600           locations->SetOut(Location::Any());
1601           break;
1602 
1603         case Primitive::kPrimFloat:
1604           // Processing a Dex `float-to-double' instruction.
1605           locations->SetInAt(0, Location::RequiresFpuRegister());
1606           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1607           break;
1608 
1609         default:
1610           LOG(FATAL) << "Unexpected type conversion from " << input_type
1611                      << " to " << result_type;
1612       }
1613       break;
1614 
1615     default:
1616       LOG(FATAL) << "Unexpected type conversion from " << input_type
1617                  << " to " << result_type;
1618   }
1619 }
1620 
VisitTypeConversion(HTypeConversion * conversion)1621 void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1622   LocationSummary* locations = conversion->GetLocations();
1623   Location out = locations->Out();
1624   Location in = locations->InAt(0);
1625   Primitive::Type result_type = conversion->GetResultType();
1626   Primitive::Type input_type = conversion->GetInputType();
1627   DCHECK_NE(result_type, input_type);
1628   switch (result_type) {
1629     case Primitive::kPrimByte:
1630       switch (input_type) {
1631         case Primitive::kPrimBoolean:
1632           // Boolean input is a result of code transformations.
1633         case Primitive::kPrimShort:
1634         case Primitive::kPrimInt:
1635         case Primitive::kPrimChar:
1636           // Processing a Dex `int-to-byte' instruction.
1637           if (in.IsRegister()) {
1638             __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
1639           } else {
1640             DCHECK(in.GetConstant()->IsIntConstant());
1641             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1642             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1643           }
1644           break;
1645 
1646         default:
1647           LOG(FATAL) << "Unexpected type conversion from " << input_type
1648                      << " to " << result_type;
1649       }
1650       break;
1651 
1652     case Primitive::kPrimShort:
1653       switch (input_type) {
1654         case Primitive::kPrimBoolean:
1655           // Boolean input is a result of code transformations.
1656         case Primitive::kPrimByte:
1657         case Primitive::kPrimInt:
1658         case Primitive::kPrimChar:
1659           // Processing a Dex `int-to-short' instruction.
1660           if (in.IsRegister()) {
1661             __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
1662           } else if (in.IsStackSlot()) {
1663             __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
1664           } else {
1665             DCHECK(in.GetConstant()->IsIntConstant());
1666             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1667             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
1668           }
1669           break;
1670 
1671         default:
1672           LOG(FATAL) << "Unexpected type conversion from " << input_type
1673                      << " to " << result_type;
1674       }
1675       break;
1676 
1677     case Primitive::kPrimInt:
1678       switch (input_type) {
1679         case Primitive::kPrimLong:
1680           // Processing a Dex `long-to-int' instruction.
1681           if (in.IsRegisterPair()) {
1682             __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
1683           } else if (in.IsDoubleStackSlot()) {
1684             __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
1685           } else {
1686             DCHECK(in.IsConstant());
1687             DCHECK(in.GetConstant()->IsLongConstant());
1688             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
1689             __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
1690           }
1691           break;
1692 
1693         case Primitive::kPrimFloat: {
1694           // Processing a Dex `float-to-int' instruction.
1695           XmmRegister input = in.AsFpuRegister<XmmRegister>();
1696           Register output = out.AsRegister<Register>();
1697           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1698           Label done, nan;
1699 
1700           __ movl(output, Immediate(kPrimIntMax));
1701           // temp = int-to-float(output)
1702           __ cvtsi2ss(temp, output);
1703           // if input >= temp goto done
1704           __ comiss(input, temp);
1705           __ j(kAboveEqual, &done);
1706           // if input == NaN goto nan
1707           __ j(kUnordered, &nan);
1708           // output = float-to-int-truncate(input)
1709           __ cvttss2si(output, input);
1710           __ jmp(&done);
1711           __ Bind(&nan);
1712           //  output = 0
1713           __ xorl(output, output);
1714           __ Bind(&done);
1715           break;
1716         }
1717 
1718         case Primitive::kPrimDouble: {
1719           // Processing a Dex `double-to-int' instruction.
1720           XmmRegister input = in.AsFpuRegister<XmmRegister>();
1721           Register output = out.AsRegister<Register>();
1722           XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1723           Label done, nan;
1724 
1725           __ movl(output, Immediate(kPrimIntMax));
1726           // temp = int-to-double(output)
1727           __ cvtsi2sd(temp, output);
1728           // if input >= temp goto done
1729           __ comisd(input, temp);
1730           __ j(kAboveEqual, &done);
1731           // if input == NaN goto nan
1732           __ j(kUnordered, &nan);
1733           // output = double-to-int-truncate(input)
1734           __ cvttsd2si(output, input);
1735           __ jmp(&done);
1736           __ Bind(&nan);
1737           //  output = 0
1738           __ xorl(output, output);
1739           __ Bind(&done);
1740           break;
1741         }
1742 
1743         default:
1744           LOG(FATAL) << "Unexpected type conversion from " << input_type
1745                      << " to " << result_type;
1746       }
1747       break;
1748 
1749     case Primitive::kPrimLong:
1750       switch (input_type) {
1751         case Primitive::kPrimBoolean:
1752           // Boolean input is a result of code transformations.
1753         case Primitive::kPrimByte:
1754         case Primitive::kPrimShort:
1755         case Primitive::kPrimInt:
1756         case Primitive::kPrimChar:
1757           // Processing a Dex `int-to-long' instruction.
1758           DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1759           DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
1760           DCHECK_EQ(in.AsRegister<Register>(), EAX);
1761           __ cdq();
1762           break;
1763 
1764         case Primitive::kPrimFloat:
1765           // Processing a Dex `float-to-long' instruction.
1766           __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
1767           codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1768           break;
1769 
1770         case Primitive::kPrimDouble:
1771           // Processing a Dex `double-to-long' instruction.
1772           __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1773           codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1774           break;
1775 
1776         default:
1777           LOG(FATAL) << "Unexpected type conversion from " << input_type
1778                      << " to " << result_type;
1779       }
1780       break;
1781 
1782     case Primitive::kPrimChar:
1783       switch (input_type) {
1784         case Primitive::kPrimBoolean:
1785           // Boolean input is a result of code transformations.
1786         case Primitive::kPrimByte:
1787         case Primitive::kPrimShort:
1788         case Primitive::kPrimInt:
1789           // Processing a Dex `Process a Dex `int-to-char'' instruction.
1790           if (in.IsRegister()) {
1791             __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
1792           } else if (in.IsStackSlot()) {
1793             __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
1794           } else {
1795             DCHECK(in.GetConstant()->IsIntConstant());
1796             int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1797             __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
1798           }
1799           break;
1800 
1801         default:
1802           LOG(FATAL) << "Unexpected type conversion from " << input_type
1803                      << " to " << result_type;
1804       }
1805       break;
1806 
1807     case Primitive::kPrimFloat:
1808       switch (input_type) {
1809         case Primitive::kPrimBoolean:
1810           // Boolean input is a result of code transformations.
1811         case Primitive::kPrimByte:
1812         case Primitive::kPrimShort:
1813         case Primitive::kPrimInt:
1814         case Primitive::kPrimChar:
1815           // Processing a Dex `int-to-float' instruction.
1816           __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
1817           break;
1818 
1819         case Primitive::kPrimLong: {
1820           // Processing a Dex `long-to-float' instruction.
1821           size_t adjustment = 0;
1822 
1823           // Create stack space for the call to
1824           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
1825           // TODO: enhance register allocator to ask for stack temporaries.
1826           if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
1827             adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
1828             __ subl(ESP, Immediate(adjustment));
1829           }
1830 
1831           // Load the value to the FP stack, using temporaries if needed.
1832           PushOntoFPStack(in, 0, adjustment, false, true);
1833 
1834           if (out.IsStackSlot()) {
1835             __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
1836           } else {
1837             __ fstps(Address(ESP, 0));
1838             Location stack_temp = Location::StackSlot(0);
1839             codegen_->Move32(out, stack_temp);
1840           }
1841 
1842           // Remove the temporary stack space we allocated.
1843           if (adjustment != 0) {
1844             __ addl(ESP, Immediate(adjustment));
1845           }
1846           break;
1847         }
1848 
1849         case Primitive::kPrimDouble:
1850           // Processing a Dex `double-to-float' instruction.
1851           __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
1852           break;
1853 
1854         default:
1855           LOG(FATAL) << "Unexpected type conversion from " << input_type
1856                      << " to " << result_type;
1857       };
1858       break;
1859 
1860     case Primitive::kPrimDouble:
1861       switch (input_type) {
1862         case Primitive::kPrimBoolean:
1863           // Boolean input is a result of code transformations.
1864         case Primitive::kPrimByte:
1865         case Primitive::kPrimShort:
1866         case Primitive::kPrimInt:
1867         case Primitive::kPrimChar:
1868           // Processing a Dex `int-to-double' instruction.
1869           __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
1870           break;
1871 
1872         case Primitive::kPrimLong: {
1873           // Processing a Dex `long-to-double' instruction.
1874           size_t adjustment = 0;
1875 
1876           // Create stack space for the call to
1877           // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
1878           // TODO: enhance register allocator to ask for stack temporaries.
1879           if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
1880             adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
1881             __ subl(ESP, Immediate(adjustment));
1882           }
1883 
1884           // Load the value to the FP stack, using temporaries if needed.
1885           PushOntoFPStack(in, 0, adjustment, false, true);
1886 
1887           if (out.IsDoubleStackSlot()) {
1888             __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
1889           } else {
1890             __ fstpl(Address(ESP, 0));
1891             Location stack_temp = Location::DoubleStackSlot(0);
1892             codegen_->Move64(out, stack_temp);
1893           }
1894 
1895           // Remove the temporary stack space we allocated.
1896           if (adjustment != 0) {
1897             __ addl(ESP, Immediate(adjustment));
1898           }
1899           break;
1900         }
1901 
1902         case Primitive::kPrimFloat:
1903           // Processing a Dex `float-to-double' instruction.
1904           __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
1905           break;
1906 
1907         default:
1908           LOG(FATAL) << "Unexpected type conversion from " << input_type
1909                      << " to " << result_type;
1910       };
1911       break;
1912 
1913     default:
1914       LOG(FATAL) << "Unexpected type conversion from " << input_type
1915                  << " to " << result_type;
1916   }
1917 }
1918 
VisitAdd(HAdd * add)1919 void LocationsBuilderX86::VisitAdd(HAdd* add) {
1920   LocationSummary* locations =
1921       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
1922   switch (add->GetResultType()) {
1923     case Primitive::kPrimInt: {
1924       locations->SetInAt(0, Location::RequiresRegister());
1925       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1926       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1927       break;
1928     }
1929 
1930     case Primitive::kPrimLong: {
1931       locations->SetInAt(0, Location::RequiresRegister());
1932       locations->SetInAt(1, Location::Any());
1933       locations->SetOut(Location::SameAsFirstInput());
1934       break;
1935     }
1936 
1937     case Primitive::kPrimFloat:
1938     case Primitive::kPrimDouble: {
1939       locations->SetInAt(0, Location::RequiresFpuRegister());
1940       locations->SetInAt(1, Location::RequiresFpuRegister());
1941       locations->SetOut(Location::SameAsFirstInput());
1942       break;
1943     }
1944 
1945     default:
1946       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1947       break;
1948   }
1949 }
1950 
VisitAdd(HAdd * add)1951 void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1952   LocationSummary* locations = add->GetLocations();
1953   Location first = locations->InAt(0);
1954   Location second = locations->InAt(1);
1955   Location out = locations->Out();
1956 
1957   switch (add->GetResultType()) {
1958     case Primitive::kPrimInt: {
1959       if (second.IsRegister()) {
1960         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1961           __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
1962         } else {
1963           __ leal(out.AsRegister<Register>(), Address(
1964               first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
1965           }
1966       } else if (second.IsConstant()) {
1967         int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
1968         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1969           __ addl(out.AsRegister<Register>(), Immediate(value));
1970         } else {
1971           __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
1972         }
1973       } else {
1974         DCHECK(first.Equals(locations->Out()));
1975         __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
1976       }
1977       break;
1978     }
1979 
1980     case Primitive::kPrimLong: {
1981       if (second.IsRegisterPair()) {
1982         __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1983         __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
1984       } else if (second.IsDoubleStackSlot()) {
1985         __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1986         __ adcl(first.AsRegisterPairHigh<Register>(),
1987                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
1988       } else {
1989         DCHECK(second.IsConstant()) << second;
1990         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1991         __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1992         __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
1993       }
1994       break;
1995     }
1996 
1997     case Primitive::kPrimFloat: {
1998       if (second.IsFpuRegister()) {
1999         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2000       }
2001       break;
2002     }
2003 
2004     case Primitive::kPrimDouble: {
2005       if (second.IsFpuRegister()) {
2006         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2007       }
2008       break;
2009     }
2010 
2011     default:
2012       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2013   }
2014 }
2015 
VisitSub(HSub * sub)2016 void LocationsBuilderX86::VisitSub(HSub* sub) {
2017   LocationSummary* locations =
2018       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
2019   switch (sub->GetResultType()) {
2020     case Primitive::kPrimInt:
2021     case Primitive::kPrimLong: {
2022       locations->SetInAt(0, Location::RequiresRegister());
2023       locations->SetInAt(1, Location::Any());
2024       locations->SetOut(Location::SameAsFirstInput());
2025       break;
2026     }
2027     case Primitive::kPrimFloat:
2028     case Primitive::kPrimDouble: {
2029       locations->SetInAt(0, Location::RequiresFpuRegister());
2030       locations->SetInAt(1, Location::RequiresFpuRegister());
2031       locations->SetOut(Location::SameAsFirstInput());
2032       break;
2033     }
2034 
2035     default:
2036       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2037   }
2038 }
2039 
VisitSub(HSub * sub)2040 void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2041   LocationSummary* locations = sub->GetLocations();
2042   Location first = locations->InAt(0);
2043   Location second = locations->InAt(1);
2044   DCHECK(first.Equals(locations->Out()));
2045   switch (sub->GetResultType()) {
2046     case Primitive::kPrimInt: {
2047       if (second.IsRegister()) {
2048         __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
2049       } else if (second.IsConstant()) {
2050         __ subl(first.AsRegister<Register>(),
2051                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2052       } else {
2053         __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
2054       }
2055       break;
2056     }
2057 
2058     case Primitive::kPrimLong: {
2059       if (second.IsRegisterPair()) {
2060         __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2061         __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
2062       } else if (second.IsDoubleStackSlot()) {
2063         __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2064         __ sbbl(first.AsRegisterPairHigh<Register>(),
2065                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
2066       } else {
2067         DCHECK(second.IsConstant()) << second;
2068         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2069         __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2070         __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
2071       }
2072       break;
2073     }
2074 
2075     case Primitive::kPrimFloat: {
2076       __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2077       break;
2078     }
2079 
2080     case Primitive::kPrimDouble: {
2081       __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2082       break;
2083     }
2084 
2085     default:
2086       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2087   }
2088 }
2089 
VisitMul(HMul * mul)2090 void LocationsBuilderX86::VisitMul(HMul* mul) {
2091   LocationSummary* locations =
2092       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2093   switch (mul->GetResultType()) {
2094     case Primitive::kPrimInt:
2095       locations->SetInAt(0, Location::RequiresRegister());
2096       locations->SetInAt(1, Location::Any());
2097       locations->SetOut(Location::SameAsFirstInput());
2098       break;
2099     case Primitive::kPrimLong: {
2100       locations->SetInAt(0, Location::RequiresRegister());
2101       locations->SetInAt(1, Location::Any());
2102       locations->SetOut(Location::SameAsFirstInput());
2103       // Needed for imul on 32bits with 64bits output.
2104       locations->AddTemp(Location::RegisterLocation(EAX));
2105       locations->AddTemp(Location::RegisterLocation(EDX));
2106       break;
2107     }
2108     case Primitive::kPrimFloat:
2109     case Primitive::kPrimDouble: {
2110       locations->SetInAt(0, Location::RequiresFpuRegister());
2111       locations->SetInAt(1, Location::RequiresFpuRegister());
2112       locations->SetOut(Location::SameAsFirstInput());
2113       break;
2114     }
2115 
2116     default:
2117       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2118   }
2119 }
2120 
VisitMul(HMul * mul)2121 void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2122   LocationSummary* locations = mul->GetLocations();
2123   Location first = locations->InAt(0);
2124   Location second = locations->InAt(1);
2125   DCHECK(first.Equals(locations->Out()));
2126 
2127   switch (mul->GetResultType()) {
2128     case Primitive::kPrimInt: {
2129       if (second.IsRegister()) {
2130         __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
2131       } else if (second.IsConstant()) {
2132         Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
2133         __ imull(first.AsRegister<Register>(), imm);
2134       } else {
2135         DCHECK(second.IsStackSlot());
2136         __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
2137       }
2138       break;
2139     }
2140 
2141     case Primitive::kPrimLong: {
2142       Register in1_hi = first.AsRegisterPairHigh<Register>();
2143       Register in1_lo = first.AsRegisterPairLow<Register>();
2144       Register eax = locations->GetTemp(0).AsRegister<Register>();
2145       Register edx = locations->GetTemp(1).AsRegister<Register>();
2146 
2147       DCHECK_EQ(EAX, eax);
2148       DCHECK_EQ(EDX, edx);
2149 
2150       // input: in1 - 64 bits, in2 - 64 bits.
2151       // output: in1
2152       // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2153       // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2154       // parts: in1.lo = (in1.lo * in2.lo)[31:0]
2155       if (second.IsConstant()) {
2156         DCHECK(second.GetConstant()->IsLongConstant());
2157 
2158         int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2159         int32_t low_value = Low32Bits(value);
2160         int32_t high_value = High32Bits(value);
2161         Immediate low(low_value);
2162         Immediate high(high_value);
2163 
2164         __ movl(eax, high);
2165         // eax <- in1.lo * in2.hi
2166         __ imull(eax, in1_lo);
2167         // in1.hi <- in1.hi * in2.lo
2168         __ imull(in1_hi, low);
2169         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2170         __ addl(in1_hi, eax);
2171         // move in2_lo to eax to prepare for double precision
2172         __ movl(eax, low);
2173         // edx:eax <- in1.lo * in2.lo
2174         __ mull(in1_lo);
2175         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2176         __ addl(in1_hi, edx);
2177         // in1.lo <- (in1.lo * in2.lo)[31:0];
2178         __ movl(in1_lo, eax);
2179       } else if (second.IsRegisterPair()) {
2180         Register in2_hi = second.AsRegisterPairHigh<Register>();
2181         Register in2_lo = second.AsRegisterPairLow<Register>();
2182 
2183         __ movl(eax, in2_hi);
2184         // eax <- in1.lo * in2.hi
2185         __ imull(eax, in1_lo);
2186         // in1.hi <- in1.hi * in2.lo
2187         __ imull(in1_hi, in2_lo);
2188         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2189         __ addl(in1_hi, eax);
2190         // move in1_lo to eax to prepare for double precision
2191         __ movl(eax, in1_lo);
2192         // edx:eax <- in1.lo * in2.lo
2193         __ mull(in2_lo);
2194         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2195         __ addl(in1_hi, edx);
2196         // in1.lo <- (in1.lo * in2.lo)[31:0];
2197         __ movl(in1_lo, eax);
2198       } else {
2199         DCHECK(second.IsDoubleStackSlot()) << second;
2200         Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2201         Address in2_lo(ESP, second.GetStackIndex());
2202 
2203         __ movl(eax, in2_hi);
2204         // eax <- in1.lo * in2.hi
2205         __ imull(eax, in1_lo);
2206         // in1.hi <- in1.hi * in2.lo
2207         __ imull(in1_hi, in2_lo);
2208         // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2209         __ addl(in1_hi, eax);
2210         // move in1_lo to eax to prepare for double precision
2211         __ movl(eax, in1_lo);
2212         // edx:eax <- in1.lo * in2.lo
2213         __ mull(in2_lo);
2214         // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2215         __ addl(in1_hi, edx);
2216         // in1.lo <- (in1.lo * in2.lo)[31:0];
2217         __ movl(in1_lo, eax);
2218       }
2219 
2220       break;
2221     }
2222 
2223     case Primitive::kPrimFloat: {
2224       __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2225       break;
2226     }
2227 
2228     case Primitive::kPrimDouble: {
2229       __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2230       break;
2231     }
2232 
2233     default:
2234       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2235   }
2236 }
2237 
PushOntoFPStack(Location source,uint32_t temp_offset,uint32_t stack_adjustment,bool is_fp,bool is_wide)2238 void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2239                                                   uint32_t temp_offset,
2240                                                   uint32_t stack_adjustment,
2241                                                   bool is_fp,
2242                                                   bool is_wide) {
2243   if (source.IsStackSlot()) {
2244     DCHECK(!is_wide);
2245     if (is_fp) {
2246       __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2247     } else {
2248       __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2249     }
2250   } else if (source.IsDoubleStackSlot()) {
2251     DCHECK(is_wide);
2252     if (is_fp) {
2253       __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2254     } else {
2255       __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2256     }
2257   } else {
2258     // Write the value to the temporary location on the stack and load to FP stack.
2259     if (!is_wide) {
2260       Location stack_temp = Location::StackSlot(temp_offset);
2261       codegen_->Move32(stack_temp, source);
2262       if (is_fp) {
2263         __ flds(Address(ESP, temp_offset));
2264       } else {
2265         __ filds(Address(ESP, temp_offset));
2266       }
2267     } else {
2268       Location stack_temp = Location::DoubleStackSlot(temp_offset);
2269       codegen_->Move64(stack_temp, source);
2270       if (is_fp) {
2271         __ fldl(Address(ESP, temp_offset));
2272       } else {
2273         __ fildl(Address(ESP, temp_offset));
2274       }
2275     }
2276   }
2277 }
2278 
GenerateRemFP(HRem * rem)2279 void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2280   Primitive::Type type = rem->GetResultType();
2281   bool is_float = type == Primitive::kPrimFloat;
2282   size_t elem_size = Primitive::ComponentSize(type);
2283   LocationSummary* locations = rem->GetLocations();
2284   Location first = locations->InAt(0);
2285   Location second = locations->InAt(1);
2286   Location out = locations->Out();
2287 
2288   // Create stack space for 2 elements.
2289   // TODO: enhance register allocator to ask for stack temporaries.
2290   __ subl(ESP, Immediate(2 * elem_size));
2291 
2292   // Load the values to the FP stack in reverse order, using temporaries if needed.
2293   const bool is_wide = !is_float;
2294   PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2295   PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
2296 
2297   // Loop doing FPREM until we stabilize.
2298   Label retry;
2299   __ Bind(&retry);
2300   __ fprem();
2301 
2302   // Move FP status to AX.
2303   __ fstsw();
2304 
2305   // And see if the argument reduction is complete. This is signaled by the
2306   // C2 FPU flag bit set to 0.
2307   __ andl(EAX, Immediate(kC2ConditionMask));
2308   __ j(kNotEqual, &retry);
2309 
2310   // We have settled on the final value. Retrieve it into an XMM register.
2311   // Store FP top of stack to real stack.
2312   if (is_float) {
2313     __ fsts(Address(ESP, 0));
2314   } else {
2315     __ fstl(Address(ESP, 0));
2316   }
2317 
2318   // Pop the 2 items from the FP stack.
2319   __ fucompp();
2320 
2321   // Load the value from the stack into an XMM register.
2322   DCHECK(out.IsFpuRegister()) << out;
2323   if (is_float) {
2324     __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2325   } else {
2326     __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2327   }
2328 
2329   // And remove the temporary stack space we allocated.
2330   __ addl(ESP, Immediate(2 * elem_size));
2331 }
2332 
2333 
DivRemOneOrMinusOne(HBinaryOperation * instruction)2334 void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2335   DCHECK(instruction->IsDiv() || instruction->IsRem());
2336 
2337   LocationSummary* locations = instruction->GetLocations();
2338   DCHECK(locations->InAt(1).IsConstant());
2339   DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
2340 
2341   Register out_register = locations->Out().AsRegister<Register>();
2342   Register input_register = locations->InAt(0).AsRegister<Register>();
2343   int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2344 
2345   DCHECK(imm == 1 || imm == -1);
2346 
2347   if (instruction->IsRem()) {
2348     __ xorl(out_register, out_register);
2349   } else {
2350     __ movl(out_register, input_register);
2351     if (imm == -1) {
2352       __ negl(out_register);
2353     }
2354   }
2355 }
2356 
2357 
DivByPowerOfTwo(HDiv * instruction)2358 void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
2359   LocationSummary* locations = instruction->GetLocations();
2360 
2361   Register out_register = locations->Out().AsRegister<Register>();
2362   Register input_register = locations->InAt(0).AsRegister<Register>();
2363   int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2364 
2365   DCHECK(IsPowerOfTwo(std::abs(imm)));
2366   Register num = locations->GetTemp(0).AsRegister<Register>();
2367 
2368   __ leal(num, Address(input_register, std::abs(imm) - 1));
2369   __ testl(input_register, input_register);
2370   __ cmovl(kGreaterEqual, num, input_register);
2371   int shift = CTZ(imm);
2372   __ sarl(num, Immediate(shift));
2373 
2374   if (imm < 0) {
2375     __ negl(num);
2376   }
2377 
2378   __ movl(out_register, num);
2379 }
2380 
GenerateDivRemWithAnyConstant(HBinaryOperation * instruction)2381 void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2382   DCHECK(instruction->IsDiv() || instruction->IsRem());
2383 
2384   LocationSummary* locations = instruction->GetLocations();
2385   int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2386 
2387   Register eax = locations->InAt(0).AsRegister<Register>();
2388   Register out = locations->Out().AsRegister<Register>();
2389   Register num;
2390   Register edx;
2391 
2392   if (instruction->IsDiv()) {
2393     edx = locations->GetTemp(0).AsRegister<Register>();
2394     num = locations->GetTemp(1).AsRegister<Register>();
2395   } else {
2396     edx = locations->Out().AsRegister<Register>();
2397     num = locations->GetTemp(0).AsRegister<Register>();
2398   }
2399 
2400   DCHECK_EQ(EAX, eax);
2401   DCHECK_EQ(EDX, edx);
2402   if (instruction->IsDiv()) {
2403     DCHECK_EQ(EAX, out);
2404   } else {
2405     DCHECK_EQ(EDX, out);
2406   }
2407 
2408   int64_t magic;
2409   int shift;
2410   CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2411 
2412   Label ndiv;
2413   Label end;
2414   // If numerator is 0, the result is 0, no computation needed.
2415   __ testl(eax, eax);
2416   __ j(kNotEqual, &ndiv);
2417 
2418   __ xorl(out, out);
2419   __ jmp(&end);
2420 
2421   __ Bind(&ndiv);
2422 
2423   // Save the numerator.
2424   __ movl(num, eax);
2425 
2426   // EAX = magic
2427   __ movl(eax, Immediate(magic));
2428 
2429   // EDX:EAX = magic * numerator
2430   __ imull(num);
2431 
2432   if (imm > 0 && magic < 0) {
2433     // EDX += num
2434     __ addl(edx, num);
2435   } else if (imm < 0 && magic > 0) {
2436     __ subl(edx, num);
2437   }
2438 
2439   // Shift if needed.
2440   if (shift != 0) {
2441     __ sarl(edx, Immediate(shift));
2442   }
2443 
2444   // EDX += 1 if EDX < 0
2445   __ movl(eax, edx);
2446   __ shrl(edx, Immediate(31));
2447   __ addl(edx, eax);
2448 
2449   if (instruction->IsRem()) {
2450     __ movl(eax, num);
2451     __ imull(edx, Immediate(imm));
2452     __ subl(eax, edx);
2453     __ movl(edx, eax);
2454   } else {
2455     __ movl(eax, edx);
2456   }
2457   __ Bind(&end);
2458 }
2459 
GenerateDivRemIntegral(HBinaryOperation * instruction)2460 void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2461   DCHECK(instruction->IsDiv() || instruction->IsRem());
2462 
2463   LocationSummary* locations = instruction->GetLocations();
2464   Location out = locations->Out();
2465   Location first = locations->InAt(0);
2466   Location second = locations->InAt(1);
2467   bool is_div = instruction->IsDiv();
2468 
2469   switch (instruction->GetResultType()) {
2470     case Primitive::kPrimInt: {
2471       DCHECK_EQ(EAX, first.AsRegister<Register>());
2472       DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
2473 
2474       if (instruction->InputAt(1)->IsIntConstant()) {
2475         int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2476 
2477         if (imm == 0) {
2478           // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2479         } else if (imm == 1 || imm == -1) {
2480           DivRemOneOrMinusOne(instruction);
2481         } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
2482           DivByPowerOfTwo(instruction->AsDiv());
2483         } else {
2484           DCHECK(imm <= -2 || imm >= 2);
2485           GenerateDivRemWithAnyConstant(instruction);
2486         }
2487       } else {
2488         SlowPathCodeX86* slow_path =
2489           new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
2490               is_div);
2491         codegen_->AddSlowPath(slow_path);
2492 
2493         Register second_reg = second.AsRegister<Register>();
2494         // 0x80000000/-1 triggers an arithmetic exception!
2495         // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2496         // it's safe to just use negl instead of more complex comparisons.
2497 
2498         __ cmpl(second_reg, Immediate(-1));
2499         __ j(kEqual, slow_path->GetEntryLabel());
2500 
2501         // edx:eax <- sign-extended of eax
2502         __ cdq();
2503         // eax = quotient, edx = remainder
2504         __ idivl(second_reg);
2505         __ Bind(slow_path->GetExitLabel());
2506       }
2507       break;
2508     }
2509 
2510     case Primitive::kPrimLong: {
2511       InvokeRuntimeCallingConvention calling_convention;
2512       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2513       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2514       DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2515       DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2516       DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2517       DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2518 
2519       if (is_div) {
2520         __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2521       } else {
2522         __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2523       }
2524       uint32_t dex_pc = is_div
2525           ? instruction->AsDiv()->GetDexPc()
2526           : instruction->AsRem()->GetDexPc();
2527       codegen_->RecordPcInfo(instruction, dex_pc);
2528 
2529       break;
2530     }
2531 
2532     default:
2533       LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2534   }
2535 }
2536 
VisitDiv(HDiv * div)2537 void LocationsBuilderX86::VisitDiv(HDiv* div) {
2538   LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
2539       ? LocationSummary::kCall
2540       : LocationSummary::kNoCall;
2541   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2542 
2543   switch (div->GetResultType()) {
2544     case Primitive::kPrimInt: {
2545       locations->SetInAt(0, Location::RegisterLocation(EAX));
2546       locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2547       locations->SetOut(Location::SameAsFirstInput());
2548       // Intel uses edx:eax as the dividend.
2549       locations->AddTemp(Location::RegisterLocation(EDX));
2550       // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2551       // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
2552       // output and request another temp.
2553       if (div->InputAt(1)->IsIntConstant()) {
2554         locations->AddTemp(Location::RequiresRegister());
2555       }
2556       break;
2557     }
2558     case Primitive::kPrimLong: {
2559       InvokeRuntimeCallingConvention calling_convention;
2560       locations->SetInAt(0, Location::RegisterPairLocation(
2561           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2562       locations->SetInAt(1, Location::RegisterPairLocation(
2563           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2564       // Runtime helper puts the result in EAX, EDX.
2565       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2566       break;
2567     }
2568     case Primitive::kPrimFloat:
2569     case Primitive::kPrimDouble: {
2570       locations->SetInAt(0, Location::RequiresFpuRegister());
2571       locations->SetInAt(1, Location::RequiresFpuRegister());
2572       locations->SetOut(Location::SameAsFirstInput());
2573       break;
2574     }
2575 
2576     default:
2577       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2578   }
2579 }
2580 
VisitDiv(HDiv * div)2581 void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2582   LocationSummary* locations = div->GetLocations();
2583   Location out = locations->Out();
2584   Location first = locations->InAt(0);
2585   Location second = locations->InAt(1);
2586 
2587   switch (div->GetResultType()) {
2588     case Primitive::kPrimInt:
2589     case Primitive::kPrimLong: {
2590       GenerateDivRemIntegral(div);
2591       break;
2592     }
2593 
2594     case Primitive::kPrimFloat: {
2595       DCHECK(first.Equals(out));
2596       __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2597       break;
2598     }
2599 
2600     case Primitive::kPrimDouble: {
2601       DCHECK(first.Equals(out));
2602       __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2603       break;
2604     }
2605 
2606     default:
2607       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2608   }
2609 }
2610 
VisitRem(HRem * rem)2611 void LocationsBuilderX86::VisitRem(HRem* rem) {
2612   Primitive::Type type = rem->GetResultType();
2613 
2614   LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2615       ? LocationSummary::kCall
2616       : LocationSummary::kNoCall;
2617   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2618 
2619   switch (type) {
2620     case Primitive::kPrimInt: {
2621       locations->SetInAt(0, Location::RegisterLocation(EAX));
2622       locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2623       locations->SetOut(Location::RegisterLocation(EDX));
2624       // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2625       // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
2626       // output and request another temp.
2627       if (rem->InputAt(1)->IsIntConstant()) {
2628         locations->AddTemp(Location::RequiresRegister());
2629       }
2630       break;
2631     }
2632     case Primitive::kPrimLong: {
2633       InvokeRuntimeCallingConvention calling_convention;
2634       locations->SetInAt(0, Location::RegisterPairLocation(
2635           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2636       locations->SetInAt(1, Location::RegisterPairLocation(
2637           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2638       // Runtime helper puts the result in EAX, EDX.
2639       locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2640       break;
2641     }
2642     case Primitive::kPrimDouble:
2643     case Primitive::kPrimFloat: {
2644       locations->SetInAt(0, Location::Any());
2645       locations->SetInAt(1, Location::Any());
2646       locations->SetOut(Location::RequiresFpuRegister());
2647       locations->AddTemp(Location::RegisterLocation(EAX));
2648       break;
2649     }
2650 
2651     default:
2652       LOG(FATAL) << "Unexpected rem type " << type;
2653   }
2654 }
2655 
VisitRem(HRem * rem)2656 void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2657   Primitive::Type type = rem->GetResultType();
2658   switch (type) {
2659     case Primitive::kPrimInt:
2660     case Primitive::kPrimLong: {
2661       GenerateDivRemIntegral(rem);
2662       break;
2663     }
2664     case Primitive::kPrimFloat:
2665     case Primitive::kPrimDouble: {
2666       GenerateRemFP(rem);
2667       break;
2668     }
2669     default:
2670       LOG(FATAL) << "Unexpected rem type " << type;
2671   }
2672 }
2673 
VisitDivZeroCheck(HDivZeroCheck * instruction)2674 void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2675   LocationSummary* locations =
2676       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2677   switch (instruction->GetType()) {
2678     case Primitive::kPrimInt: {
2679       locations->SetInAt(0, Location::Any());
2680       break;
2681     }
2682     case Primitive::kPrimLong: {
2683       locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2684       if (!instruction->IsConstant()) {
2685         locations->AddTemp(Location::RequiresRegister());
2686       }
2687       break;
2688     }
2689     default:
2690       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2691   }
2692   if (instruction->HasUses()) {
2693     locations->SetOut(Location::SameAsFirstInput());
2694   }
2695 }
2696 
VisitDivZeroCheck(HDivZeroCheck * instruction)2697 void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2698   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2699   codegen_->AddSlowPath(slow_path);
2700 
2701   LocationSummary* locations = instruction->GetLocations();
2702   Location value = locations->InAt(0);
2703 
2704   switch (instruction->GetType()) {
2705     case Primitive::kPrimInt: {
2706       if (value.IsRegister()) {
2707         __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
2708         __ j(kEqual, slow_path->GetEntryLabel());
2709       } else if (value.IsStackSlot()) {
2710         __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2711         __ j(kEqual, slow_path->GetEntryLabel());
2712       } else {
2713         DCHECK(value.IsConstant()) << value;
2714         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2715         __ jmp(slow_path->GetEntryLabel());
2716         }
2717       }
2718       break;
2719     }
2720     case Primitive::kPrimLong: {
2721       if (value.IsRegisterPair()) {
2722         Register temp = locations->GetTemp(0).AsRegister<Register>();
2723         __ movl(temp, value.AsRegisterPairLow<Register>());
2724         __ orl(temp, value.AsRegisterPairHigh<Register>());
2725         __ j(kEqual, slow_path->GetEntryLabel());
2726       } else {
2727         DCHECK(value.IsConstant()) << value;
2728         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2729           __ jmp(slow_path->GetEntryLabel());
2730         }
2731       }
2732       break;
2733     }
2734     default:
2735       LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
2736   }
2737 }
2738 
HandleShift(HBinaryOperation * op)2739 void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2740   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2741 
2742   LocationSummary* locations =
2743       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2744 
2745   switch (op->GetResultType()) {
2746     case Primitive::kPrimInt:
2747     case Primitive::kPrimLong: {
2748       // Can't have Location::Any() and output SameAsFirstInput()
2749       locations->SetInAt(0, Location::RequiresRegister());
2750       // The shift count needs to be in CL or a constant.
2751       locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2752       locations->SetOut(Location::SameAsFirstInput());
2753       break;
2754     }
2755     default:
2756       LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2757   }
2758 }
2759 
HandleShift(HBinaryOperation * op)2760 void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2761   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2762 
2763   LocationSummary* locations = op->GetLocations();
2764   Location first = locations->InAt(0);
2765   Location second = locations->InAt(1);
2766   DCHECK(first.Equals(locations->Out()));
2767 
2768   switch (op->GetResultType()) {
2769     case Primitive::kPrimInt: {
2770       DCHECK(first.IsRegister());
2771       Register first_reg = first.AsRegister<Register>();
2772       if (second.IsRegister()) {
2773         Register second_reg = second.AsRegister<Register>();
2774         DCHECK_EQ(ECX, second_reg);
2775         if (op->IsShl()) {
2776           __ shll(first_reg, second_reg);
2777         } else if (op->IsShr()) {
2778           __ sarl(first_reg, second_reg);
2779         } else {
2780           __ shrl(first_reg, second_reg);
2781         }
2782       } else {
2783         int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
2784         if (shift == 0) {
2785           return;
2786         }
2787         Immediate imm(shift);
2788         if (op->IsShl()) {
2789           __ shll(first_reg, imm);
2790         } else if (op->IsShr()) {
2791           __ sarl(first_reg, imm);
2792         } else {
2793           __ shrl(first_reg, imm);
2794         }
2795       }
2796       break;
2797     }
2798     case Primitive::kPrimLong: {
2799       if (second.IsRegister()) {
2800         Register second_reg = second.AsRegister<Register>();
2801         DCHECK_EQ(ECX, second_reg);
2802         if (op->IsShl()) {
2803           GenerateShlLong(first, second_reg);
2804         } else if (op->IsShr()) {
2805           GenerateShrLong(first, second_reg);
2806         } else {
2807           GenerateUShrLong(first, second_reg);
2808         }
2809       } else {
2810         // Shift by a constant.
2811         int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
2812         // Nothing to do if the shift is 0, as the input is already the output.
2813         if (shift != 0) {
2814           if (op->IsShl()) {
2815             GenerateShlLong(first, shift);
2816           } else if (op->IsShr()) {
2817             GenerateShrLong(first, shift);
2818           } else {
2819             GenerateUShrLong(first, shift);
2820           }
2821         }
2822       }
2823       break;
2824     }
2825     default:
2826       LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2827   }
2828 }
2829 
GenerateShlLong(const Location & loc,int shift)2830 void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
2831   Register low = loc.AsRegisterPairLow<Register>();
2832   Register high = loc.AsRegisterPairHigh<Register>();
2833   if (shift == 1) {
2834     // This is just an addition.
2835     __ addl(low, low);
2836     __ adcl(high, high);
2837   } else if (shift == 32) {
2838     // Shift by 32 is easy. High gets low, and low gets 0.
2839     codegen_->EmitParallelMoves(
2840         loc.ToLow(),
2841         loc.ToHigh(),
2842         Primitive::kPrimInt,
2843         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
2844         loc.ToLow(),
2845         Primitive::kPrimInt);
2846   } else if (shift > 32) {
2847     // Low part becomes 0.  High part is low part << (shift-32).
2848     __ movl(high, low);
2849     __ shll(high, Immediate(shift - 32));
2850     __ xorl(low, low);
2851   } else {
2852     // Between 1 and 31.
2853     __ shld(high, low, Immediate(shift));
2854     __ shll(low, Immediate(shift));
2855   }
2856 }
2857 
GenerateShlLong(const Location & loc,Register shifter)2858 void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2859   Label done;
2860   __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2861   __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2862   __ testl(shifter, Immediate(32));
2863   __ j(kEqual, &done);
2864   __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2865   __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2866   __ Bind(&done);
2867 }
2868 
GenerateShrLong(const Location & loc,int shift)2869 void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
2870   Register low = loc.AsRegisterPairLow<Register>();
2871   Register high = loc.AsRegisterPairHigh<Register>();
2872   if (shift == 32) {
2873     // Need to copy the sign.
2874     DCHECK_NE(low, high);
2875     __ movl(low, high);
2876     __ sarl(high, Immediate(31));
2877   } else if (shift > 32) {
2878     DCHECK_NE(low, high);
2879     // High part becomes sign. Low part is shifted by shift - 32.
2880     __ movl(low, high);
2881     __ sarl(high, Immediate(31));
2882     __ sarl(low, Immediate(shift - 32));
2883   } else {
2884     // Between 1 and 31.
2885     __ shrd(low, high, Immediate(shift));
2886     __ sarl(high, Immediate(shift));
2887   }
2888 }
2889 
GenerateShrLong(const Location & loc,Register shifter)2890 void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2891   Label done;
2892   __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2893   __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2894   __ testl(shifter, Immediate(32));
2895   __ j(kEqual, &done);
2896   __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2897   __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2898   __ Bind(&done);
2899 }
2900 
GenerateUShrLong(const Location & loc,int shift)2901 void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
2902   Register low = loc.AsRegisterPairLow<Register>();
2903   Register high = loc.AsRegisterPairHigh<Register>();
2904   if (shift == 32) {
2905     // Shift by 32 is easy. Low gets high, and high gets 0.
2906     codegen_->EmitParallelMoves(
2907         loc.ToHigh(),
2908         loc.ToLow(),
2909         Primitive::kPrimInt,
2910         Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
2911         loc.ToHigh(),
2912         Primitive::kPrimInt);
2913   } else if (shift > 32) {
2914     // Low part is high >> (shift - 32). High part becomes 0.
2915     __ movl(low, high);
2916     __ shrl(low, Immediate(shift - 32));
2917     __ xorl(high, high);
2918   } else {
2919     // Between 1 and 31.
2920     __ shrd(low, high, Immediate(shift));
2921     __ shrl(high, Immediate(shift));
2922   }
2923 }
2924 
GenerateUShrLong(const Location & loc,Register shifter)2925 void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2926   Label done;
2927   __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2928   __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2929   __ testl(shifter, Immediate(32));
2930   __ j(kEqual, &done);
2931   __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2932   __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2933   __ Bind(&done);
2934 }
2935 
VisitShl(HShl * shl)2936 void LocationsBuilderX86::VisitShl(HShl* shl) {
2937   HandleShift(shl);
2938 }
2939 
VisitShl(HShl * shl)2940 void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2941   HandleShift(shl);
2942 }
2943 
VisitShr(HShr * shr)2944 void LocationsBuilderX86::VisitShr(HShr* shr) {
2945   HandleShift(shr);
2946 }
2947 
VisitShr(HShr * shr)2948 void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2949   HandleShift(shr);
2950 }
2951 
VisitUShr(HUShr * ushr)2952 void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2953   HandleShift(ushr);
2954 }
2955 
VisitUShr(HUShr * ushr)2956 void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2957   HandleShift(ushr);
2958 }
2959 
VisitNewInstance(HNewInstance * instruction)2960 void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
2961   LocationSummary* locations =
2962       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2963   locations->SetOut(Location::RegisterLocation(EAX));
2964   InvokeRuntimeCallingConvention calling_convention;
2965   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2966   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2967 }
2968 
VisitNewInstance(HNewInstance * instruction)2969 void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2970   InvokeRuntimeCallingConvention calling_convention;
2971   codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
2972   __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2973 
2974   __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
2975 
2976   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2977   DCHECK(!codegen_->IsLeafMethod());
2978 }
2979 
VisitNewArray(HNewArray * instruction)2980 void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2981   LocationSummary* locations =
2982       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2983   locations->SetOut(Location::RegisterLocation(EAX));
2984   InvokeRuntimeCallingConvention calling_convention;
2985   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2986   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2987   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2988 }
2989 
VisitNewArray(HNewArray * instruction)2990 void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2991   InvokeRuntimeCallingConvention calling_convention;
2992   codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
2993   __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2994 
2995   __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
2996 
2997   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2998   DCHECK(!codegen_->IsLeafMethod());
2999 }
3000 
VisitParameterValue(HParameterValue * instruction)3001 void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
3002   LocationSummary* locations =
3003       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3004   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3005   if (location.IsStackSlot()) {
3006     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3007   } else if (location.IsDoubleStackSlot()) {
3008     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3009   }
3010   locations->SetOut(location);
3011 }
3012 
VisitParameterValue(HParameterValue * instruction)3013 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
3014   UNUSED(instruction);
3015 }
3016 
VisitNot(HNot * not_)3017 void LocationsBuilderX86::VisitNot(HNot* not_) {
3018   LocationSummary* locations =
3019       new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
3020   locations->SetInAt(0, Location::RequiresRegister());
3021   locations->SetOut(Location::SameAsFirstInput());
3022 }
3023 
VisitNot(HNot * not_)3024 void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3025   LocationSummary* locations = not_->GetLocations();
3026   Location in = locations->InAt(0);
3027   Location out = locations->Out();
3028   DCHECK(in.Equals(out));
3029   switch (not_->GetResultType()) {
3030     case Primitive::kPrimInt:
3031       __ notl(out.AsRegister<Register>());
3032       break;
3033 
3034     case Primitive::kPrimLong:
3035       __ notl(out.AsRegisterPairLow<Register>());
3036       __ notl(out.AsRegisterPairHigh<Register>());
3037       break;
3038 
3039     default:
3040       LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3041   }
3042 }
3043 
VisitBooleanNot(HBooleanNot * bool_not)3044 void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3045   LocationSummary* locations =
3046       new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3047   locations->SetInAt(0, Location::RequiresRegister());
3048   locations->SetOut(Location::SameAsFirstInput());
3049 }
3050 
VisitBooleanNot(HBooleanNot * bool_not)3051 void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
3052   LocationSummary* locations = bool_not->GetLocations();
3053   Location in = locations->InAt(0);
3054   Location out = locations->Out();
3055   DCHECK(in.Equals(out));
3056   __ xorl(out.AsRegister<Register>(), Immediate(1));
3057 }
3058 
VisitCompare(HCompare * compare)3059 void LocationsBuilderX86::VisitCompare(HCompare* compare) {
3060   LocationSummary* locations =
3061       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
3062   switch (compare->InputAt(0)->GetType()) {
3063     case Primitive::kPrimLong: {
3064       locations->SetInAt(0, Location::RequiresRegister());
3065       locations->SetInAt(1, Location::Any());
3066       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3067       break;
3068     }
3069     case Primitive::kPrimFloat:
3070     case Primitive::kPrimDouble: {
3071       locations->SetInAt(0, Location::RequiresFpuRegister());
3072       locations->SetInAt(1, Location::RequiresFpuRegister());
3073       locations->SetOut(Location::RequiresRegister());
3074       break;
3075     }
3076     default:
3077       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3078   }
3079 }
3080 
VisitCompare(HCompare * compare)3081 void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
3082   LocationSummary* locations = compare->GetLocations();
3083   Register out = locations->Out().AsRegister<Register>();
3084   Location left = locations->InAt(0);
3085   Location right = locations->InAt(1);
3086 
3087   Label less, greater, done;
3088   switch (compare->InputAt(0)->GetType()) {
3089     case Primitive::kPrimLong: {
3090       Register left_low = left.AsRegisterPairLow<Register>();
3091       Register left_high = left.AsRegisterPairHigh<Register>();
3092       int32_t val_low = 0;
3093       int32_t val_high = 0;
3094       bool right_is_const = false;
3095 
3096       if (right.IsConstant()) {
3097         DCHECK(right.GetConstant()->IsLongConstant());
3098         right_is_const = true;
3099         int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3100         val_low = Low32Bits(val);
3101         val_high = High32Bits(val);
3102       }
3103 
3104       if (right.IsRegisterPair()) {
3105         __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
3106       } else if (right.IsDoubleStackSlot()) {
3107         __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
3108       } else {
3109         DCHECK(right_is_const) << right;
3110         if (val_high == 0) {
3111           __ testl(left_high, left_high);
3112         } else {
3113           __ cmpl(left_high, Immediate(val_high));
3114         }
3115       }
3116       __ j(kLess, &less);  // Signed compare.
3117       __ j(kGreater, &greater);  // Signed compare.
3118       if (right.IsRegisterPair()) {
3119         __ cmpl(left_low, right.AsRegisterPairLow<Register>());
3120       } else if (right.IsDoubleStackSlot()) {
3121         __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
3122       } else {
3123         DCHECK(right_is_const) << right;
3124         if (val_low == 0) {
3125           __ testl(left_low, left_low);
3126         } else {
3127           __ cmpl(left_low, Immediate(val_low));
3128         }
3129       }
3130       break;
3131     }
3132     case Primitive::kPrimFloat: {
3133       __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
3134       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3135       break;
3136     }
3137     case Primitive::kPrimDouble: {
3138       __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
3139       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3140       break;
3141     }
3142     default:
3143       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3144   }
3145   __ movl(out, Immediate(0));
3146   __ j(kEqual, &done);
3147   __ j(kBelow, &less);  // kBelow is for CF (unsigned & floats).
3148 
3149   __ Bind(&greater);
3150   __ movl(out, Immediate(1));
3151   __ jmp(&done);
3152 
3153   __ Bind(&less);
3154   __ movl(out, Immediate(-1));
3155 
3156   __ Bind(&done);
3157 }
3158 
VisitPhi(HPhi * instruction)3159 void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
3160   LocationSummary* locations =
3161       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3162   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3163     locations->SetInAt(i, Location::Any());
3164   }
3165   locations->SetOut(Location::Any());
3166 }
3167 
VisitPhi(HPhi * instruction)3168 void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
3169   UNUSED(instruction);
3170   LOG(FATAL) << "Unreachable";
3171 }
3172 
GenerateMemoryBarrier(MemBarrierKind kind)3173 void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3174   /*
3175    * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3176    * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3177    * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3178    */
3179   switch (kind) {
3180     case MemBarrierKind::kAnyAny: {
3181       __ mfence();
3182       break;
3183     }
3184     case MemBarrierKind::kAnyStore:
3185     case MemBarrierKind::kLoadAny:
3186     case MemBarrierKind::kStoreStore: {
3187       // nop
3188       break;
3189     }
3190     default:
3191       LOG(FATAL) << "Unexpected memory barrier " << kind;
3192   }
3193 }
3194 
3195 
GenerateStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Register temp)3196 void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
3197                                                   Register temp) {
3198   // TODO: Implement all kinds of calls:
3199   // 1) boot -> boot
3200   // 2) app -> boot
3201   // 3) app -> app
3202   //
3203   // Currently we implement the app -> app logic, which looks up in the resolve cache.
3204 
3205   if (invoke->IsStringInit()) {
3206     // temp = thread->string_init_entrypoint
3207     __ fs()->movl(temp, Address::Absolute(invoke->GetStringInitOffset()));
3208     // (temp + offset_of_quick_compiled_code)()
3209     __ call(Address(
3210         temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3211   } else {
3212     // temp = method;
3213     LoadCurrentMethod(temp);
3214     if (!invoke->IsRecursive()) {
3215       // temp = temp->dex_cache_resolved_methods_;
3216       __ movl(temp, Address(temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
3217       // temp = temp[index_in_cache]
3218       __ movl(temp, Address(temp,
3219                             CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
3220       // (temp + offset_of_quick_compiled_code)()
3221       __ call(Address(temp,
3222           ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3223     } else {
3224       __ call(GetFrameEntryLabel());
3225     }
3226   }
3227 
3228   DCHECK(!IsLeafMethod());
3229 }
3230 
MarkGCCard(Register temp,Register card,Register object,Register value)3231 void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
3232   Label is_null;
3233   __ testl(value, value);
3234   __ j(kEqual, &is_null);
3235   __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3236   __ movl(temp, object);
3237   __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
3238   __ movb(Address(temp, card, TIMES_1, 0),
3239           X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
3240   __ Bind(&is_null);
3241 }
3242 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)3243 void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3244   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3245   LocationSummary* locations =
3246       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3247   locations->SetInAt(0, Location::RequiresRegister());
3248 
3249   if (Primitive::IsFloatingPointType(instruction->GetType())) {
3250     locations->SetOut(Location::RequiresFpuRegister());
3251   } else {
3252     // The output overlaps in case of long: we don't want the low move to overwrite
3253     // the object's location.
3254     locations->SetOut(Location::RequiresRegister(),
3255         (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3256                                                          : Location::kNoOutputOverlap);
3257   }
3258 
3259   if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3260     // Long values can be loaded atomically into an XMM using movsd.
3261     // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3262     // and then copy the XMM into the output 32bits at a time).
3263     locations->AddTemp(Location::RequiresFpuRegister());
3264   }
3265 }
3266 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)3267 void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3268                                                  const FieldInfo& field_info) {
3269   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3270 
3271   LocationSummary* locations = instruction->GetLocations();
3272   Register base = locations->InAt(0).AsRegister<Register>();
3273   Location out = locations->Out();
3274   bool is_volatile = field_info.IsVolatile();
3275   Primitive::Type field_type = field_info.GetFieldType();
3276   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3277 
3278   switch (field_type) {
3279     case Primitive::kPrimBoolean: {
3280       __ movzxb(out.AsRegister<Register>(), Address(base, offset));
3281       break;
3282     }
3283 
3284     case Primitive::kPrimByte: {
3285       __ movsxb(out.AsRegister<Register>(), Address(base, offset));
3286       break;
3287     }
3288 
3289     case Primitive::kPrimShort: {
3290       __ movsxw(out.AsRegister<Register>(), Address(base, offset));
3291       break;
3292     }
3293 
3294     case Primitive::kPrimChar: {
3295       __ movzxw(out.AsRegister<Register>(), Address(base, offset));
3296       break;
3297     }
3298 
3299     case Primitive::kPrimInt:
3300     case Primitive::kPrimNot: {
3301       __ movl(out.AsRegister<Register>(), Address(base, offset));
3302       break;
3303     }
3304 
3305     case Primitive::kPrimLong: {
3306       if (is_volatile) {
3307         XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3308         __ movsd(temp, Address(base, offset));
3309         codegen_->MaybeRecordImplicitNullCheck(instruction);
3310         __ movd(out.AsRegisterPairLow<Register>(), temp);
3311         __ psrlq(temp, Immediate(32));
3312         __ movd(out.AsRegisterPairHigh<Register>(), temp);
3313       } else {
3314         DCHECK_NE(base, out.AsRegisterPairLow<Register>());
3315         __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
3316         codegen_->MaybeRecordImplicitNullCheck(instruction);
3317         __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3318       }
3319       break;
3320     }
3321 
3322     case Primitive::kPrimFloat: {
3323       __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3324       break;
3325     }
3326 
3327     case Primitive::kPrimDouble: {
3328       __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3329       break;
3330     }
3331 
3332     case Primitive::kPrimVoid:
3333       LOG(FATAL) << "Unreachable type " << field_type;
3334       UNREACHABLE();
3335   }
3336 
3337   // Longs are handled in the switch.
3338   if (field_type != Primitive::kPrimLong) {
3339     codegen_->MaybeRecordImplicitNullCheck(instruction);
3340   }
3341 
3342   if (is_volatile) {
3343     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3344   }
3345 }
3346 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info)3347 void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3348   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3349 
3350   LocationSummary* locations =
3351       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3352   locations->SetInAt(0, Location::RequiresRegister());
3353   bool is_volatile = field_info.IsVolatile();
3354   Primitive::Type field_type = field_info.GetFieldType();
3355   bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3356     || (field_type == Primitive::kPrimByte);
3357 
3358   // The register allocator does not support multiple
3359   // inputs that die at entry with one in a specific register.
3360   if (is_byte_type) {
3361     // Ensure the value is in a byte register.
3362     locations->SetInAt(1, Location::RegisterLocation(EAX));
3363   } else if (Primitive::IsFloatingPointType(field_type)) {
3364     locations->SetInAt(1, Location::RequiresFpuRegister());
3365   } else {
3366     locations->SetInAt(1, Location::RequiresRegister());
3367   }
3368   // Temporary registers for the write barrier.
3369   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3370     locations->AddTemp(Location::RequiresRegister());
3371     // Ensure the card is in a byte register.
3372     locations->AddTemp(Location::RegisterLocation(ECX));
3373   } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3374     // 64bits value can be atomically written to an address with movsd and an XMM register.
3375     // We need two XMM registers because there's no easier way to (bit) copy a register pair
3376     // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3377     // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3378     // isolated cases when we need this it isn't worth adding the extra complexity.
3379     locations->AddTemp(Location::RequiresFpuRegister());
3380     locations->AddTemp(Location::RequiresFpuRegister());
3381   }
3382 }
3383 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info)3384 void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
3385                                                  const FieldInfo& field_info) {
3386   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3387 
3388   LocationSummary* locations = instruction->GetLocations();
3389   Register base = locations->InAt(0).AsRegister<Register>();
3390   Location value = locations->InAt(1);
3391   bool is_volatile = field_info.IsVolatile();
3392   Primitive::Type field_type = field_info.GetFieldType();
3393   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3394 
3395   if (is_volatile) {
3396     GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3397   }
3398 
3399   switch (field_type) {
3400     case Primitive::kPrimBoolean:
3401     case Primitive::kPrimByte: {
3402       __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3403       break;
3404     }
3405 
3406     case Primitive::kPrimShort:
3407     case Primitive::kPrimChar: {
3408       __ movw(Address(base, offset), value.AsRegister<Register>());
3409       break;
3410     }
3411 
3412     case Primitive::kPrimInt:
3413     case Primitive::kPrimNot: {
3414       __ movl(Address(base, offset), value.AsRegister<Register>());
3415       break;
3416     }
3417 
3418     case Primitive::kPrimLong: {
3419       if (is_volatile) {
3420         XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3421         XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3422         __ movd(temp1, value.AsRegisterPairLow<Register>());
3423         __ movd(temp2, value.AsRegisterPairHigh<Register>());
3424         __ punpckldq(temp1, temp2);
3425         __ movsd(Address(base, offset), temp1);
3426         codegen_->MaybeRecordImplicitNullCheck(instruction);
3427       } else {
3428         __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
3429         codegen_->MaybeRecordImplicitNullCheck(instruction);
3430         __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3431       }
3432       break;
3433     }
3434 
3435     case Primitive::kPrimFloat: {
3436       __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3437       break;
3438     }
3439 
3440     case Primitive::kPrimDouble: {
3441       __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3442       break;
3443     }
3444 
3445     case Primitive::kPrimVoid:
3446       LOG(FATAL) << "Unreachable type " << field_type;
3447       UNREACHABLE();
3448   }
3449 
3450   // Longs are handled in the switch.
3451   if (field_type != Primitive::kPrimLong) {
3452     codegen_->MaybeRecordImplicitNullCheck(instruction);
3453   }
3454 
3455   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3456     Register temp = locations->GetTemp(0).AsRegister<Register>();
3457     Register card = locations->GetTemp(1).AsRegister<Register>();
3458     codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
3459   }
3460 
3461   if (is_volatile) {
3462     GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3463   }
3464 }
3465 
VisitStaticFieldGet(HStaticFieldGet * instruction)3466 void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3467   HandleFieldGet(instruction, instruction->GetFieldInfo());
3468 }
3469 
VisitStaticFieldGet(HStaticFieldGet * instruction)3470 void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3471   HandleFieldGet(instruction, instruction->GetFieldInfo());
3472 }
3473 
VisitStaticFieldSet(HStaticFieldSet * instruction)3474 void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3475   HandleFieldSet(instruction, instruction->GetFieldInfo());
3476 }
3477 
VisitStaticFieldSet(HStaticFieldSet * instruction)3478 void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3479   HandleFieldSet(instruction, instruction->GetFieldInfo());
3480 }
3481 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)3482 void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3483   HandleFieldSet(instruction, instruction->GetFieldInfo());
3484 }
3485 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)3486 void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3487   HandleFieldSet(instruction, instruction->GetFieldInfo());
3488 }
3489 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)3490 void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3491   HandleFieldGet(instruction, instruction->GetFieldInfo());
3492 }
3493 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)3494 void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3495   HandleFieldGet(instruction, instruction->GetFieldInfo());
3496 }
3497 
VisitNullCheck(HNullCheck * instruction)3498 void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
3499   LocationSummary* locations =
3500       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3501   Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3502       ? Location::RequiresRegister()
3503       : Location::Any();
3504   locations->SetInAt(0, loc);
3505   if (instruction->HasUses()) {
3506     locations->SetOut(Location::SameAsFirstInput());
3507   }
3508 }
3509 
GenerateImplicitNullCheck(HNullCheck * instruction)3510 void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
3511   if (codegen_->CanMoveNullCheckToUser(instruction)) {
3512     return;
3513   }
3514   LocationSummary* locations = instruction->GetLocations();
3515   Location obj = locations->InAt(0);
3516 
3517   __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3518   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3519 }
3520 
GenerateExplicitNullCheck(HNullCheck * instruction)3521 void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
3522   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
3523   codegen_->AddSlowPath(slow_path);
3524 
3525   LocationSummary* locations = instruction->GetLocations();
3526   Location obj = locations->InAt(0);
3527 
3528   if (obj.IsRegister()) {
3529     __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
3530   } else if (obj.IsStackSlot()) {
3531     __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
3532   } else {
3533     DCHECK(obj.IsConstant()) << obj;
3534     DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3535     __ jmp(slow_path->GetEntryLabel());
3536     return;
3537   }
3538   __ j(kEqual, slow_path->GetEntryLabel());
3539 }
3540 
VisitNullCheck(HNullCheck * instruction)3541 void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3542   if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3543     GenerateImplicitNullCheck(instruction);
3544   } else {
3545     GenerateExplicitNullCheck(instruction);
3546   }
3547 }
3548 
VisitArrayGet(HArrayGet * instruction)3549 void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
3550   LocationSummary* locations =
3551       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3552   locations->SetInAt(0, Location::RequiresRegister());
3553   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3554   if (Primitive::IsFloatingPointType(instruction->GetType())) {
3555     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3556   } else {
3557     // The output overlaps in case of long: we don't want the low move to overwrite
3558     // the array's location.
3559     locations->SetOut(Location::RequiresRegister(),
3560         (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3561                                                          : Location::kNoOutputOverlap);
3562   }
3563 }
3564 
VisitArrayGet(HArrayGet * instruction)3565 void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3566   LocationSummary* locations = instruction->GetLocations();
3567   Register obj = locations->InAt(0).AsRegister<Register>();
3568   Location index = locations->InAt(1);
3569 
3570   Primitive::Type type = instruction->GetType();
3571   switch (type) {
3572     case Primitive::kPrimBoolean: {
3573       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
3574       Register out = locations->Out().AsRegister<Register>();
3575       if (index.IsConstant()) {
3576         __ movzxb(out, Address(obj,
3577             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3578       } else {
3579         __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
3580       }
3581       break;
3582     }
3583 
3584     case Primitive::kPrimByte: {
3585       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
3586       Register out = locations->Out().AsRegister<Register>();
3587       if (index.IsConstant()) {
3588         __ movsxb(out, Address(obj,
3589             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3590       } else {
3591         __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
3592       }
3593       break;
3594     }
3595 
3596     case Primitive::kPrimShort: {
3597       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
3598       Register out = locations->Out().AsRegister<Register>();
3599       if (index.IsConstant()) {
3600         __ movsxw(out, Address(obj,
3601             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3602       } else {
3603         __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
3604       }
3605       break;
3606     }
3607 
3608     case Primitive::kPrimChar: {
3609       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
3610       Register out = locations->Out().AsRegister<Register>();
3611       if (index.IsConstant()) {
3612         __ movzxw(out, Address(obj,
3613             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3614       } else {
3615         __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
3616       }
3617       break;
3618     }
3619 
3620     case Primitive::kPrimInt:
3621     case Primitive::kPrimNot: {
3622       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3623       Register out = locations->Out().AsRegister<Register>();
3624       if (index.IsConstant()) {
3625         __ movl(out, Address(obj,
3626             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3627       } else {
3628         __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3629       }
3630       break;
3631     }
3632 
3633     case Primitive::kPrimLong: {
3634       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
3635       Location out = locations->Out();
3636       DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
3637       if (index.IsConstant()) {
3638         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3639         __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
3640         codegen_->MaybeRecordImplicitNullCheck(instruction);
3641         __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
3642       } else {
3643         __ movl(out.AsRegisterPairLow<Register>(),
3644                 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3645         codegen_->MaybeRecordImplicitNullCheck(instruction);
3646         __ movl(out.AsRegisterPairHigh<Register>(),
3647                 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
3648       }
3649       break;
3650     }
3651 
3652     case Primitive::kPrimFloat: {
3653       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3654       XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3655       if (index.IsConstant()) {
3656         __ movss(out, Address(obj,
3657             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3658       } else {
3659         __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3660       }
3661       break;
3662     }
3663 
3664     case Primitive::kPrimDouble: {
3665       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3666       XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3667       if (index.IsConstant()) {
3668         __ movsd(out, Address(obj,
3669             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3670       } else {
3671         __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3672       }
3673       break;
3674     }
3675 
3676     case Primitive::kPrimVoid:
3677       LOG(FATAL) << "Unreachable type " << type;
3678       UNREACHABLE();
3679   }
3680 
3681   if (type != Primitive::kPrimLong) {
3682     codegen_->MaybeRecordImplicitNullCheck(instruction);
3683   }
3684 }
3685 
VisitArraySet(HArraySet * instruction)3686 void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
3687   // This location builder might end up asking to up to four registers, which is
3688   // not currently possible for baseline. The situation in which we need four
3689   // registers cannot be met by baseline though, because it has not run any
3690   // optimization.
3691 
3692   Primitive::Type value_type = instruction->GetComponentType();
3693   bool needs_write_barrier =
3694       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3695 
3696   bool needs_runtime_call = instruction->NeedsTypeCheck();
3697 
3698   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3699       instruction,
3700       needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3701 
3702   if (needs_runtime_call) {
3703     InvokeRuntimeCallingConvention calling_convention;
3704     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3705     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3706     locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3707   } else {
3708     bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3709         || (value_type == Primitive::kPrimByte);
3710     // We need the inputs to be different than the output in case of long operation.
3711     // In case of a byte operation, the register allocator does not support multiple
3712     // inputs that die at entry with one in a specific register.
3713     locations->SetInAt(0, Location::RequiresRegister());
3714     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3715     if (is_byte_type) {
3716       // Ensure the value is in a byte register.
3717       locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
3718     } else if (Primitive::IsFloatingPointType(value_type)) {
3719       locations->SetInAt(2, Location::RequiresFpuRegister());
3720     } else {
3721       locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
3722     }
3723     // Temporary registers for the write barrier.
3724     if (needs_write_barrier) {
3725       locations->AddTemp(Location::RequiresRegister());
3726       // Ensure the card is in a byte register.
3727       locations->AddTemp(Location::RegisterLocation(ECX));
3728     }
3729   }
3730 }
3731 
VisitArraySet(HArraySet * instruction)3732 void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3733   LocationSummary* locations = instruction->GetLocations();
3734   Register obj = locations->InAt(0).AsRegister<Register>();
3735   Location index = locations->InAt(1);
3736   Location value = locations->InAt(2);
3737   Primitive::Type value_type = instruction->GetComponentType();
3738   bool needs_runtime_call = locations->WillCall();
3739   bool needs_write_barrier =
3740       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3741 
3742   switch (value_type) {
3743     case Primitive::kPrimBoolean:
3744     case Primitive::kPrimByte: {
3745       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
3746       if (index.IsConstant()) {
3747         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
3748         if (value.IsRegister()) {
3749           __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
3750         } else {
3751           __ movb(Address(obj, offset),
3752                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3753         }
3754       } else {
3755         if (value.IsRegister()) {
3756           __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
3757                   value.AsRegister<ByteRegister>());
3758         } else {
3759           __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
3760                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3761         }
3762       }
3763       codegen_->MaybeRecordImplicitNullCheck(instruction);
3764       break;
3765     }
3766 
3767     case Primitive::kPrimShort:
3768     case Primitive::kPrimChar: {
3769       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
3770       if (index.IsConstant()) {
3771         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
3772         if (value.IsRegister()) {
3773           __ movw(Address(obj, offset), value.AsRegister<Register>());
3774         } else {
3775           __ movw(Address(obj, offset),
3776                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3777         }
3778       } else {
3779         if (value.IsRegister()) {
3780           __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3781                   value.AsRegister<Register>());
3782         } else {
3783           __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3784                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3785         }
3786       }
3787       codegen_->MaybeRecordImplicitNullCheck(instruction);
3788       break;
3789     }
3790 
3791     case Primitive::kPrimInt:
3792     case Primitive::kPrimNot: {
3793       if (!needs_runtime_call) {
3794         uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3795         if (index.IsConstant()) {
3796           size_t offset =
3797               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3798           if (value.IsRegister()) {
3799             __ movl(Address(obj, offset), value.AsRegister<Register>());
3800           } else {
3801             DCHECK(value.IsConstant()) << value;
3802             __ movl(Address(obj, offset),
3803                     Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3804           }
3805         } else {
3806           DCHECK(index.IsRegister()) << index;
3807           if (value.IsRegister()) {
3808             __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3809                     value.AsRegister<Register>());
3810           } else {
3811             DCHECK(value.IsConstant()) << value;
3812             __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3813                     Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3814           }
3815         }
3816         codegen_->MaybeRecordImplicitNullCheck(instruction);
3817 
3818         if (needs_write_barrier) {
3819           Register temp = locations->GetTemp(0).AsRegister<Register>();
3820           Register card = locations->GetTemp(1).AsRegister<Register>();
3821           codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
3822         }
3823       } else {
3824         DCHECK_EQ(value_type, Primitive::kPrimNot);
3825         DCHECK(!codegen_->IsLeafMethod());
3826         __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3827         codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3828       }
3829       break;
3830     }
3831 
3832     case Primitive::kPrimLong: {
3833       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
3834       if (index.IsConstant()) {
3835         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3836         if (value.IsRegisterPair()) {
3837           __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
3838           codegen_->MaybeRecordImplicitNullCheck(instruction);
3839           __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
3840         } else {
3841           DCHECK(value.IsConstant());
3842           int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3843           __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
3844           codegen_->MaybeRecordImplicitNullCheck(instruction);
3845           __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3846         }
3847       } else {
3848         if (value.IsRegisterPair()) {
3849           __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3850                   value.AsRegisterPairLow<Register>());
3851           codegen_->MaybeRecordImplicitNullCheck(instruction);
3852           __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
3853                   value.AsRegisterPairHigh<Register>());
3854         } else {
3855           DCHECK(value.IsConstant());
3856           int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3857           __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3858                   Immediate(Low32Bits(val)));
3859           codegen_->MaybeRecordImplicitNullCheck(instruction);
3860           __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
3861                   Immediate(High32Bits(val)));
3862         }
3863       }
3864       break;
3865     }
3866 
3867     case Primitive::kPrimFloat: {
3868       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3869       DCHECK(value.IsFpuRegister());
3870       if (index.IsConstant()) {
3871         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3872         __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3873       } else {
3874         __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3875                 value.AsFpuRegister<XmmRegister>());
3876       }
3877       break;
3878     }
3879 
3880     case Primitive::kPrimDouble: {
3881       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3882       DCHECK(value.IsFpuRegister());
3883       if (index.IsConstant()) {
3884         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3885         __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3886       } else {
3887         __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3888                 value.AsFpuRegister<XmmRegister>());
3889       }
3890       break;
3891     }
3892 
3893     case Primitive::kPrimVoid:
3894       LOG(FATAL) << "Unreachable type " << instruction->GetType();
3895       UNREACHABLE();
3896   }
3897 }
3898 
VisitArrayLength(HArrayLength * instruction)3899 void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3900   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
3901   locations->SetInAt(0, Location::RequiresRegister());
3902   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3903   instruction->SetLocations(locations);
3904 }
3905 
VisitArrayLength(HArrayLength * instruction)3906 void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3907   LocationSummary* locations = instruction->GetLocations();
3908   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
3909   Register obj = locations->InAt(0).AsRegister<Register>();
3910   Register out = locations->Out().AsRegister<Register>();
3911   __ movl(out, Address(obj, offset));
3912   codegen_->MaybeRecordImplicitNullCheck(instruction);
3913 }
3914 
VisitBoundsCheck(HBoundsCheck * instruction)3915 void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3916   LocationSummary* locations =
3917       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3918   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3919   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3920   if (instruction->HasUses()) {
3921     locations->SetOut(Location::SameAsFirstInput());
3922   }
3923 }
3924 
VisitBoundsCheck(HBoundsCheck * instruction)3925 void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3926   LocationSummary* locations = instruction->GetLocations();
3927   Location index_loc = locations->InAt(0);
3928   Location length_loc = locations->InAt(1);
3929   SlowPathCodeX86* slow_path =
3930     new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
3931 
3932   if (length_loc.IsConstant()) {
3933     int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3934     if (index_loc.IsConstant()) {
3935       // BCE will remove the bounds check if we are guarenteed to pass.
3936       int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3937       if (index < 0 || index >= length) {
3938         codegen_->AddSlowPath(slow_path);
3939         __ jmp(slow_path->GetEntryLabel());
3940       } else {
3941         // Some optimization after BCE may have generated this, and we should not
3942         // generate a bounds check if it is a valid range.
3943       }
3944       return;
3945     }
3946 
3947     // We have to reverse the jump condition because the length is the constant.
3948     Register index_reg = index_loc.AsRegister<Register>();
3949     __ cmpl(index_reg, Immediate(length));
3950     codegen_->AddSlowPath(slow_path);
3951     __ j(kAboveEqual, slow_path->GetEntryLabel());
3952   } else {
3953     Register length = length_loc.AsRegister<Register>();
3954     if (index_loc.IsConstant()) {
3955       int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3956       __ cmpl(length, Immediate(value));
3957     } else {
3958       __ cmpl(length, index_loc.AsRegister<Register>());
3959     }
3960     codegen_->AddSlowPath(slow_path);
3961     __ j(kBelowEqual, slow_path->GetEntryLabel());
3962   }
3963 }
3964 
VisitTemporary(HTemporary * temp)3965 void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3966   temp->SetLocations(nullptr);
3967 }
3968 
VisitTemporary(HTemporary * temp)3969 void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3970   // Nothing to do, this is driven by the code generator.
3971   UNUSED(temp);
3972 }
3973 
VisitParallelMove(HParallelMove * instruction)3974 void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
3975   UNUSED(instruction);
3976   LOG(FATAL) << "Unreachable";
3977 }
3978 
VisitParallelMove(HParallelMove * instruction)3979 void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
3980   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3981 }
3982 
VisitSuspendCheck(HSuspendCheck * instruction)3983 void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3984   new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3985 }
3986 
VisitSuspendCheck(HSuspendCheck * instruction)3987 void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3988   HBasicBlock* block = instruction->GetBlock();
3989   if (block->GetLoopInformation() != nullptr) {
3990     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3991     // The back edge will generate the suspend check.
3992     return;
3993   }
3994   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3995     // The goto will generate the suspend check.
3996     return;
3997   }
3998   GenerateSuspendCheck(instruction, nullptr);
3999 }
4000 
GenerateSuspendCheck(HSuspendCheck * instruction,HBasicBlock * successor)4001 void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4002                                                        HBasicBlock* successor) {
4003   SuspendCheckSlowPathX86* slow_path =
4004       down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4005   if (slow_path == nullptr) {
4006     slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4007     instruction->SetSlowPath(slow_path);
4008     codegen_->AddSlowPath(slow_path);
4009     if (successor != nullptr) {
4010       DCHECK(successor->IsLoopHeader());
4011       codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4012     }
4013   } else {
4014     DCHECK_EQ(slow_path->GetSuccessor(), successor);
4015   }
4016 
4017   __ fs()->cmpw(Address::Absolute(
4018       Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
4019   if (successor == nullptr) {
4020     __ j(kNotEqual, slow_path->GetEntryLabel());
4021     __ Bind(slow_path->GetReturnLabel());
4022   } else {
4023     __ j(kEqual, codegen_->GetLabelOf(successor));
4024     __ jmp(slow_path->GetEntryLabel());
4025   }
4026 }
4027 
GetAssembler() const4028 X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4029   return codegen_->GetAssembler();
4030 }
4031 
MoveMemoryToMemory32(int dst,int src)4032 void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
4033   ScratchRegisterScope ensure_scratch(
4034       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4035   Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4036   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4037   __ movl(temp_reg, Address(ESP, src + stack_offset));
4038   __ movl(Address(ESP, dst + stack_offset), temp_reg);
4039 }
4040 
MoveMemoryToMemory64(int dst,int src)4041 void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
4042   ScratchRegisterScope ensure_scratch(
4043       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4044   Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4045   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4046   __ movl(temp_reg, Address(ESP, src + stack_offset));
4047   __ movl(Address(ESP, dst + stack_offset), temp_reg);
4048   __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4049   __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
4050 }
4051 
EmitMove(size_t index)4052 void ParallelMoveResolverX86::EmitMove(size_t index) {
4053   MoveOperands* move = moves_.Get(index);
4054   Location source = move->GetSource();
4055   Location destination = move->GetDestination();
4056 
4057   if (source.IsRegister()) {
4058     if (destination.IsRegister()) {
4059       __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4060     } else {
4061       DCHECK(destination.IsStackSlot());
4062       __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
4063     }
4064   } else if (source.IsFpuRegister()) {
4065     if (destination.IsFpuRegister()) {
4066       __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4067     } else if (destination.IsStackSlot()) {
4068       __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4069     } else {
4070       DCHECK(destination.IsDoubleStackSlot());
4071       __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4072     }
4073   } else if (source.IsStackSlot()) {
4074     if (destination.IsRegister()) {
4075       __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
4076     } else if (destination.IsFpuRegister()) {
4077       __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4078     } else {
4079       DCHECK(destination.IsStackSlot());
4080       MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4081     }
4082   } else if (source.IsDoubleStackSlot()) {
4083     if (destination.IsFpuRegister()) {
4084       __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4085     } else {
4086       DCHECK(destination.IsDoubleStackSlot()) << destination;
4087       MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
4088     }
4089   } else if (source.IsConstant()) {
4090     HConstant* constant = source.GetConstant();
4091     if (constant->IsIntConstant() || constant->IsNullConstant()) {
4092       int32_t value = CodeGenerator::GetInt32ValueOf(constant);
4093       if (destination.IsRegister()) {
4094         if (value == 0) {
4095           __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4096         } else {
4097           __ movl(destination.AsRegister<Register>(), Immediate(value));
4098         }
4099       } else {
4100         DCHECK(destination.IsStackSlot()) << destination;
4101         __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
4102       }
4103     } else if (constant->IsFloatConstant()) {
4104       float fp_value = constant->AsFloatConstant()->GetValue();
4105       int32_t value = bit_cast<int32_t, float>(fp_value);
4106       Immediate imm(value);
4107       if (destination.IsFpuRegister()) {
4108         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4109         if (value == 0) {
4110           // Easy handling of 0.0.
4111           __ xorps(dest, dest);
4112         } else {
4113           ScratchRegisterScope ensure_scratch(
4114               this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4115           Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4116           __ movl(temp, Immediate(value));
4117           __ movd(dest, temp);
4118         }
4119       } else {
4120         DCHECK(destination.IsStackSlot()) << destination;
4121         __ movl(Address(ESP, destination.GetStackIndex()), imm);
4122       }
4123     } else if (constant->IsLongConstant()) {
4124       int64_t value = constant->AsLongConstant()->GetValue();
4125       int32_t low_value = Low32Bits(value);
4126       int32_t high_value = High32Bits(value);
4127       Immediate low(low_value);
4128       Immediate high(high_value);
4129       if (destination.IsDoubleStackSlot()) {
4130         __ movl(Address(ESP, destination.GetStackIndex()), low);
4131         __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4132       } else {
4133         __ movl(destination.AsRegisterPairLow<Register>(), low);
4134         __ movl(destination.AsRegisterPairHigh<Register>(), high);
4135       }
4136     } else {
4137       DCHECK(constant->IsDoubleConstant());
4138       double dbl_value = constant->AsDoubleConstant()->GetValue();
4139       int64_t value = bit_cast<int64_t, double>(dbl_value);
4140       int32_t low_value = Low32Bits(value);
4141       int32_t high_value = High32Bits(value);
4142       Immediate low(low_value);
4143       Immediate high(high_value);
4144       if (destination.IsFpuRegister()) {
4145         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4146         if (value == 0) {
4147           // Easy handling of 0.0.
4148           __ xorpd(dest, dest);
4149         } else {
4150           __ pushl(high);
4151           __ pushl(low);
4152           __ movsd(dest, Address(ESP, 0));
4153           __ addl(ESP, Immediate(8));
4154         }
4155       } else {
4156         DCHECK(destination.IsDoubleStackSlot()) << destination;
4157         __ movl(Address(ESP, destination.GetStackIndex()), low);
4158         __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4159       }
4160     }
4161   } else {
4162     LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
4163   }
4164 }
4165 
Exchange(Register reg,int mem)4166 void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
4167   Register suggested_scratch = reg == EAX ? EBX : EAX;
4168   ScratchRegisterScope ensure_scratch(
4169       this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4170 
4171   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4172   __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4173   __ movl(Address(ESP, mem + stack_offset), reg);
4174   __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
4175 }
4176 
Exchange32(XmmRegister reg,int mem)4177 void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
4178   ScratchRegisterScope ensure_scratch(
4179       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4180 
4181   Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4182   int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4183   __ movl(temp_reg, Address(ESP, mem + stack_offset));
4184   __ movss(Address(ESP, mem + stack_offset), reg);
4185   __ movd(reg, temp_reg);
4186 }
4187 
Exchange(int mem1,int mem2)4188 void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
4189   ScratchRegisterScope ensure_scratch1(
4190       this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4191 
4192   Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
4193   ScratchRegisterScope ensure_scratch2(
4194       this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4195 
4196   int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
4197   stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
4198   __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
4199   __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
4200   __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
4201   __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
4202 }
4203 
EmitSwap(size_t index)4204 void ParallelMoveResolverX86::EmitSwap(size_t index) {
4205   MoveOperands* move = moves_.Get(index);
4206   Location source = move->GetSource();
4207   Location destination = move->GetDestination();
4208 
4209   if (source.IsRegister() && destination.IsRegister()) {
4210     __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4211   } else if (source.IsRegister() && destination.IsStackSlot()) {
4212     Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
4213   } else if (source.IsStackSlot() && destination.IsRegister()) {
4214     Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
4215   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4216     Exchange(destination.GetStackIndex(), source.GetStackIndex());
4217   } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4218     // Use XOR Swap algorithm to avoid a temporary.
4219     DCHECK_NE(source.reg(), destination.reg());
4220     __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4221     __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4222     __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4223   } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
4224     Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
4225   } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
4226     Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
4227   } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
4228     // Take advantage of the 16 bytes in the XMM register.
4229     XmmRegister reg = source.AsFpuRegister<XmmRegister>();
4230     Address stack(ESP, destination.GetStackIndex());
4231     // Load the double into the high doubleword.
4232     __ movhpd(reg, stack);
4233 
4234     // Store the low double into the destination.
4235     __ movsd(stack, reg);
4236 
4237     // Move the high double to the low double.
4238     __ psrldq(reg, Immediate(8));
4239   } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
4240     // Take advantage of the 16 bytes in the XMM register.
4241     XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
4242     Address stack(ESP, source.GetStackIndex());
4243     // Load the double into the high doubleword.
4244     __ movhpd(reg, stack);
4245 
4246     // Store the low double into the destination.
4247     __ movsd(stack, reg);
4248 
4249     // Move the high double to the low double.
4250     __ psrldq(reg, Immediate(8));
4251   } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
4252     Exchange(destination.GetStackIndex(), source.GetStackIndex());
4253     Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
4254   } else {
4255     LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
4256   }
4257 }
4258 
SpillScratch(int reg)4259 void ParallelMoveResolverX86::SpillScratch(int reg) {
4260   __ pushl(static_cast<Register>(reg));
4261 }
4262 
RestoreScratch(int reg)4263 void ParallelMoveResolverX86::RestoreScratch(int reg) {
4264   __ popl(static_cast<Register>(reg));
4265 }
4266 
VisitLoadClass(HLoadClass * cls)4267 void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
4268   LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4269       ? LocationSummary::kCallOnSlowPath
4270       : LocationSummary::kNoCall;
4271   LocationSummary* locations =
4272       new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
4273   locations->SetOut(Location::RequiresRegister());
4274 }
4275 
VisitLoadClass(HLoadClass * cls)4276 void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
4277   Register out = cls->GetLocations()->Out().AsRegister<Register>();
4278   if (cls->IsReferrersClass()) {
4279     DCHECK(!cls->CanCallRuntime());
4280     DCHECK(!cls->MustGenerateClinitCheck());
4281     codegen_->LoadCurrentMethod(out);
4282     __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
4283   } else {
4284     DCHECK(cls->CanCallRuntime());
4285     codegen_->LoadCurrentMethod(out);
4286     __ movl(out, Address(out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
4287     __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
4288 
4289     SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4290         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4291     codegen_->AddSlowPath(slow_path);
4292     __ testl(out, out);
4293     __ j(kEqual, slow_path->GetEntryLabel());
4294     if (cls->MustGenerateClinitCheck()) {
4295       GenerateClassInitializationCheck(slow_path, out);
4296     } else {
4297       __ Bind(slow_path->GetExitLabel());
4298     }
4299   }
4300 }
4301 
VisitClinitCheck(HClinitCheck * check)4302 void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
4303   LocationSummary* locations =
4304       new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4305   locations->SetInAt(0, Location::RequiresRegister());
4306   if (check->HasUses()) {
4307     locations->SetOut(Location::SameAsFirstInput());
4308   }
4309 }
4310 
VisitClinitCheck(HClinitCheck * check)4311 void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
4312   // We assume the class to not be null.
4313   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4314       check->GetLoadClass(), check, check->GetDexPc(), true);
4315   codegen_->AddSlowPath(slow_path);
4316   GenerateClassInitializationCheck(slow_path,
4317                                    check->GetLocations()->InAt(0).AsRegister<Register>());
4318 }
4319 
GenerateClassInitializationCheck(SlowPathCodeX86 * slow_path,Register class_reg)4320 void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
4321     SlowPathCodeX86* slow_path, Register class_reg) {
4322   __ cmpl(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
4323           Immediate(mirror::Class::kStatusInitialized));
4324   __ j(kLess, slow_path->GetEntryLabel());
4325   __ Bind(slow_path->GetExitLabel());
4326   // No need for memory fence, thanks to the X86 memory model.
4327 }
4328 
VisitLoadString(HLoadString * load)4329 void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
4330   LocationSummary* locations =
4331       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
4332   locations->SetOut(Location::RequiresRegister());
4333 }
4334 
VisitLoadString(HLoadString * load)4335 void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
4336   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
4337   codegen_->AddSlowPath(slow_path);
4338 
4339   Register out = load->GetLocations()->Out().AsRegister<Register>();
4340   codegen_->LoadCurrentMethod(out);
4341   __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
4342   __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
4343   __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4344   __ testl(out, out);
4345   __ j(kEqual, slow_path->GetEntryLabel());
4346   __ Bind(slow_path->GetExitLabel());
4347 }
4348 
VisitLoadException(HLoadException * load)4349 void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
4350   LocationSummary* locations =
4351       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4352   locations->SetOut(Location::RequiresRegister());
4353 }
4354 
VisitLoadException(HLoadException * load)4355 void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
4356   Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
4357   __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
4358   __ fs()->movl(address, Immediate(0));
4359 }
4360 
VisitThrow(HThrow * instruction)4361 void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
4362   LocationSummary* locations =
4363       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4364   InvokeRuntimeCallingConvention calling_convention;
4365   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4366 }
4367 
VisitThrow(HThrow * instruction)4368 void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
4369   __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
4370   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4371 }
4372 
VisitInstanceOf(HInstanceOf * instruction)4373 void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
4374   LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4375       ? LocationSummary::kNoCall
4376       : LocationSummary::kCallOnSlowPath;
4377   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4378   locations->SetInAt(0, Location::RequiresRegister());
4379   locations->SetInAt(1, Location::Any());
4380   locations->SetOut(Location::RequiresRegister());
4381 }
4382 
VisitInstanceOf(HInstanceOf * instruction)4383 void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
4384   LocationSummary* locations = instruction->GetLocations();
4385   Register obj = locations->InAt(0).AsRegister<Register>();
4386   Location cls = locations->InAt(1);
4387   Register out = locations->Out().AsRegister<Register>();
4388   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4389   Label done, zero;
4390   SlowPathCodeX86* slow_path = nullptr;
4391 
4392   // Return 0 if `obj` is null.
4393   // Avoid null check if we know obj is not null.
4394   if (instruction->MustDoNullCheck()) {
4395     __ testl(obj, obj);
4396     __ j(kEqual, &zero);
4397   }
4398   __ movl(out, Address(obj, class_offset));
4399   // Compare the class of `obj` with `cls`.
4400   if (cls.IsRegister()) {
4401     __ cmpl(out, cls.AsRegister<Register>());
4402   } else {
4403     DCHECK(cls.IsStackSlot()) << cls;
4404     __ cmpl(out, Address(ESP, cls.GetStackIndex()));
4405   }
4406 
4407   if (instruction->IsClassFinal()) {
4408     // Classes must be equal for the instanceof to succeed.
4409     __ j(kNotEqual, &zero);
4410     __ movl(out, Immediate(1));
4411     __ jmp(&done);
4412   } else {
4413     // If the classes are not equal, we go into a slow path.
4414     DCHECK(locations->OnlyCallsOnSlowPath());
4415     slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4416         instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
4417     codegen_->AddSlowPath(slow_path);
4418     __ j(kNotEqual, slow_path->GetEntryLabel());
4419     __ movl(out, Immediate(1));
4420     __ jmp(&done);
4421   }
4422 
4423   if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4424     __ Bind(&zero);
4425     __ movl(out, Immediate(0));
4426   }
4427 
4428   if (slow_path != nullptr) {
4429     __ Bind(slow_path->GetExitLabel());
4430   }
4431   __ Bind(&done);
4432 }
4433 
VisitCheckCast(HCheckCast * instruction)4434 void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4435   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4436       instruction, LocationSummary::kCallOnSlowPath);
4437   locations->SetInAt(0, Location::RequiresRegister());
4438   locations->SetInAt(1, Location::Any());
4439   locations->AddTemp(Location::RequiresRegister());
4440 }
4441 
VisitCheckCast(HCheckCast * instruction)4442 void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4443   LocationSummary* locations = instruction->GetLocations();
4444   Register obj = locations->InAt(0).AsRegister<Register>();
4445   Location cls = locations->InAt(1);
4446   Register temp = locations->GetTemp(0).AsRegister<Register>();
4447   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4448   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4449       instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4450   codegen_->AddSlowPath(slow_path);
4451 
4452   // Avoid null check if we know obj is not null.
4453   if (instruction->MustDoNullCheck()) {
4454     __ testl(obj, obj);
4455     __ j(kEqual, slow_path->GetExitLabel());
4456   }
4457 
4458   __ movl(temp, Address(obj, class_offset));
4459   // Compare the class of `obj` with `cls`.
4460   if (cls.IsRegister()) {
4461     __ cmpl(temp, cls.AsRegister<Register>());
4462   } else {
4463     DCHECK(cls.IsStackSlot()) << cls;
4464     __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4465   }
4466 
4467   __ j(kNotEqual, slow_path->GetEntryLabel());
4468   __ Bind(slow_path->GetExitLabel());
4469 }
4470 
VisitMonitorOperation(HMonitorOperation * instruction)4471 void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4472   LocationSummary* locations =
4473       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4474   InvokeRuntimeCallingConvention calling_convention;
4475   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4476 }
4477 
VisitMonitorOperation(HMonitorOperation * instruction)4478 void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4479   __ fs()->call(Address::Absolute(instruction->IsEnter()
4480         ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4481         : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4482   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4483 }
4484 
VisitAnd(HAnd * instruction)4485 void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
VisitOr(HOr * instruction)4486 void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
VisitXor(HXor * instruction)4487 void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4488 
HandleBitwiseOperation(HBinaryOperation * instruction)4489 void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4490   LocationSummary* locations =
4491       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4492   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4493          || instruction->GetResultType() == Primitive::kPrimLong);
4494   locations->SetInAt(0, Location::RequiresRegister());
4495   locations->SetInAt(1, Location::Any());
4496   locations->SetOut(Location::SameAsFirstInput());
4497 }
4498 
VisitAnd(HAnd * instruction)4499 void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4500   HandleBitwiseOperation(instruction);
4501 }
4502 
VisitOr(HOr * instruction)4503 void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4504   HandleBitwiseOperation(instruction);
4505 }
4506 
VisitXor(HXor * instruction)4507 void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4508   HandleBitwiseOperation(instruction);
4509 }
4510 
HandleBitwiseOperation(HBinaryOperation * instruction)4511 void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4512   LocationSummary* locations = instruction->GetLocations();
4513   Location first = locations->InAt(0);
4514   Location second = locations->InAt(1);
4515   DCHECK(first.Equals(locations->Out()));
4516 
4517   if (instruction->GetResultType() == Primitive::kPrimInt) {
4518     if (second.IsRegister()) {
4519       if (instruction->IsAnd()) {
4520         __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
4521       } else if (instruction->IsOr()) {
4522         __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
4523       } else {
4524         DCHECK(instruction->IsXor());
4525         __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
4526       }
4527     } else if (second.IsConstant()) {
4528       if (instruction->IsAnd()) {
4529         __ andl(first.AsRegister<Register>(),
4530                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
4531       } else if (instruction->IsOr()) {
4532         __ orl(first.AsRegister<Register>(),
4533                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
4534       } else {
4535         DCHECK(instruction->IsXor());
4536         __ xorl(first.AsRegister<Register>(),
4537                 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
4538       }
4539     } else {
4540       if (instruction->IsAnd()) {
4541         __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
4542       } else if (instruction->IsOr()) {
4543         __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
4544       } else {
4545         DCHECK(instruction->IsXor());
4546         __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
4547       }
4548     }
4549   } else {
4550     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4551     if (second.IsRegisterPair()) {
4552       if (instruction->IsAnd()) {
4553         __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4554         __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4555       } else if (instruction->IsOr()) {
4556         __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4557         __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4558       } else {
4559         DCHECK(instruction->IsXor());
4560         __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4561         __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4562       }
4563     } else if (second.IsDoubleStackSlot()) {
4564       if (instruction->IsAnd()) {
4565         __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4566         __ andl(first.AsRegisterPairHigh<Register>(),
4567                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4568       } else if (instruction->IsOr()) {
4569         __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4570         __ orl(first.AsRegisterPairHigh<Register>(),
4571                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4572       } else {
4573         DCHECK(instruction->IsXor());
4574         __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4575         __ xorl(first.AsRegisterPairHigh<Register>(),
4576                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4577       }
4578     } else {
4579       DCHECK(second.IsConstant()) << second;
4580       int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
4581       int32_t low_value = Low32Bits(value);
4582       int32_t high_value = High32Bits(value);
4583       Immediate low(low_value);
4584       Immediate high(high_value);
4585       Register first_low = first.AsRegisterPairLow<Register>();
4586       Register first_high = first.AsRegisterPairHigh<Register>();
4587       if (instruction->IsAnd()) {
4588         if (low_value == 0) {
4589           __ xorl(first_low, first_low);
4590         } else if (low_value != -1) {
4591           __ andl(first_low, low);
4592         }
4593         if (high_value == 0) {
4594           __ xorl(first_high, first_high);
4595         } else if (high_value != -1) {
4596           __ andl(first_high, high);
4597         }
4598       } else if (instruction->IsOr()) {
4599         if (low_value != 0) {
4600           __ orl(first_low, low);
4601         }
4602         if (high_value != 0) {
4603           __ orl(first_high, high);
4604         }
4605       } else {
4606         DCHECK(instruction->IsXor());
4607         if (low_value != 0) {
4608           __ xorl(first_low, low);
4609         }
4610         if (high_value != 0) {
4611           __ xorl(first_high, high);
4612         }
4613       }
4614     }
4615   }
4616 }
4617 
VisitBoundType(HBoundType * instruction)4618 void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4619   // Nothing to do, this should be removed during prepare for register allocator.
4620   UNUSED(instruction);
4621   LOG(FATAL) << "Unreachable";
4622 }
4623 
VisitBoundType(HBoundType * instruction)4624 void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4625   // Nothing to do, this should be removed during prepare for register allocator.
4626   UNUSED(instruction);
4627   LOG(FATAL) << "Unreachable";
4628 }
4629 
4630 }  // namespace x86
4631 }  // namespace art
4632