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_64.h"
18 
19 #include "entrypoints/quick/quick_entrypoints.h"
20 #include "gc/accounting/card_table.h"
21 #include "mirror/array.h"
22 #include "mirror/art_method.h"
23 #include "mirror/object_reference.h"
24 #include "thread.h"
25 #include "utils/assembler.h"
26 #include "utils/stack_checks.h"
27 #include "utils/x86_64/assembler_x86_64.h"
28 #include "utils/x86_64/managed_register_x86_64.h"
29 
30 namespace art {
31 
AsX86_64() const32 x86_64::X86_64ManagedRegister Location::AsX86_64() const {
33   return reg().AsX86_64();
34 }
35 
36 namespace x86_64 {
37 
38 static constexpr bool kExplicitStackOverflowCheck = true;
39 
40 // Some x86_64 instructions require a register to be available as temp.
41 static constexpr Register TMP = R11;
42 
43 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
44 static constexpr int kCurrentMethodStackOffset = 0;
45 
X86_64CpuLocation(Register reg)46 static Location X86_64CpuLocation(Register reg) {
47   return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
48 }
49 
50 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
51 static constexpr size_t kRuntimeParameterCoreRegistersLength =
52     arraysize(kRuntimeParameterCoreRegisters);
53 
54 class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
55  public:
InvokeRuntimeCallingConvention()56   InvokeRuntimeCallingConvention()
57       : CallingConvention(kRuntimeParameterCoreRegisters,
58                           kRuntimeParameterCoreRegistersLength) {}
59 
60  private:
61   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
62 };
63 
64 #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
65 
66 class NullCheckSlowPathX86_64 : public SlowPathCode {
67  public:
NullCheckSlowPathX86_64(uint32_t dex_pc)68   explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
69 
EmitNativeCode(CodeGenerator * codegen)70   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
71     __ Bind(GetEntryLabel());
72     __ gs()->call(
73         Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
74     codegen->RecordPcInfo(dex_pc_);
75   }
76 
77  private:
78   const uint32_t dex_pc_;
79   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
80 };
81 
82 class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
83  public:
StackOverflowCheckSlowPathX86_64()84   StackOverflowCheckSlowPathX86_64() {}
85 
EmitNativeCode(CodeGenerator * codegen)86   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
87     __ Bind(GetEntryLabel());
88     __ addq(CpuRegister(RSP),
89             Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
90     __ gs()->jmp(
91         Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
92   }
93 
94  private:
95   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
96 };
97 
98 class BoundsCheckSlowPathX86_64 : public SlowPathCode {
99  public:
BoundsCheckSlowPathX86_64(uint32_t dex_pc,Location index_location,Location length_location)100   explicit BoundsCheckSlowPathX86_64(uint32_t dex_pc,
101                                      Location index_location,
102                                      Location length_location)
103       : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
104 
EmitNativeCode(CodeGenerator * codegen)105   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
106     CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
107     __ Bind(GetEntryLabel());
108     InvokeRuntimeCallingConvention calling_convention;
109     x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
110     x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
111     __ gs()->call(Address::Absolute(
112         QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
113     codegen->RecordPcInfo(dex_pc_);
114   }
115 
116  private:
117   const uint32_t dex_pc_;
118   const Location index_location_;
119   const Location length_location_;
120 
121   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
122 };
123 
124 #undef __
125 #define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
126 
X86_64Condition(IfCondition cond)127 inline Condition X86_64Condition(IfCondition cond) {
128   switch (cond) {
129     case kCondEQ: return kEqual;
130     case kCondNE: return kNotEqual;
131     case kCondLT: return kLess;
132     case kCondLE: return kLessEqual;
133     case kCondGT: return kGreater;
134     case kCondGE: return kGreaterEqual;
135     default:
136       LOG(FATAL) << "Unknown if condition";
137   }
138   return kEqual;
139 }
140 
DumpCoreRegister(std::ostream & stream,int reg) const141 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
142   stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
143 }
144 
DumpFloatingPointRegister(std::ostream & stream,int reg) const145 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
146   stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
147 }
148 
CodeGeneratorX86_64(HGraph * graph)149 CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
150       : CodeGenerator(graph, kNumberOfRegIds),
151         location_builder_(graph, this),
152         instruction_visitor_(graph, this),
153         move_resolver_(graph->GetArena(), this) {}
154 
FrameEntrySpillSize() const155 size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
156   return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
157 }
158 
InstructionCodeGeneratorX86_64(HGraph * graph,CodeGeneratorX86_64 * codegen)159 InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
160                                                                CodeGeneratorX86_64* codegen)
161       : HGraphVisitor(graph),
162         assembler_(codegen->GetAssembler()),
163         codegen_(codegen) {}
164 
AllocateFreeRegister(Primitive::Type type,bool * blocked_registers) const165 ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
166                                                           bool* blocked_registers) const {
167   switch (type) {
168     case Primitive::kPrimLong:
169     case Primitive::kPrimByte:
170     case Primitive::kPrimBoolean:
171     case Primitive::kPrimChar:
172     case Primitive::kPrimShort:
173     case Primitive::kPrimInt:
174     case Primitive::kPrimNot: {
175       size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
176       return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
177     }
178 
179     case Primitive::kPrimFloat:
180     case Primitive::kPrimDouble:
181       LOG(FATAL) << "Unimplemented register type " << type;
182 
183     case Primitive::kPrimVoid:
184       LOG(FATAL) << "Unreachable type " << type;
185   }
186 
187   return ManagedRegister::NoRegister();
188 }
189 
SetupBlockedRegisters(bool * blocked_registers) const190 void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
191   // Stack register is always reserved.
192   blocked_registers[RSP] = true;
193 
194   // Block the register used as TMP.
195   blocked_registers[TMP] = true;
196 
197   // TODO: We currently don't use Quick's callee saved registers.
198   blocked_registers[RBX] = true;
199   blocked_registers[RBP] = true;
200   blocked_registers[R12] = true;
201   blocked_registers[R13] = true;
202   blocked_registers[R14] = true;
203   blocked_registers[R15] = true;
204 }
205 
GenerateFrameEntry()206 void CodeGeneratorX86_64::GenerateFrameEntry() {
207   // Create a fake register to mimic Quick.
208   static const int kFakeReturnRegister = 16;
209   core_spill_mask_ |= (1 << kFakeReturnRegister);
210 
211   // The return PC has already been pushed on the stack.
212   __ subq(CpuRegister(RSP),
213           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
214 
215   bool skip_overflow_check = IsLeafMethod()
216       && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
217 
218   if (!skip_overflow_check) {
219     if (kExplicitStackOverflowCheck) {
220       SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
221       AddSlowPath(slow_path);
222 
223       __ gs()->cmpq(CpuRegister(RSP),
224                     Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
225       __ j(kLess, slow_path->GetEntryLabel());
226     } else {
227       __ testq(CpuRegister(RAX), Address(
228           CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
229     }
230   }
231 
232   __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
233 }
234 
GenerateFrameExit()235 void CodeGeneratorX86_64::GenerateFrameExit() {
236   __ addq(CpuRegister(RSP),
237           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
238 }
239 
Bind(Label * label)240 void CodeGeneratorX86_64::Bind(Label* label) {
241   __ Bind(label);
242 }
243 
LoadCurrentMethod(CpuRegister reg)244 void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
245   __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
246 }
247 
GetStackLocation(HLoadLocal * load) const248 Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
249   switch (load->GetType()) {
250     case Primitive::kPrimLong:
251       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
252       break;
253 
254     case Primitive::kPrimInt:
255     case Primitive::kPrimNot:
256       return Location::StackSlot(GetStackSlot(load->GetLocal()));
257 
258     case Primitive::kPrimFloat:
259     case Primitive::kPrimDouble:
260       LOG(FATAL) << "Unimplemented type " << load->GetType();
261 
262     case Primitive::kPrimBoolean:
263     case Primitive::kPrimByte:
264     case Primitive::kPrimChar:
265     case Primitive::kPrimShort:
266     case Primitive::kPrimVoid:
267       LOG(FATAL) << "Unexpected type " << load->GetType();
268   }
269 
270   LOG(FATAL) << "Unreachable";
271   return Location();
272 }
273 
Move(Location destination,Location source)274 void CodeGeneratorX86_64::Move(Location destination, Location source) {
275   if (source.Equals(destination)) {
276     return;
277   }
278   if (destination.IsRegister()) {
279     if (source.IsRegister()) {
280       __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
281     } else if (source.IsStackSlot()) {
282       __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
283     } else {
284       DCHECK(source.IsDoubleStackSlot());
285       __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
286     }
287   } else if (destination.IsStackSlot()) {
288     if (source.IsRegister()) {
289       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
290     } else {
291       DCHECK(source.IsStackSlot());
292       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
293       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
294     }
295   } else {
296     DCHECK(destination.IsDoubleStackSlot());
297     if (source.IsRegister()) {
298       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
299     } else {
300       DCHECK(source.IsDoubleStackSlot());
301       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
302       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
303     }
304   }
305 }
306 
Move(HInstruction * instruction,Location location,HInstruction * move_for)307 void CodeGeneratorX86_64::Move(HInstruction* instruction,
308                                Location location,
309                                HInstruction* move_for) {
310   if (instruction->AsIntConstant() != nullptr) {
311     Immediate imm(instruction->AsIntConstant()->GetValue());
312     if (location.IsRegister()) {
313       __ movl(location.AsX86_64().AsCpuRegister(), imm);
314     } else {
315       __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
316     }
317   } else if (instruction->AsLongConstant() != nullptr) {
318     int64_t value = instruction->AsLongConstant()->GetValue();
319     if (location.IsRegister()) {
320       __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
321     } else {
322       __ movq(CpuRegister(TMP), Immediate(value));
323       __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
324     }
325   } else if (instruction->AsLoadLocal() != nullptr) {
326     switch (instruction->GetType()) {
327       case Primitive::kPrimBoolean:
328       case Primitive::kPrimByte:
329       case Primitive::kPrimChar:
330       case Primitive::kPrimShort:
331       case Primitive::kPrimInt:
332       case Primitive::kPrimNot:
333         Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
334         break;
335 
336       case Primitive::kPrimLong:
337         Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
338         break;
339 
340       default:
341         LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
342     }
343   } else {
344     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
345     switch (instruction->GetType()) {
346       case Primitive::kPrimBoolean:
347       case Primitive::kPrimByte:
348       case Primitive::kPrimChar:
349       case Primitive::kPrimShort:
350       case Primitive::kPrimInt:
351       case Primitive::kPrimNot:
352       case Primitive::kPrimLong:
353         Move(location, instruction->GetLocations()->Out());
354         break;
355 
356       default:
357         LOG(FATAL) << "Unimplemented type " << instruction->GetType();
358     }
359   }
360 }
361 
VisitGoto(HGoto * got)362 void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
363   got->SetLocations(nullptr);
364 }
365 
VisitGoto(HGoto * got)366 void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
367   HBasicBlock* successor = got->GetSuccessor();
368   if (GetGraph()->GetExitBlock() == successor) {
369     codegen_->GenerateFrameExit();
370   } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
371     __ jmp(codegen_->GetLabelOf(successor));
372   }
373 }
374 
VisitExit(HExit * exit)375 void LocationsBuilderX86_64::VisitExit(HExit* exit) {
376   exit->SetLocations(nullptr);
377 }
378 
VisitExit(HExit * exit)379 void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
380   if (kIsDebugBuild) {
381     __ Comment("Unreachable");
382     __ int3();
383   }
384 }
385 
VisitIf(HIf * if_instr)386 void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
387   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
388   HInstruction* cond = if_instr->InputAt(0);
389   DCHECK(cond->IsCondition());
390   HCondition* condition = cond->AsCondition();
391   if (condition->NeedsMaterialization()) {
392     locations->SetInAt(0, Location::Any());
393   }
394   if_instr->SetLocations(locations);
395 }
396 
VisitIf(HIf * if_instr)397 void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
398   HInstruction* cond = if_instr->InputAt(0);
399   DCHECK(cond->IsCondition());
400   HCondition* condition = cond->AsCondition();
401   if (condition->NeedsMaterialization()) {
402     // Materialized condition, compare against 0.
403     Location lhs = if_instr->GetLocations()->InAt(0);
404     if (lhs.IsRegister()) {
405       __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
406     } else {
407       __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
408     }
409     __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
410   } else {
411     Location lhs = condition->GetLocations()->InAt(0);
412     Location rhs = condition->GetLocations()->InAt(1);
413     if (rhs.IsRegister()) {
414       __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
415     } else if (rhs.IsConstant()) {
416       __ cmpl(lhs.AsX86_64().AsCpuRegister(),
417               Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
418     } else {
419       __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
420     }
421     __ j(X86_64Condition(condition->GetCondition()),
422          codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
423   }
424   if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
425     __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
426   }
427 }
428 
VisitLocal(HLocal * local)429 void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
430   local->SetLocations(nullptr);
431 }
432 
VisitLocal(HLocal * local)433 void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
434   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
435 }
436 
VisitLoadLocal(HLoadLocal * local)437 void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
438   local->SetLocations(nullptr);
439 }
440 
VisitLoadLocal(HLoadLocal * load)441 void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
442   // Nothing to do, this is driven by the code generator.
443 }
444 
VisitStoreLocal(HStoreLocal * store)445 void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
446   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
447   switch (store->InputAt(1)->GetType()) {
448     case Primitive::kPrimBoolean:
449     case Primitive::kPrimByte:
450     case Primitive::kPrimChar:
451     case Primitive::kPrimShort:
452     case Primitive::kPrimInt:
453     case Primitive::kPrimNot:
454       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
455       break;
456 
457     case Primitive::kPrimLong:
458       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
459       break;
460 
461     default:
462       LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
463   }
464   store->SetLocations(locations);
465 }
466 
VisitStoreLocal(HStoreLocal * store)467 void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
468 }
469 
VisitCondition(HCondition * comp)470 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
471   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
472   locations->SetInAt(0, Location::RequiresRegister());
473   locations->SetInAt(1, Location::Any());
474   if (comp->NeedsMaterialization()) {
475     locations->SetOut(Location::RequiresRegister());
476   }
477   comp->SetLocations(locations);
478 }
479 
VisitCondition(HCondition * comp)480 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
481   if (comp->NeedsMaterialization()) {
482     LocationSummary* locations = comp->GetLocations();
483     if (locations->InAt(1).IsRegister()) {
484       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
485               locations->InAt(1).AsX86_64().AsCpuRegister());
486     } else if (locations->InAt(1).IsConstant()) {
487       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
488               Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
489     } else {
490       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
491               Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
492     }
493     __ setcc(X86_64Condition(comp->GetCondition()),
494              comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
495   }
496 }
497 
VisitEqual(HEqual * comp)498 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
499   VisitCondition(comp);
500 }
501 
VisitEqual(HEqual * comp)502 void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
503   VisitCondition(comp);
504 }
505 
VisitNotEqual(HNotEqual * comp)506 void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
507   VisitCondition(comp);
508 }
509 
VisitNotEqual(HNotEqual * comp)510 void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
511   VisitCondition(comp);
512 }
513 
VisitLessThan(HLessThan * comp)514 void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
515   VisitCondition(comp);
516 }
517 
VisitLessThan(HLessThan * comp)518 void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
519   VisitCondition(comp);
520 }
521 
VisitLessThanOrEqual(HLessThanOrEqual * comp)522 void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
523   VisitCondition(comp);
524 }
525 
VisitLessThanOrEqual(HLessThanOrEqual * comp)526 void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
527   VisitCondition(comp);
528 }
529 
VisitGreaterThan(HGreaterThan * comp)530 void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
531   VisitCondition(comp);
532 }
533 
VisitGreaterThan(HGreaterThan * comp)534 void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
535   VisitCondition(comp);
536 }
537 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)538 void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
539   VisitCondition(comp);
540 }
541 
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)542 void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
543   VisitCondition(comp);
544 }
545 
VisitCompare(HCompare * compare)546 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
547   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
548   locations->SetInAt(0, Location::RequiresRegister());
549   locations->SetInAt(1, Location::RequiresRegister());
550   locations->SetOut(Location::RequiresRegister());
551   compare->SetLocations(locations);
552 }
553 
VisitCompare(HCompare * compare)554 void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
555   Label greater, done;
556   LocationSummary* locations = compare->GetLocations();
557   switch (compare->InputAt(0)->GetType()) {
558     case Primitive::kPrimLong:
559       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
560               locations->InAt(1).AsX86_64().AsCpuRegister());
561       break;
562     default:
563       LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
564   }
565 
566   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
567   __ j(kEqual, &done);
568   __ j(kGreater, &greater);
569 
570   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
571   __ jmp(&done);
572 
573   __ Bind(&greater);
574   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
575 
576   __ Bind(&done);
577 }
578 
VisitIntConstant(HIntConstant * constant)579 void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
580   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
581   locations->SetOut(Location::ConstantLocation(constant));
582   constant->SetLocations(locations);
583 }
584 
VisitIntConstant(HIntConstant * constant)585 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
586 }
587 
VisitLongConstant(HLongConstant * constant)588 void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
589   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
590   locations->SetOut(Location::ConstantLocation(constant));
591   constant->SetLocations(locations);
592 }
593 
VisitLongConstant(HLongConstant * constant)594 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
595 }
596 
VisitReturnVoid(HReturnVoid * ret)597 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
598   ret->SetLocations(nullptr);
599 }
600 
VisitReturnVoid(HReturnVoid * ret)601 void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
602   codegen_->GenerateFrameExit();
603   __ ret();
604 }
605 
VisitReturn(HReturn * ret)606 void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
607   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
608   switch (ret->InputAt(0)->GetType()) {
609     case Primitive::kPrimBoolean:
610     case Primitive::kPrimByte:
611     case Primitive::kPrimChar:
612     case Primitive::kPrimShort:
613     case Primitive::kPrimInt:
614     case Primitive::kPrimNot:
615     case Primitive::kPrimLong:
616       locations->SetInAt(0, X86_64CpuLocation(RAX));
617       break;
618 
619     default:
620       LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
621   }
622   ret->SetLocations(locations);
623 }
624 
VisitReturn(HReturn * ret)625 void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
626   if (kIsDebugBuild) {
627     switch (ret->InputAt(0)->GetType()) {
628       case Primitive::kPrimBoolean:
629       case Primitive::kPrimByte:
630       case Primitive::kPrimChar:
631       case Primitive::kPrimShort:
632       case Primitive::kPrimInt:
633       case Primitive::kPrimNot:
634       case Primitive::kPrimLong:
635         DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
636         break;
637 
638       default:
639         LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
640     }
641   }
642   codegen_->GenerateFrameExit();
643   __ ret();
644 }
645 
GetNextLocation(Primitive::Type type)646 Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
647   switch (type) {
648     case Primitive::kPrimBoolean:
649     case Primitive::kPrimByte:
650     case Primitive::kPrimChar:
651     case Primitive::kPrimShort:
652     case Primitive::kPrimInt:
653     case Primitive::kPrimNot: {
654       uint32_t index = gp_index_++;
655       stack_index_++;
656       if (index < calling_convention.GetNumberOfRegisters()) {
657         return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
658       } else {
659         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
660       }
661     }
662 
663     case Primitive::kPrimLong: {
664       uint32_t index = gp_index_;
665       stack_index_ += 2;
666       if (index < calling_convention.GetNumberOfRegisters()) {
667         gp_index_ += 1;
668         return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
669       } else {
670         gp_index_ += 2;
671         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
672       }
673     }
674 
675     case Primitive::kPrimDouble:
676     case Primitive::kPrimFloat:
677       LOG(FATAL) << "Unimplemented parameter type " << type;
678       break;
679 
680     case Primitive::kPrimVoid:
681       LOG(FATAL) << "Unexpected parameter type " << type;
682       break;
683   }
684   return Location();
685 }
686 
VisitInvokeStatic(HInvokeStatic * invoke)687 void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
688   codegen_->MarkNotLeaf();
689   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
690   locations->AddTemp(X86_64CpuLocation(RDI));
691 
692   InvokeDexCallingConventionVisitor calling_convention_visitor;
693   for (size_t i = 0; i < invoke->InputCount(); ++i) {
694     HInstruction* input = invoke->InputAt(i);
695     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
696   }
697 
698   switch (invoke->GetType()) {
699     case Primitive::kPrimBoolean:
700     case Primitive::kPrimByte:
701     case Primitive::kPrimChar:
702     case Primitive::kPrimShort:
703     case Primitive::kPrimInt:
704     case Primitive::kPrimNot:
705     case Primitive::kPrimLong:
706       locations->SetOut(X86_64CpuLocation(RAX));
707       break;
708 
709     case Primitive::kPrimVoid:
710       break;
711 
712     case Primitive::kPrimDouble:
713     case Primitive::kPrimFloat:
714       LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
715       break;
716   }
717 
718   invoke->SetLocations(locations);
719 }
720 
VisitInvokeStatic(HInvokeStatic * invoke)721 void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
722   CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
723   uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
724   size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
725       invoke->GetIndexInDexCache() * heap_reference_size;
726 
727   // TODO: Implement all kinds of calls:
728   // 1) boot -> boot
729   // 2) app -> boot
730   // 3) app -> app
731   //
732   // Currently we implement the app -> app logic, which looks up in the resolve cache.
733 
734   // temp = method;
735   LoadCurrentMethod(temp);
736   // temp = temp->dex_cache_resolved_methods_;
737   __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
738   // temp = temp[index_in_cache]
739   __ movl(temp, Address(temp, index_in_cache));
740   // (temp + offset_of_quick_compiled_code)()
741   __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
742                   kX86_64PointerSize).SizeValue()));
743 
744   DCHECK(!codegen_->IsLeafMethod());
745   codegen_->RecordPcInfo(invoke->GetDexPc());
746 }
747 
VisitAdd(HAdd * add)748 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
749   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
750   switch (add->GetResultType()) {
751     case Primitive::kPrimInt: {
752       locations->SetInAt(0, Location::RequiresRegister());
753       locations->SetInAt(1, Location::Any());
754       locations->SetOut(Location::SameAsFirstInput());
755       break;
756     }
757     case Primitive::kPrimLong: {
758       locations->SetInAt(0, Location::RequiresRegister());
759       locations->SetInAt(1, Location::RequiresRegister());
760       locations->SetOut(Location::SameAsFirstInput());
761       break;
762     }
763 
764     case Primitive::kPrimBoolean:
765     case Primitive::kPrimByte:
766     case Primitive::kPrimChar:
767     case Primitive::kPrimShort:
768       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
769       break;
770 
771     default:
772       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
773   }
774   add->SetLocations(locations);
775 }
776 
VisitAdd(HAdd * add)777 void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
778   LocationSummary* locations = add->GetLocations();
779   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
780             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
781   switch (add->GetResultType()) {
782     case Primitive::kPrimInt: {
783       if (locations->InAt(1).IsRegister()) {
784         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
785                 locations->InAt(1).AsX86_64().AsCpuRegister());
786       } else if (locations->InAt(1).IsConstant()) {
787         HConstant* instruction = locations->InAt(1).GetConstant();
788         Immediate imm(instruction->AsIntConstant()->GetValue());
789         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
790       } else {
791         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
792                 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
793       }
794       break;
795     }
796     case Primitive::kPrimLong: {
797       __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
798               locations->InAt(1).AsX86_64().AsCpuRegister());
799       break;
800     }
801 
802     case Primitive::kPrimBoolean:
803     case Primitive::kPrimByte:
804     case Primitive::kPrimChar:
805     case Primitive::kPrimShort:
806       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
807       break;
808 
809     default:
810       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
811   }
812 }
813 
VisitSub(HSub * sub)814 void LocationsBuilderX86_64::VisitSub(HSub* sub) {
815   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
816   switch (sub->GetResultType()) {
817     case Primitive::kPrimInt: {
818       locations->SetInAt(0, Location::RequiresRegister());
819       locations->SetInAt(1, Location::Any());
820       locations->SetOut(Location::SameAsFirstInput());
821       break;
822     }
823     case Primitive::kPrimLong: {
824       locations->SetInAt(0, Location::RequiresRegister());
825       locations->SetInAt(1, Location::RequiresRegister());
826       locations->SetOut(Location::SameAsFirstInput());
827       break;
828     }
829 
830     case Primitive::kPrimBoolean:
831     case Primitive::kPrimByte:
832     case Primitive::kPrimChar:
833     case Primitive::kPrimShort:
834       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
835       break;
836 
837     default:
838       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
839   }
840   sub->SetLocations(locations);
841 }
842 
VisitSub(HSub * sub)843 void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
844   LocationSummary* locations = sub->GetLocations();
845   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
846             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
847   switch (sub->GetResultType()) {
848     case Primitive::kPrimInt: {
849       if (locations->InAt(1).IsRegister()) {
850         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
851                 locations->InAt(1).AsX86_64().AsCpuRegister());
852       } else if (locations->InAt(1).IsConstant()) {
853         HConstant* instruction = locations->InAt(1).GetConstant();
854         Immediate imm(instruction->AsIntConstant()->GetValue());
855         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
856       } else {
857         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
858                 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
859       }
860       break;
861     }
862     case Primitive::kPrimLong: {
863       __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
864               locations->InAt(1).AsX86_64().AsCpuRegister());
865       break;
866     }
867 
868     case Primitive::kPrimBoolean:
869     case Primitive::kPrimByte:
870     case Primitive::kPrimChar:
871     case Primitive::kPrimShort:
872       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
873       break;
874 
875     default:
876       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
877   }
878 }
879 
VisitNewInstance(HNewInstance * instruction)880 void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
881   codegen_->MarkNotLeaf();
882   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
883   locations->SetOut(X86_64CpuLocation(RAX));
884   instruction->SetLocations(locations);
885 }
886 
VisitNewInstance(HNewInstance * instruction)887 void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
888   InvokeRuntimeCallingConvention calling_convention;
889   LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
890   __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
891 
892   __ gs()->call(Address::Absolute(
893       QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
894 
895   DCHECK(!codegen_->IsLeafMethod());
896   codegen_->RecordPcInfo(instruction->GetDexPc());
897 }
898 
VisitParameterValue(HParameterValue * instruction)899 void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
900   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
901   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
902   if (location.IsStackSlot()) {
903     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
904   } else if (location.IsDoubleStackSlot()) {
905     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
906   }
907   locations->SetOut(location);
908   instruction->SetLocations(locations);
909 }
910 
VisitParameterValue(HParameterValue * instruction)911 void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
912   // Nothing to do, the parameter is already at its location.
913 }
914 
VisitNot(HNot * instruction)915 void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
916   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
917   locations->SetInAt(0, Location::RequiresRegister());
918   locations->SetOut(Location::SameAsFirstInput());
919   instruction->SetLocations(locations);
920 }
921 
VisitNot(HNot * instruction)922 void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
923   LocationSummary* locations = instruction->GetLocations();
924   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
925             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
926   __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
927 }
928 
VisitPhi(HPhi * instruction)929 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
930   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
931   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
932     locations->SetInAt(i, Location::Any());
933   }
934   locations->SetOut(Location::Any());
935   instruction->SetLocations(locations);
936 }
937 
VisitPhi(HPhi * instruction)938 void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
939   LOG(FATAL) << "Unimplemented";
940 }
941 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)942 void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
943   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
944   locations->SetInAt(0, Location::RequiresRegister());
945   locations->SetInAt(1, Location::RequiresRegister());
946   // Temporary registers for the write barrier.
947   if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
948     locations->AddTemp(Location::RequiresRegister());
949     locations->AddTemp(Location::RequiresRegister());
950   }
951   instruction->SetLocations(locations);
952 }
953 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)954 void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
955   LocationSummary* locations = instruction->GetLocations();
956   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
957   CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
958   size_t offset = instruction->GetFieldOffset().SizeValue();
959   Primitive::Type field_type = instruction->InputAt(1)->GetType();
960 
961   switch (field_type) {
962     case Primitive::kPrimBoolean:
963     case Primitive::kPrimByte: {
964       __ movb(Address(obj, offset), value);
965       break;
966     }
967 
968     case Primitive::kPrimShort:
969     case Primitive::kPrimChar: {
970       __ movw(Address(obj, offset), value);
971       break;
972     }
973 
974     case Primitive::kPrimInt:
975     case Primitive::kPrimNot: {
976       __ movl(Address(obj, offset), value);
977       if (field_type == Primitive::kPrimNot) {
978         CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
979         CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
980         codegen_->MarkGCCard(temp, card, obj, value);
981       }
982       break;
983     }
984 
985     case Primitive::kPrimLong: {
986       __ movq(Address(obj, offset), value);
987       break;
988     }
989 
990     case Primitive::kPrimFloat:
991     case Primitive::kPrimDouble:
992       LOG(FATAL) << "Unimplemented register type " << field_type;
993 
994     case Primitive::kPrimVoid:
995       LOG(FATAL) << "Unreachable type " << field_type;
996   }
997 }
998 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)999 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1000   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1001   locations->SetInAt(0, Location::RequiresRegister());
1002   locations->SetOut(Location::RequiresRegister());
1003   instruction->SetLocations(locations);
1004 }
1005 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1006 void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1007   LocationSummary* locations = instruction->GetLocations();
1008   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1009   CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1010   size_t offset = instruction->GetFieldOffset().SizeValue();
1011 
1012   switch (instruction->GetType()) {
1013     case Primitive::kPrimBoolean: {
1014       __ movzxb(out, Address(obj, offset));
1015       break;
1016     }
1017 
1018     case Primitive::kPrimByte: {
1019       __ movsxb(out, Address(obj, offset));
1020       break;
1021     }
1022 
1023     case Primitive::kPrimShort: {
1024       __ movsxw(out, Address(obj, offset));
1025       break;
1026     }
1027 
1028     case Primitive::kPrimChar: {
1029       __ movzxw(out, Address(obj, offset));
1030       break;
1031     }
1032 
1033     case Primitive::kPrimInt:
1034     case Primitive::kPrimNot: {
1035       __ movl(out, Address(obj, offset));
1036       break;
1037     }
1038 
1039     case Primitive::kPrimLong: {
1040       __ movq(out, Address(obj, offset));
1041       break;
1042     }
1043 
1044     case Primitive::kPrimFloat:
1045     case Primitive::kPrimDouble:
1046       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1047 
1048     case Primitive::kPrimVoid:
1049       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1050   }
1051 }
1052 
VisitNullCheck(HNullCheck * instruction)1053 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
1054   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1055   locations->SetInAt(0, Location::Any());
1056   // TODO: Have a normalization phase that makes this instruction never used.
1057   locations->SetOut(Location::SameAsFirstInput());
1058   instruction->SetLocations(locations);
1059 }
1060 
VisitNullCheck(HNullCheck * instruction)1061 void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
1062   SlowPathCode* slow_path =
1063       new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
1064   codegen_->AddSlowPath(slow_path);
1065 
1066   LocationSummary* locations = instruction->GetLocations();
1067   Location obj = locations->InAt(0);
1068   DCHECK(obj.Equals(locations->Out()));
1069 
1070   if (obj.IsRegister()) {
1071     __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1072   } else {
1073     DCHECK(locations->InAt(0).IsStackSlot());
1074     __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1075   }
1076   __ j(kEqual, slow_path->GetEntryLabel());
1077 }
1078 
VisitArrayGet(HArrayGet * instruction)1079 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
1080   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1081   locations->SetInAt(0, Location::RequiresRegister());
1082   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1083   locations->SetOut(Location::RequiresRegister());
1084   instruction->SetLocations(locations);
1085 }
1086 
VisitArrayGet(HArrayGet * instruction)1087 void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1088   LocationSummary* locations = instruction->GetLocations();
1089   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1090   Location index = locations->InAt(1);
1091 
1092   switch (instruction->GetType()) {
1093     case Primitive::kPrimBoolean: {
1094       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1095       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1096       if (index.IsConstant()) {
1097         __ movzxb(out, Address(obj,
1098             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1099       } else {
1100         __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1101       }
1102       break;
1103     }
1104 
1105     case Primitive::kPrimByte: {
1106       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1107       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1108       if (index.IsConstant()) {
1109         __ movsxb(out, Address(obj,
1110             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1111       } else {
1112         __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1113       }
1114       break;
1115     }
1116 
1117     case Primitive::kPrimShort: {
1118       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1119       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1120       if (index.IsConstant()) {
1121         __ movsxw(out, Address(obj,
1122             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1123       } else {
1124         __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1125       }
1126       break;
1127     }
1128 
1129     case Primitive::kPrimChar: {
1130       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1131       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1132       if (index.IsConstant()) {
1133         __ movzxw(out, Address(obj,
1134             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1135       } else {
1136         __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1137       }
1138       break;
1139     }
1140 
1141     case Primitive::kPrimInt:
1142     case Primitive::kPrimNot: {
1143       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1144       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1145       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1146       if (index.IsConstant()) {
1147         __ movl(out, Address(obj,
1148             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1149       } else {
1150         __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1151       }
1152       break;
1153     }
1154 
1155     case Primitive::kPrimLong: {
1156       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1157       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1158       if (index.IsConstant()) {
1159         __ movq(out, Address(obj,
1160             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1161       } else {
1162         __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1163       }
1164       break;
1165     }
1166 
1167     case Primitive::kPrimFloat:
1168     case Primitive::kPrimDouble:
1169       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1170 
1171     case Primitive::kPrimVoid:
1172       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1173   }
1174 }
1175 
VisitArraySet(HArraySet * instruction)1176 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
1177   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1178   Primitive::Type value_type = instruction->InputAt(2)->GetType();
1179   if (value_type == Primitive::kPrimNot) {
1180     InvokeRuntimeCallingConvention calling_convention;
1181     locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1182     locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1183     locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
1184     codegen_->MarkNotLeaf();
1185   } else {
1186     locations->SetInAt(0, Location::RequiresRegister());
1187     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1188     locations->SetInAt(2, Location::RequiresRegister());
1189   }
1190   instruction->SetLocations(locations);
1191 }
1192 
VisitArraySet(HArraySet * instruction)1193 void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1194   LocationSummary* locations = instruction->GetLocations();
1195   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1196   Location index = locations->InAt(1);
1197   Primitive::Type value_type = instruction->InputAt(2)->GetType();
1198 
1199   switch (value_type) {
1200     case Primitive::kPrimBoolean:
1201     case Primitive::kPrimByte: {
1202       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1203       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1204       if (index.IsConstant()) {
1205         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1206         __ movb(Address(obj, offset), value);
1207       } else {
1208         __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1209       }
1210       break;
1211     }
1212 
1213     case Primitive::kPrimShort:
1214     case Primitive::kPrimChar: {
1215       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1216       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1217       if (index.IsConstant()) {
1218         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1219         __ movw(Address(obj, offset), value);
1220       } else {
1221         __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1222       }
1223       break;
1224     }
1225 
1226     case Primitive::kPrimInt: {
1227       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1228       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1229       if (index.IsConstant()) {
1230         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1231         __ movl(Address(obj, offset), value);
1232       } else {
1233         __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1234       }
1235       break;
1236     }
1237 
1238     case Primitive::kPrimNot: {
1239       __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1240       DCHECK(!codegen_->IsLeafMethod());
1241       codegen_->RecordPcInfo(instruction->GetDexPc());
1242       break;
1243     }
1244 
1245     case Primitive::kPrimLong: {
1246       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1247       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1248       if (index.IsConstant()) {
1249         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1250         __ movq(Address(obj, offset), value);
1251       } else {
1252         __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1253       }
1254       break;
1255     }
1256 
1257     case Primitive::kPrimFloat:
1258     case Primitive::kPrimDouble:
1259       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1260 
1261     case Primitive::kPrimVoid:
1262       LOG(FATAL) << "Unreachable type " << instruction->GetType();
1263   }
1264 }
1265 
VisitArrayLength(HArrayLength * instruction)1266 void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
1267   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1268   locations->SetInAt(0, Location::RequiresRegister());
1269   locations->SetOut(Location::RequiresRegister());
1270   instruction->SetLocations(locations);
1271 }
1272 
VisitArrayLength(HArrayLength * instruction)1273 void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1274   LocationSummary* locations = instruction->GetLocations();
1275   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1276   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1277   CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1278   __ movl(out, Address(obj, offset));
1279 }
1280 
VisitBoundsCheck(HBoundsCheck * instruction)1281 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1282   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1283   locations->SetInAt(0, Location::RequiresRegister());
1284   locations->SetInAt(1, Location::RequiresRegister());
1285   // TODO: Have a normalization phase that makes this instruction never used.
1286   locations->SetOut(Location::SameAsFirstInput());
1287   instruction->SetLocations(locations);
1288 }
1289 
VisitBoundsCheck(HBoundsCheck * instruction)1290 void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1291   LocationSummary* locations = instruction->GetLocations();
1292   SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
1293       instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1294   codegen_->AddSlowPath(slow_path);
1295 
1296   CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1297   CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1298 
1299   __ cmpl(index, length);
1300   __ j(kAboveEqual, slow_path->GetEntryLabel());
1301 }
1302 
MarkGCCard(CpuRegister temp,CpuRegister card,CpuRegister object,CpuRegister value)1303 void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1304                                      CpuRegister card,
1305                                      CpuRegister object,
1306                                      CpuRegister value) {
1307   Label is_null;
1308   __ testl(value, value);
1309   __ j(kEqual, &is_null);
1310   __ gs()->movq(card, Address::Absolute(
1311       Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1312   __ movq(temp, object);
1313   __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1314   __ movb(Address(temp, card, TIMES_1, 0),  card);
1315   __ Bind(&is_null);
1316 }
1317 
VisitTemporary(HTemporary * temp)1318 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1319   temp->SetLocations(nullptr);
1320 }
1321 
VisitTemporary(HTemporary * temp)1322 void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1323   // Nothing to do, this is driven by the code generator.
1324 }
1325 
VisitParallelMove(HParallelMove * instruction)1326 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1327   LOG(FATAL) << "Unimplemented";
1328 }
1329 
VisitParallelMove(HParallelMove * instruction)1330 void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
1331   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1332 }
1333 
GetAssembler() const1334 X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1335   return codegen_->GetAssembler();
1336 }
1337 
EmitMove(size_t index)1338 void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1339   MoveOperands* move = moves_.Get(index);
1340   Location source = move->GetSource();
1341   Location destination = move->GetDestination();
1342 
1343   if (source.IsRegister()) {
1344     if (destination.IsRegister()) {
1345       __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1346     } else if (destination.IsStackSlot()) {
1347       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1348               source.AsX86_64().AsCpuRegister());
1349     } else {
1350       DCHECK(destination.IsDoubleStackSlot());
1351       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1352               source.AsX86_64().AsCpuRegister());
1353     }
1354   } else if (source.IsStackSlot()) {
1355     if (destination.IsRegister()) {
1356       __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1357               Address(CpuRegister(RSP), source.GetStackIndex()));
1358     } else {
1359       DCHECK(destination.IsStackSlot());
1360       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1361       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1362     }
1363   } else if (source.IsDoubleStackSlot()) {
1364     if (destination.IsRegister()) {
1365       __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1366               Address(CpuRegister(RSP), source.GetStackIndex()));
1367     } else {
1368       DCHECK(destination.IsDoubleStackSlot());
1369       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1370       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1371     }
1372   } else if (source.IsConstant()) {
1373     HConstant* constant = source.GetConstant();
1374     if (constant->IsIntConstant()) {
1375       Immediate imm(constant->AsIntConstant()->GetValue());
1376       if (destination.IsRegister()) {
1377         __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1378       } else {
1379         __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1380       }
1381     } else if (constant->IsLongConstant()) {
1382       int64_t value = constant->AsLongConstant()->GetValue();
1383       if (destination.IsRegister()) {
1384         __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1385       } else {
1386         __ movq(CpuRegister(TMP), Immediate(value));
1387         __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1388       }
1389     } else {
1390       LOG(FATAL) << "Unimplemented constant type";
1391     }
1392   } else {
1393     LOG(FATAL) << "Unimplemented";
1394   }
1395 }
1396 
Exchange32(CpuRegister reg,int mem)1397 void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
1398   __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1399   __ movl(Address(CpuRegister(RSP), mem), reg);
1400   __ movl(reg, CpuRegister(TMP));
1401 }
1402 
Exchange32(int mem1,int mem2)1403 void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
1404   ScratchRegisterScope ensure_scratch(
1405       this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1406 
1407   int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1408   __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1409   __ movl(CpuRegister(ensure_scratch.GetRegister()),
1410           Address(CpuRegister(RSP), mem2 + stack_offset));
1411   __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1412   __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1413           CpuRegister(ensure_scratch.GetRegister()));
1414 }
1415 
Exchange64(CpuRegister reg,int mem)1416 void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1417   __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1418   __ movq(Address(CpuRegister(RSP), mem), reg);
1419   __ movq(reg, CpuRegister(TMP));
1420 }
1421 
Exchange64(int mem1,int mem2)1422 void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1423   ScratchRegisterScope ensure_scratch(
1424       this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1425 
1426   int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1427   __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1428   __ movq(CpuRegister(ensure_scratch.GetRegister()),
1429           Address(CpuRegister(RSP), mem2 + stack_offset));
1430   __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1431   __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1432           CpuRegister(ensure_scratch.GetRegister()));
1433 }
1434 
EmitSwap(size_t index)1435 void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1436   MoveOperands* move = moves_.Get(index);
1437   Location source = move->GetSource();
1438   Location destination = move->GetDestination();
1439 
1440   if (source.IsRegister() && destination.IsRegister()) {
1441     __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1442   } else if (source.IsRegister() && destination.IsStackSlot()) {
1443     Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1444   } else if (source.IsStackSlot() && destination.IsRegister()) {
1445     Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1446   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1447     Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1448   } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1449     Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1450   } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1451     Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1452   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1453     Exchange64(destination.GetStackIndex(), source.GetStackIndex());
1454   } else {
1455     LOG(FATAL) << "Unimplemented";
1456   }
1457 }
1458 
1459 
SpillScratch(int reg)1460 void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1461   __ pushq(CpuRegister(reg));
1462 }
1463 
1464 
RestoreScratch(int reg)1465 void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1466   __ popq(CpuRegister(reg));
1467 }
1468 
1469 }  // namespace x86_64
1470 }  // namespace art
1471