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