blob: 2ff2a1710ef5a64ae66447dd636097b98b26617a [file] [log] [blame]
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001/*
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"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010021#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"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010026#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010027#include "utils/x86_64/assembler_x86_64.h"
28#include "utils/x86_64/managed_register_x86_64.h"
29
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030namespace art {
31
32x86_64::X86_64ManagedRegister Location::AsX86_64() const {
33 return reg().AsX86_64();
34}
35
36namespace x86_64 {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038static 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
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010046static Location X86_64CpuLocation(Register reg) {
47 return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
48}
49
50static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
51static constexpr size_t kRuntimeParameterCoreRegistersLength =
52 arraysize(kRuntimeParameterCoreRegisters);
53
54class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
55 public:
56 InvokeRuntimeCallingConvention()
57 : CallingConvention(kRuntimeParameterCoreRegisters,
58 kRuntimeParameterCoreRegistersLength) {}
59
60 private:
61 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
62};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010063
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
65
66class NullCheckSlowPathX86_64 : public SlowPathCode {
67 public:
68 explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
69
70 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
71 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010072 __ gs()->call(
73 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074 codegen->RecordPcInfo(dex_pc_);
75 }
76
77 private:
78 const uint32_t dex_pc_;
79 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
80};
81
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010082class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
83 public:
84 StackOverflowCheckSlowPathX86_64() {}
85
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
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010098class BoundsCheckSlowPathX86_64 : public SlowPathCode {
99 public:
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
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
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100124#undef __
125#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
126
Dave Allison20dfc792014-06-16 20:44:29 -0700127inline 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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100141void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
142 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
143}
144
145void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
146 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
147}
148
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100149CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
150 : CodeGenerator(graph, kNumberOfRegIds),
151 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000152 instruction_visitor_(graph, this),
153 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100154
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100155size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
156 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
157}
158
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
160 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100161 : HGraphVisitor(graph),
162 assembler_(codegen->GetAssembler()),
163 codegen_(codegen) {}
164
165ManagedRegister 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
190void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
191 // Stack register is always reserved.
192 blocked_registers[RSP] = true;
193
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000194 // Block the register used as TMP.
195 blocked_registers[TMP] = true;
196
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100197 // 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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100206void 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.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100212 __ subq(CpuRegister(RSP),
213 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
214
215 bool skip_overflow_check = IsLeafMethod()
216 && !IsLargeFrame(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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100232 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
233}
234
235void CodeGeneratorX86_64::GenerateFrameExit() {
236 __ addq(CpuRegister(RSP),
237 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
238}
239
240void CodeGeneratorX86_64::Bind(Label* label) {
241 __ Bind(label);
242}
243
244void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
245 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
246}
247
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100248Location 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
274void 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());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000292 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
293 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100294 }
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());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000301 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
302 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100303 }
304 }
305}
306
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100307void CodeGeneratorX86_64::Move(HInstruction* instruction,
308 Location location,
309 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100310 if (instruction->AsIntConstant() != nullptr) {
311 Immediate imm(instruction->AsIntConstant()->GetValue());
312 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000313 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100314 } 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 {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000322 __ movq(CpuRegister(TMP), Immediate(value));
323 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100324 }
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 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100344 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100345 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
362void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
363 got->SetLocations(nullptr);
364}
365
366void 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
375void LocationsBuilderX86_64::VisitExit(HExit* exit) {
376 exit->SetLocations(nullptr);
377}
378
379void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
380 if (kIsDebugBuild) {
381 __ Comment("Unreachable");
382 __ int3();
383 }
384}
385
386void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
387 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100388 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 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100394 if_instr->SetLocations(locations);
395}
396
397void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700398 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);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100413 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 }
Dave Allison20dfc792014-06-16 20:44:29 -0700421 __ 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()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426 }
427}
428
429void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
430 local->SetLocations(nullptr);
431}
432
433void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
434 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
435}
436
437void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
438 local->SetLocations(nullptr);
439}
440
441void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
442 // Nothing to do, this is driven by the code generator.
443}
444
445void 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
467void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
468}
469
Dave Allison20dfc792014-06-16 20:44:29 -0700470void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
471 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000472 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100473 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100474 if (comp->NeedsMaterialization()) {
475 locations->SetOut(Location::RequiresRegister());
476 }
Dave Allison20dfc792014-06-16 20:44:29 -0700477 comp->SetLocations(locations);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100478}
479
Dave Allison20dfc792014-06-16 20:44:29 -0700480void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
481 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100482 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 }
Dave Allison20dfc792014-06-16 20:44:29 -0700493 __ setcc(X86_64Condition(comp->GetCondition()),
494 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
495 }
496}
497
498void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
499 VisitCondition(comp);
500}
501
502void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
503 VisitCondition(comp);
504}
505
506void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
507 VisitCondition(comp);
508}
509
510void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
511 VisitCondition(comp);
512}
513
514void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
515 VisitCondition(comp);
516}
517
518void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
519 VisitCondition(comp);
520}
521
522void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
523 VisitCondition(comp);
524}
525
526void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
527 VisitCondition(comp);
528}
529
530void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
531 VisitCondition(comp);
532}
533
534void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
535 VisitCondition(comp);
536}
537
538void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
539 VisitCondition(comp);
540}
541
542void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
543 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100544}
545
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100546void 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
554void 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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100579void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100580 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100581 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100582 constant->SetLocations(locations);
583}
584
585void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586}
587
588void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100589 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100590 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100591 constant->SetLocations(locations);
592}
593
594void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100595}
596
597void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
598 ret->SetLocations(nullptr);
599}
600
601void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
602 codegen_->GenerateFrameExit();
603 __ ret();
604}
605
606void 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
625void 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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100646Location 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
687void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100688 codegen_->MarkNotLeaf();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100689 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
721void 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().SizeValue()));
742
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100743 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100744 codegen_->RecordPcInfo(invoke->GetDexPc());
745}
746
747void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
748 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
749 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100750 case Primitive::kPrimInt: {
751 locations->SetInAt(0, Location::RequiresRegister());
752 locations->SetInAt(1, Location::Any());
753 locations->SetOut(Location::SameAsFirstInput());
754 break;
755 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100756 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000757 locations->SetInAt(0, Location::RequiresRegister());
758 locations->SetInAt(1, Location::RequiresRegister());
759 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100760 break;
761 }
762
763 case Primitive::kPrimBoolean:
764 case Primitive::kPrimByte:
765 case Primitive::kPrimChar:
766 case Primitive::kPrimShort:
767 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
768 break;
769
770 default:
771 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
772 }
773 add->SetLocations(locations);
774}
775
776void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
777 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000778 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
779 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100780 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000781 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100782 if (locations->InAt(1).IsRegister()) {
783 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
784 locations->InAt(1).AsX86_64().AsCpuRegister());
785 } else if (locations->InAt(1).IsConstant()) {
786 HConstant* instruction = locations->InAt(1).GetConstant();
787 Immediate imm(instruction->AsIntConstant()->GetValue());
788 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
789 } else {
790 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
791 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
792 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000793 break;
794 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100795 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100796 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
797 locations->InAt(1).AsX86_64().AsCpuRegister());
798 break;
799 }
800
801 case Primitive::kPrimBoolean:
802 case Primitive::kPrimByte:
803 case Primitive::kPrimChar:
804 case Primitive::kPrimShort:
805 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
806 break;
807
808 default:
809 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
810 }
811}
812
813void LocationsBuilderX86_64::VisitSub(HSub* sub) {
814 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
815 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100816 case Primitive::kPrimInt: {
817 locations->SetInAt(0, Location::RequiresRegister());
818 locations->SetInAt(1, Location::Any());
819 locations->SetOut(Location::SameAsFirstInput());
820 break;
821 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100822 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000823 locations->SetInAt(0, Location::RequiresRegister());
824 locations->SetInAt(1, Location::RequiresRegister());
825 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100826 break;
827 }
828
829 case Primitive::kPrimBoolean:
830 case Primitive::kPrimByte:
831 case Primitive::kPrimChar:
832 case Primitive::kPrimShort:
833 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
834 break;
835
836 default:
837 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
838 }
839 sub->SetLocations(locations);
840}
841
842void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
843 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000844 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
845 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100846 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000847 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100848 if (locations->InAt(1).IsRegister()) {
849 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
850 locations->InAt(1).AsX86_64().AsCpuRegister());
851 } else if (locations->InAt(1).IsConstant()) {
852 HConstant* instruction = locations->InAt(1).GetConstant();
853 Immediate imm(instruction->AsIntConstant()->GetValue());
854 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
855 } else {
856 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
857 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
858 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000859 break;
860 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100861 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100862 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
863 locations->InAt(1).AsX86_64().AsCpuRegister());
864 break;
865 }
866
867 case Primitive::kPrimBoolean:
868 case Primitive::kPrimByte:
869 case Primitive::kPrimChar:
870 case Primitive::kPrimShort:
871 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
872 break;
873
874 default:
875 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
876 }
877}
878
879void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100880 codegen_->MarkNotLeaf();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100881 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
882 locations->SetOut(X86_64CpuLocation(RAX));
883 instruction->SetLocations(locations);
884}
885
886void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
887 InvokeRuntimeCallingConvention calling_convention;
888 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
889 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
890
891 __ gs()->call(Address::Absolute(
892 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
893
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100894 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100895 codegen_->RecordPcInfo(instruction->GetDexPc());
896}
897
898void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
899 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
900 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
901 if (location.IsStackSlot()) {
902 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
903 } else if (location.IsDoubleStackSlot()) {
904 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
905 }
906 locations->SetOut(location);
907 instruction->SetLocations(locations);
908}
909
910void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
911 // Nothing to do, the parameter is already at its location.
912}
913
914void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
915 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000916 locations->SetInAt(0, Location::RequiresRegister());
917 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100918 instruction->SetLocations(locations);
919}
920
921void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
922 LocationSummary* locations = instruction->GetLocations();
923 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
924 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
925 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
926}
927
928void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
929 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
930 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
931 locations->SetInAt(i, Location::Any());
932 }
933 locations->SetOut(Location::Any());
934 instruction->SetLocations(locations);
935}
936
937void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
938 LOG(FATAL) << "Unimplemented";
939}
940
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100941void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
942 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
943 locations->SetInAt(0, Location::RequiresRegister());
944 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100945 // Temporary registers for the write barrier.
946 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
947 locations->AddTemp(Location::RequiresRegister());
948 locations->AddTemp(Location::RequiresRegister());
949 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100950 instruction->SetLocations(locations);
951}
952
953void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
954 LocationSummary* locations = instruction->GetLocations();
955 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
956 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
957 size_t offset = instruction->GetFieldOffset().SizeValue();
958 Primitive::Type field_type = instruction->InputAt(1)->GetType();
959
960 switch (field_type) {
961 case Primitive::kPrimBoolean:
962 case Primitive::kPrimByte: {
963 __ movb(Address(obj, offset), value);
964 break;
965 }
966
967 case Primitive::kPrimShort:
968 case Primitive::kPrimChar: {
969 __ movw(Address(obj, offset), value);
970 break;
971 }
972
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100973 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100974 case Primitive::kPrimNot: {
975 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100976 if (field_type == Primitive::kPrimNot) {
977 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
978 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
979 codegen_->MarkGCCard(temp, card, obj, value);
980 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100981 break;
982 }
983
984 case Primitive::kPrimLong: {
985 __ movq(Address(obj, offset), value);
986 break;
987 }
988
989 case Primitive::kPrimFloat:
990 case Primitive::kPrimDouble:
991 LOG(FATAL) << "Unimplemented register type " << field_type;
992
993 case Primitive::kPrimVoid:
994 LOG(FATAL) << "Unreachable type " << field_type;
995 }
996}
997
998void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
999 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1000 locations->SetInAt(0, Location::RequiresRegister());
1001 locations->SetOut(Location::RequiresRegister());
1002 instruction->SetLocations(locations);
1003}
1004
1005void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1006 LocationSummary* locations = instruction->GetLocations();
1007 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1008 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1009 size_t offset = instruction->GetFieldOffset().SizeValue();
1010
1011 switch (instruction->GetType()) {
1012 case Primitive::kPrimBoolean: {
1013 __ movzxb(out, Address(obj, offset));
1014 break;
1015 }
1016
1017 case Primitive::kPrimByte: {
1018 __ movsxb(out, Address(obj, offset));
1019 break;
1020 }
1021
1022 case Primitive::kPrimShort: {
1023 __ movsxw(out, Address(obj, offset));
1024 break;
1025 }
1026
1027 case Primitive::kPrimChar: {
1028 __ movzxw(out, Address(obj, offset));
1029 break;
1030 }
1031
1032 case Primitive::kPrimInt:
1033 case Primitive::kPrimNot: {
1034 __ movl(out, Address(obj, offset));
1035 break;
1036 }
1037
1038 case Primitive::kPrimLong: {
1039 __ movq(out, Address(obj, offset));
1040 break;
1041 }
1042
1043 case Primitive::kPrimFloat:
1044 case Primitive::kPrimDouble:
1045 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1046
1047 case Primitive::kPrimVoid:
1048 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1049 }
1050}
1051
1052void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
1053 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1054 locations->SetInAt(0, Location::Any());
1055 // TODO: Have a normalization phase that makes this instruction never used.
1056 locations->SetOut(Location::SameAsFirstInput());
1057 instruction->SetLocations(locations);
1058}
1059
1060void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
1061 SlowPathCode* slow_path =
1062 new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
1063 codegen_->AddSlowPath(slow_path);
1064
1065 LocationSummary* locations = instruction->GetLocations();
1066 Location obj = locations->InAt(0);
1067 DCHECK(obj.Equals(locations->Out()));
1068
1069 if (obj.IsRegister()) {
1070 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1071 } else {
1072 DCHECK(locations->InAt(0).IsStackSlot());
1073 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1074 }
1075 __ j(kEqual, slow_path->GetEntryLabel());
1076}
1077
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001078void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
1079 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1080 locations->SetInAt(0, Location::RequiresRegister());
1081 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1082 locations->SetOut(Location::RequiresRegister());
1083 instruction->SetLocations(locations);
1084}
1085
1086void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1087 LocationSummary* locations = instruction->GetLocations();
1088 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1089 Location index = locations->InAt(1);
1090
1091 switch (instruction->GetType()) {
1092 case Primitive::kPrimBoolean: {
1093 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1094 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1095 if (index.IsConstant()) {
1096 __ movzxb(out, Address(obj,
1097 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1098 } else {
1099 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1100 }
1101 break;
1102 }
1103
1104 case Primitive::kPrimByte: {
1105 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1106 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1107 if (index.IsConstant()) {
1108 __ movsxb(out, Address(obj,
1109 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1110 } else {
1111 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1112 }
1113 break;
1114 }
1115
1116 case Primitive::kPrimShort: {
1117 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1118 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1119 if (index.IsConstant()) {
1120 __ movsxw(out, Address(obj,
1121 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1122 } else {
1123 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1124 }
1125 break;
1126 }
1127
1128 case Primitive::kPrimChar: {
1129 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1130 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1131 if (index.IsConstant()) {
1132 __ movzxw(out, Address(obj,
1133 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1134 } else {
1135 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1136 }
1137 break;
1138 }
1139
1140 case Primitive::kPrimInt:
1141 case Primitive::kPrimNot: {
1142 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1143 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1144 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1145 if (index.IsConstant()) {
1146 __ movl(out, Address(obj,
1147 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1148 } else {
1149 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1150 }
1151 break;
1152 }
1153
1154 case Primitive::kPrimLong: {
1155 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1156 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1157 if (index.IsConstant()) {
1158 __ movq(out, Address(obj,
1159 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1160 } else {
1161 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1162 }
1163 break;
1164 }
1165
1166 case Primitive::kPrimFloat:
1167 case Primitive::kPrimDouble:
1168 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1169
1170 case Primitive::kPrimVoid:
1171 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1172 }
1173}
1174
1175void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
1176 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1177 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1178 if (value_type == Primitive::kPrimNot) {
1179 InvokeRuntimeCallingConvention calling_convention;
1180 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1181 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1182 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
1183 codegen_->MarkNotLeaf();
1184 } else {
1185 locations->SetInAt(0, Location::RequiresRegister());
1186 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1187 locations->SetInAt(2, Location::RequiresRegister());
1188 }
1189 instruction->SetLocations(locations);
1190}
1191
1192void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1193 LocationSummary* locations = instruction->GetLocations();
1194 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1195 Location index = locations->InAt(1);
1196 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1197
1198 switch (value_type) {
1199 case Primitive::kPrimBoolean:
1200 case Primitive::kPrimByte: {
1201 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1202 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1203 if (index.IsConstant()) {
1204 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1205 __ movb(Address(obj, offset), value);
1206 } else {
1207 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1208 }
1209 break;
1210 }
1211
1212 case Primitive::kPrimShort:
1213 case Primitive::kPrimChar: {
1214 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1215 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1216 if (index.IsConstant()) {
1217 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1218 __ movw(Address(obj, offset), value);
1219 } else {
1220 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1221 }
1222 break;
1223 }
1224
1225 case Primitive::kPrimInt: {
1226 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1227 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1228 if (index.IsConstant()) {
1229 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1230 __ movl(Address(obj, offset), value);
1231 } else {
1232 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1233 }
1234 break;
1235 }
1236
1237 case Primitive::kPrimNot: {
1238 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1239 DCHECK(!codegen_->IsLeafMethod());
1240 codegen_->RecordPcInfo(instruction->GetDexPc());
1241 break;
1242 }
1243
1244 case Primitive::kPrimLong: {
1245 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1246 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1247 if (index.IsConstant()) {
1248 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1249 __ movq(Address(obj, offset), value);
1250 } else {
1251 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1252 }
1253 break;
1254 }
1255
1256 case Primitive::kPrimFloat:
1257 case Primitive::kPrimDouble:
1258 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1259
1260 case Primitive::kPrimVoid:
1261 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1262 }
1263}
1264
1265void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
1266 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1267 locations->SetInAt(0, Location::RequiresRegister());
1268 locations->SetOut(Location::RequiresRegister());
1269 instruction->SetLocations(locations);
1270}
1271
1272void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1273 LocationSummary* locations = instruction->GetLocations();
1274 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1275 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1276 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1277 __ movl(out, Address(obj, offset));
1278}
1279
1280void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1281 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1282 locations->SetInAt(0, Location::RequiresRegister());
1283 locations->SetInAt(1, Location::RequiresRegister());
1284 // TODO: Have a normalization phase that makes this instruction never used.
1285 locations->SetOut(Location::SameAsFirstInput());
1286 instruction->SetLocations(locations);
1287}
1288
1289void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1290 LocationSummary* locations = instruction->GetLocations();
1291 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
1292 instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1293 codegen_->AddSlowPath(slow_path);
1294
1295 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1296 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1297
1298 __ cmpl(index, length);
1299 __ j(kAboveEqual, slow_path->GetEntryLabel());
1300}
1301
1302void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1303 CpuRegister card,
1304 CpuRegister object,
1305 CpuRegister value) {
1306 Label is_null;
1307 __ testl(value, value);
1308 __ j(kEqual, &is_null);
1309 __ gs()->movq(card, Address::Absolute(
1310 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1311 __ movq(temp, object);
1312 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1313 __ movb(Address(temp, card, TIMES_1, 0), card);
1314 __ Bind(&is_null);
1315}
1316
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001317void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1318 temp->SetLocations(nullptr);
1319}
1320
1321void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1322 // Nothing to do, this is driven by the code generator.
1323}
1324
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001325void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1326 LOG(FATAL) << "Unimplemented";
1327}
1328
1329void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001330 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1331}
1332
1333X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1334 return codegen_->GetAssembler();
1335}
1336
1337void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1338 MoveOperands* move = moves_.Get(index);
1339 Location source = move->GetSource();
1340 Location destination = move->GetDestination();
1341
1342 if (source.IsRegister()) {
1343 if (destination.IsRegister()) {
1344 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001345 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001346 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1347 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001348 } else {
1349 DCHECK(destination.IsDoubleStackSlot());
1350 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1351 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001352 }
1353 } else if (source.IsStackSlot()) {
1354 if (destination.IsRegister()) {
1355 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1356 Address(CpuRegister(RSP), source.GetStackIndex()));
1357 } else {
1358 DCHECK(destination.IsStackSlot());
1359 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1360 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1361 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001362 } else if (source.IsDoubleStackSlot()) {
1363 if (destination.IsRegister()) {
1364 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1365 Address(CpuRegister(RSP), source.GetStackIndex()));
1366 } else {
1367 DCHECK(destination.IsDoubleStackSlot());
1368 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1369 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1370 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001371 } else if (source.IsConstant()) {
1372 HConstant* constant = source.GetConstant();
1373 if (constant->IsIntConstant()) {
1374 Immediate imm(constant->AsIntConstant()->GetValue());
1375 if (destination.IsRegister()) {
1376 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1377 } else {
1378 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1379 }
1380 } else if (constant->IsLongConstant()) {
1381 int64_t value = constant->AsLongConstant()->GetValue();
1382 if (destination.IsRegister()) {
1383 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1384 } else {
1385 __ movq(CpuRegister(TMP), Immediate(value));
1386 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1387 }
1388 } else {
1389 LOG(FATAL) << "Unimplemented constant type";
1390 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001391 } else {
1392 LOG(FATAL) << "Unimplemented";
1393 }
1394}
1395
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001396void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001397 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001398 __ movl(Address(CpuRegister(RSP), mem), reg);
1399 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001400}
1401
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001402void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001403 ScratchRegisterScope ensure_scratch(
1404 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1405
1406 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1407 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1408 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1409 Address(CpuRegister(RSP), mem2 + stack_offset));
1410 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1411 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1412 CpuRegister(ensure_scratch.GetRegister()));
1413}
1414
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001415void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1416 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1417 __ movq(Address(CpuRegister(RSP), mem), reg);
1418 __ movq(reg, CpuRegister(TMP));
1419}
1420
1421void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1422 ScratchRegisterScope ensure_scratch(
1423 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1424
1425 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1426 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1427 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1428 Address(CpuRegister(RSP), mem2 + stack_offset));
1429 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1430 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1431 CpuRegister(ensure_scratch.GetRegister()));
1432}
1433
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001434void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1435 MoveOperands* move = moves_.Get(index);
1436 Location source = move->GetSource();
1437 Location destination = move->GetDestination();
1438
1439 if (source.IsRegister() && destination.IsRegister()) {
1440 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1441 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001442 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001443 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001444 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001445 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001446 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1447 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1448 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1449 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1450 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1451 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1452 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001453 } else {
1454 LOG(FATAL) << "Unimplemented";
1455 }
1456}
1457
1458
1459void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1460 __ pushq(CpuRegister(reg));
1461}
1462
1463
1464void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1465 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001466}
1467
1468} // namespace x86_64
1469} // namespace art