blob: c4571caf271105181ffaf39346ca4cf04218e68f [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 Geoffrayf6e206c2014-08-07 20:25:41 +010038static constexpr bool kExplicitStackOverflowCheck = false;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010039
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
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100211 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700212 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100213
214 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
215 __ testq(CpuRegister(RAX), Address(
216 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
217 RecordPcInfo(0);
218 }
219
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100220 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100221 __ subq(CpuRegister(RSP),
222 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
223
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100224 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
225 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
226 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100227
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100228 __ gs()->cmpq(CpuRegister(RSP),
229 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
230 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100231 }
232
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100233 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
234}
235
236void CodeGeneratorX86_64::GenerateFrameExit() {
237 __ addq(CpuRegister(RSP),
238 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
239}
240
241void CodeGeneratorX86_64::Bind(Label* label) {
242 __ Bind(label);
243}
244
245void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
246 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
247}
248
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100249Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
250 switch (load->GetType()) {
251 case Primitive::kPrimLong:
252 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
253 break;
254
255 case Primitive::kPrimInt:
256 case Primitive::kPrimNot:
257 return Location::StackSlot(GetStackSlot(load->GetLocal()));
258
259 case Primitive::kPrimFloat:
260 case Primitive::kPrimDouble:
261 LOG(FATAL) << "Unimplemented type " << load->GetType();
262
263 case Primitive::kPrimBoolean:
264 case Primitive::kPrimByte:
265 case Primitive::kPrimChar:
266 case Primitive::kPrimShort:
267 case Primitive::kPrimVoid:
268 LOG(FATAL) << "Unexpected type " << load->GetType();
269 }
270
271 LOG(FATAL) << "Unreachable";
272 return Location();
273}
274
275void CodeGeneratorX86_64::Move(Location destination, Location source) {
276 if (source.Equals(destination)) {
277 return;
278 }
279 if (destination.IsRegister()) {
280 if (source.IsRegister()) {
281 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
282 } else if (source.IsStackSlot()) {
283 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
284 } else {
285 DCHECK(source.IsDoubleStackSlot());
286 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
287 }
288 } else if (destination.IsStackSlot()) {
289 if (source.IsRegister()) {
290 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
291 } else {
292 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000293 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
294 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100295 }
296 } else {
297 DCHECK(destination.IsDoubleStackSlot());
298 if (source.IsRegister()) {
299 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
300 } else {
301 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000302 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
303 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100304 }
305 }
306}
307
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100308void CodeGeneratorX86_64::Move(HInstruction* instruction,
309 Location location,
310 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100311 if (instruction->AsIntConstant() != nullptr) {
312 Immediate imm(instruction->AsIntConstant()->GetValue());
313 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000314 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100315 } else {
316 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
317 }
318 } else if (instruction->AsLongConstant() != nullptr) {
319 int64_t value = instruction->AsLongConstant()->GetValue();
320 if (location.IsRegister()) {
321 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
322 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000323 __ movq(CpuRegister(TMP), Immediate(value));
324 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100325 }
326 } else if (instruction->AsLoadLocal() != nullptr) {
327 switch (instruction->GetType()) {
328 case Primitive::kPrimBoolean:
329 case Primitive::kPrimByte:
330 case Primitive::kPrimChar:
331 case Primitive::kPrimShort:
332 case Primitive::kPrimInt:
333 case Primitive::kPrimNot:
334 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
335 break;
336
337 case Primitive::kPrimLong:
338 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
339 break;
340
341 default:
342 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
343 }
344 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100345 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100346 switch (instruction->GetType()) {
347 case Primitive::kPrimBoolean:
348 case Primitive::kPrimByte:
349 case Primitive::kPrimChar:
350 case Primitive::kPrimShort:
351 case Primitive::kPrimInt:
352 case Primitive::kPrimNot:
353 case Primitive::kPrimLong:
354 Move(location, instruction->GetLocations()->Out());
355 break;
356
357 default:
358 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
359 }
360 }
361}
362
363void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
364 got->SetLocations(nullptr);
365}
366
367void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
368 HBasicBlock* successor = got->GetSuccessor();
369 if (GetGraph()->GetExitBlock() == successor) {
370 codegen_->GenerateFrameExit();
371 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
372 __ jmp(codegen_->GetLabelOf(successor));
373 }
374}
375
376void LocationsBuilderX86_64::VisitExit(HExit* exit) {
377 exit->SetLocations(nullptr);
378}
379
380void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
381 if (kIsDebugBuild) {
382 __ Comment("Unreachable");
383 __ int3();
384 }
385}
386
387void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
388 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100389 HInstruction* cond = if_instr->InputAt(0);
390 DCHECK(cond->IsCondition());
391 HCondition* condition = cond->AsCondition();
392 if (condition->NeedsMaterialization()) {
393 locations->SetInAt(0, Location::Any());
394 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100395 if_instr->SetLocations(locations);
396}
397
398void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700399 HInstruction* cond = if_instr->InputAt(0);
400 DCHECK(cond->IsCondition());
401 HCondition* condition = cond->AsCondition();
402 if (condition->NeedsMaterialization()) {
403 // Materialized condition, compare against 0.
404 Location lhs = if_instr->GetLocations()->InAt(0);
405 if (lhs.IsRegister()) {
406 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
407 } else {
408 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
409 }
410 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
411 } else {
412 Location lhs = condition->GetLocations()->InAt(0);
413 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100414 if (rhs.IsRegister()) {
415 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
416 } else if (rhs.IsConstant()) {
417 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
418 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
419 } else {
420 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
421 }
Dave Allison20dfc792014-06-16 20:44:29 -0700422 __ j(X86_64Condition(condition->GetCondition()),
423 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
424 }
425 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
426 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100427 }
428}
429
430void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
431 local->SetLocations(nullptr);
432}
433
434void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
435 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
436}
437
438void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
439 local->SetLocations(nullptr);
440}
441
442void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
443 // Nothing to do, this is driven by the code generator.
444}
445
446void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
447 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
448 switch (store->InputAt(1)->GetType()) {
449 case Primitive::kPrimBoolean:
450 case Primitive::kPrimByte:
451 case Primitive::kPrimChar:
452 case Primitive::kPrimShort:
453 case Primitive::kPrimInt:
454 case Primitive::kPrimNot:
455 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
456 break;
457
458 case Primitive::kPrimLong:
459 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
460 break;
461
462 default:
463 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
464 }
465 store->SetLocations(locations);
466}
467
468void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
469}
470
Dave Allison20dfc792014-06-16 20:44:29 -0700471void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
472 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000473 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100474 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100475 if (comp->NeedsMaterialization()) {
476 locations->SetOut(Location::RequiresRegister());
477 }
Dave Allison20dfc792014-06-16 20:44:29 -0700478 comp->SetLocations(locations);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100479}
480
Dave Allison20dfc792014-06-16 20:44:29 -0700481void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
482 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100483 LocationSummary* locations = comp->GetLocations();
484 if (locations->InAt(1).IsRegister()) {
485 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
486 locations->InAt(1).AsX86_64().AsCpuRegister());
487 } else if (locations->InAt(1).IsConstant()) {
488 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
489 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
490 } else {
491 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
492 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
493 }
Dave Allison20dfc792014-06-16 20:44:29 -0700494 __ setcc(X86_64Condition(comp->GetCondition()),
495 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
496 }
497}
498
499void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
500 VisitCondition(comp);
501}
502
503void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
504 VisitCondition(comp);
505}
506
507void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
508 VisitCondition(comp);
509}
510
511void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
512 VisitCondition(comp);
513}
514
515void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
516 VisitCondition(comp);
517}
518
519void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
520 VisitCondition(comp);
521}
522
523void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
524 VisitCondition(comp);
525}
526
527void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
528 VisitCondition(comp);
529}
530
531void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
532 VisitCondition(comp);
533}
534
535void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
536 VisitCondition(comp);
537}
538
539void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
540 VisitCondition(comp);
541}
542
543void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
544 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100545}
546
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100547void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
548 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
549 locations->SetInAt(0, Location::RequiresRegister());
550 locations->SetInAt(1, Location::RequiresRegister());
551 locations->SetOut(Location::RequiresRegister());
552 compare->SetLocations(locations);
553}
554
555void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
556 Label greater, done;
557 LocationSummary* locations = compare->GetLocations();
558 switch (compare->InputAt(0)->GetType()) {
559 case Primitive::kPrimLong:
560 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
561 locations->InAt(1).AsX86_64().AsCpuRegister());
562 break;
563 default:
564 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
565 }
566
567 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
568 __ j(kEqual, &done);
569 __ j(kGreater, &greater);
570
571 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
572 __ jmp(&done);
573
574 __ Bind(&greater);
575 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
576
577 __ Bind(&done);
578}
579
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100580void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100581 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100582 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100583 constant->SetLocations(locations);
584}
585
586void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100587}
588
589void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100590 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100591 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100592 constant->SetLocations(locations);
593}
594
595void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100596}
597
598void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
599 ret->SetLocations(nullptr);
600}
601
602void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
603 codegen_->GenerateFrameExit();
604 __ ret();
605}
606
607void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
608 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
609 switch (ret->InputAt(0)->GetType()) {
610 case Primitive::kPrimBoolean:
611 case Primitive::kPrimByte:
612 case Primitive::kPrimChar:
613 case Primitive::kPrimShort:
614 case Primitive::kPrimInt:
615 case Primitive::kPrimNot:
616 case Primitive::kPrimLong:
617 locations->SetInAt(0, X86_64CpuLocation(RAX));
618 break;
619
620 default:
621 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
622 }
623 ret->SetLocations(locations);
624}
625
626void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
627 if (kIsDebugBuild) {
628 switch (ret->InputAt(0)->GetType()) {
629 case Primitive::kPrimBoolean:
630 case Primitive::kPrimByte:
631 case Primitive::kPrimChar:
632 case Primitive::kPrimShort:
633 case Primitive::kPrimInt:
634 case Primitive::kPrimNot:
635 case Primitive::kPrimLong:
636 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
637 break;
638
639 default:
640 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
641 }
642 }
643 codegen_->GenerateFrameExit();
644 __ ret();
645}
646
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100647Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
648 switch (type) {
649 case Primitive::kPrimBoolean:
650 case Primitive::kPrimByte:
651 case Primitive::kPrimChar:
652 case Primitive::kPrimShort:
653 case Primitive::kPrimInt:
654 case Primitive::kPrimNot: {
655 uint32_t index = gp_index_++;
656 stack_index_++;
657 if (index < calling_convention.GetNumberOfRegisters()) {
658 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
659 } else {
660 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
661 }
662 }
663
664 case Primitive::kPrimLong: {
665 uint32_t index = gp_index_;
666 stack_index_ += 2;
667 if (index < calling_convention.GetNumberOfRegisters()) {
668 gp_index_ += 1;
669 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
670 } else {
671 gp_index_ += 2;
672 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
673 }
674 }
675
676 case Primitive::kPrimDouble:
677 case Primitive::kPrimFloat:
678 LOG(FATAL) << "Unimplemented parameter type " << type;
679 break;
680
681 case Primitive::kPrimVoid:
682 LOG(FATAL) << "Unexpected parameter type " << type;
683 break;
684 }
685 return Location();
686}
687
688void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100689 codegen_->MarkNotLeaf();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100690 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
691 locations->AddTemp(X86_64CpuLocation(RDI));
692
693 InvokeDexCallingConventionVisitor calling_convention_visitor;
694 for (size_t i = 0; i < invoke->InputCount(); ++i) {
695 HInstruction* input = invoke->InputAt(i);
696 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
697 }
698
699 switch (invoke->GetType()) {
700 case Primitive::kPrimBoolean:
701 case Primitive::kPrimByte:
702 case Primitive::kPrimChar:
703 case Primitive::kPrimShort:
704 case Primitive::kPrimInt:
705 case Primitive::kPrimNot:
706 case Primitive::kPrimLong:
707 locations->SetOut(X86_64CpuLocation(RAX));
708 break;
709
710 case Primitive::kPrimVoid:
711 break;
712
713 case Primitive::kPrimDouble:
714 case Primitive::kPrimFloat:
715 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
716 break;
717 }
718
719 invoke->SetLocations(locations);
720}
721
722void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
723 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
724 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
725 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
726 invoke->GetIndexInDexCache() * heap_reference_size;
727
728 // TODO: Implement all kinds of calls:
729 // 1) boot -> boot
730 // 2) app -> boot
731 // 3) app -> app
732 //
733 // Currently we implement the app -> app logic, which looks up in the resolve cache.
734
735 // temp = method;
736 LoadCurrentMethod(temp);
737 // temp = temp->dex_cache_resolved_methods_;
738 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
739 // temp = temp[index_in_cache]
740 __ movl(temp, Address(temp, index_in_cache));
741 // (temp + offset_of_quick_compiled_code)()
742 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
743
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100744 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100745 codegen_->RecordPcInfo(invoke->GetDexPc());
746}
747
748void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
749 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
750 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100751 case Primitive::kPrimInt: {
752 locations->SetInAt(0, Location::RequiresRegister());
753 locations->SetInAt(1, Location::Any());
754 locations->SetOut(Location::SameAsFirstInput());
755 break;
756 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100757 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000758 locations->SetInAt(0, Location::RequiresRegister());
759 locations->SetInAt(1, Location::RequiresRegister());
760 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100761 break;
762 }
763
764 case Primitive::kPrimBoolean:
765 case Primitive::kPrimByte:
766 case Primitive::kPrimChar:
767 case Primitive::kPrimShort:
768 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
769 break;
770
771 default:
772 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
773 }
774 add->SetLocations(locations);
775}
776
777void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
778 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000779 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
780 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100781 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000782 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100783 if (locations->InAt(1).IsRegister()) {
784 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
785 locations->InAt(1).AsX86_64().AsCpuRegister());
786 } else if (locations->InAt(1).IsConstant()) {
787 HConstant* instruction = locations->InAt(1).GetConstant();
788 Immediate imm(instruction->AsIntConstant()->GetValue());
789 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
790 } else {
791 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
792 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
793 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000794 break;
795 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100796 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100797 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
798 locations->InAt(1).AsX86_64().AsCpuRegister());
799 break;
800 }
801
802 case Primitive::kPrimBoolean:
803 case Primitive::kPrimByte:
804 case Primitive::kPrimChar:
805 case Primitive::kPrimShort:
806 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
807 break;
808
809 default:
810 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
811 }
812}
813
814void LocationsBuilderX86_64::VisitSub(HSub* sub) {
815 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
816 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100817 case Primitive::kPrimInt: {
818 locations->SetInAt(0, Location::RequiresRegister());
819 locations->SetInAt(1, Location::Any());
820 locations->SetOut(Location::SameAsFirstInput());
821 break;
822 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100823 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000824 locations->SetInAt(0, Location::RequiresRegister());
825 locations->SetInAt(1, Location::RequiresRegister());
826 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100827 break;
828 }
829
830 case Primitive::kPrimBoolean:
831 case Primitive::kPrimByte:
832 case Primitive::kPrimChar:
833 case Primitive::kPrimShort:
834 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
835 break;
836
837 default:
838 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
839 }
840 sub->SetLocations(locations);
841}
842
843void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
844 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000845 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
846 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100847 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000848 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100849 if (locations->InAt(1).IsRegister()) {
850 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
851 locations->InAt(1).AsX86_64().AsCpuRegister());
852 } else if (locations->InAt(1).IsConstant()) {
853 HConstant* instruction = locations->InAt(1).GetConstant();
854 Immediate imm(instruction->AsIntConstant()->GetValue());
855 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
856 } else {
857 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
858 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
859 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000860 break;
861 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100862 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100863 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
864 locations->InAt(1).AsX86_64().AsCpuRegister());
865 break;
866 }
867
868 case Primitive::kPrimBoolean:
869 case Primitive::kPrimByte:
870 case Primitive::kPrimChar:
871 case Primitive::kPrimShort:
872 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
873 break;
874
875 default:
876 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
877 }
878}
879
880void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100881 codegen_->MarkNotLeaf();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100882 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
883 locations->SetOut(X86_64CpuLocation(RAX));
884 instruction->SetLocations(locations);
885}
886
887void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
888 InvokeRuntimeCallingConvention calling_convention;
889 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
890 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
891
892 __ gs()->call(Address::Absolute(
893 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
894
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100895 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100896 codegen_->RecordPcInfo(instruction->GetDexPc());
897}
898
899void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
900 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
901 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
902 if (location.IsStackSlot()) {
903 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
904 } else if (location.IsDoubleStackSlot()) {
905 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
906 }
907 locations->SetOut(location);
908 instruction->SetLocations(locations);
909}
910
911void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
912 // Nothing to do, the parameter is already at its location.
913}
914
915void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
916 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000917 locations->SetInAt(0, Location::RequiresRegister());
918 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100919 instruction->SetLocations(locations);
920}
921
922void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
923 LocationSummary* locations = instruction->GetLocations();
924 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
925 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
926 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
927}
928
929void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
930 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
931 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
932 locations->SetInAt(i, Location::Any());
933 }
934 locations->SetOut(Location::Any());
935 instruction->SetLocations(locations);
936}
937
938void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
939 LOG(FATAL) << "Unimplemented";
940}
941
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100942void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
943 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
944 locations->SetInAt(0, Location::RequiresRegister());
945 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100946 // Temporary registers for the write barrier.
947 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
948 locations->AddTemp(Location::RequiresRegister());
949 locations->AddTemp(Location::RequiresRegister());
950 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100951 instruction->SetLocations(locations);
952}
953
954void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
955 LocationSummary* locations = instruction->GetLocations();
956 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
957 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
958 size_t offset = instruction->GetFieldOffset().SizeValue();
959 Primitive::Type field_type = instruction->InputAt(1)->GetType();
960
961 switch (field_type) {
962 case Primitive::kPrimBoolean:
963 case Primitive::kPrimByte: {
964 __ movb(Address(obj, offset), value);
965 break;
966 }
967
968 case Primitive::kPrimShort:
969 case Primitive::kPrimChar: {
970 __ movw(Address(obj, offset), value);
971 break;
972 }
973
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100974 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100975 case Primitive::kPrimNot: {
976 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100977 if (field_type == Primitive::kPrimNot) {
978 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
979 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
980 codegen_->MarkGCCard(temp, card, obj, value);
981 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100982 break;
983 }
984
985 case Primitive::kPrimLong: {
986 __ movq(Address(obj, offset), value);
987 break;
988 }
989
990 case Primitive::kPrimFloat:
991 case Primitive::kPrimDouble:
992 LOG(FATAL) << "Unimplemented register type " << field_type;
993
994 case Primitive::kPrimVoid:
995 LOG(FATAL) << "Unreachable type " << field_type;
996 }
997}
998
999void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1000 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1001 locations->SetInAt(0, Location::RequiresRegister());
1002 locations->SetOut(Location::RequiresRegister());
1003 instruction->SetLocations(locations);
1004}
1005
1006void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1007 LocationSummary* locations = instruction->GetLocations();
1008 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1009 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1010 size_t offset = instruction->GetFieldOffset().SizeValue();
1011
1012 switch (instruction->GetType()) {
1013 case Primitive::kPrimBoolean: {
1014 __ movzxb(out, Address(obj, offset));
1015 break;
1016 }
1017
1018 case Primitive::kPrimByte: {
1019 __ movsxb(out, Address(obj, offset));
1020 break;
1021 }
1022
1023 case Primitive::kPrimShort: {
1024 __ movsxw(out, Address(obj, offset));
1025 break;
1026 }
1027
1028 case Primitive::kPrimChar: {
1029 __ movzxw(out, Address(obj, offset));
1030 break;
1031 }
1032
1033 case Primitive::kPrimInt:
1034 case Primitive::kPrimNot: {
1035 __ movl(out, Address(obj, offset));
1036 break;
1037 }
1038
1039 case Primitive::kPrimLong: {
1040 __ movq(out, Address(obj, offset));
1041 break;
1042 }
1043
1044 case Primitive::kPrimFloat:
1045 case Primitive::kPrimDouble:
1046 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1047
1048 case Primitive::kPrimVoid:
1049 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1050 }
1051}
1052
1053void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
1054 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1055 locations->SetInAt(0, Location::Any());
1056 // TODO: Have a normalization phase that makes this instruction never used.
1057 locations->SetOut(Location::SameAsFirstInput());
1058 instruction->SetLocations(locations);
1059}
1060
1061void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
1062 SlowPathCode* slow_path =
1063 new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
1064 codegen_->AddSlowPath(slow_path);
1065
1066 LocationSummary* locations = instruction->GetLocations();
1067 Location obj = locations->InAt(0);
1068 DCHECK(obj.Equals(locations->Out()));
1069
1070 if (obj.IsRegister()) {
1071 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1072 } else {
1073 DCHECK(locations->InAt(0).IsStackSlot());
1074 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1075 }
1076 __ j(kEqual, slow_path->GetEntryLabel());
1077}
1078
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001079void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
1080 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1081 locations->SetInAt(0, Location::RequiresRegister());
1082 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1083 locations->SetOut(Location::RequiresRegister());
1084 instruction->SetLocations(locations);
1085}
1086
1087void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1088 LocationSummary* locations = instruction->GetLocations();
1089 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1090 Location index = locations->InAt(1);
1091
1092 switch (instruction->GetType()) {
1093 case Primitive::kPrimBoolean: {
1094 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1095 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1096 if (index.IsConstant()) {
1097 __ movzxb(out, Address(obj,
1098 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1099 } else {
1100 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1101 }
1102 break;
1103 }
1104
1105 case Primitive::kPrimByte: {
1106 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1107 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1108 if (index.IsConstant()) {
1109 __ movsxb(out, Address(obj,
1110 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1111 } else {
1112 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1113 }
1114 break;
1115 }
1116
1117 case Primitive::kPrimShort: {
1118 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1119 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1120 if (index.IsConstant()) {
1121 __ movsxw(out, Address(obj,
1122 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1123 } else {
1124 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1125 }
1126 break;
1127 }
1128
1129 case Primitive::kPrimChar: {
1130 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1131 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1132 if (index.IsConstant()) {
1133 __ movzxw(out, Address(obj,
1134 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1135 } else {
1136 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1137 }
1138 break;
1139 }
1140
1141 case Primitive::kPrimInt:
1142 case Primitive::kPrimNot: {
1143 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1144 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1145 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1146 if (index.IsConstant()) {
1147 __ movl(out, Address(obj,
1148 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1149 } else {
1150 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1151 }
1152 break;
1153 }
1154
1155 case Primitive::kPrimLong: {
1156 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1157 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1158 if (index.IsConstant()) {
1159 __ movq(out, Address(obj,
1160 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1161 } else {
1162 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1163 }
1164 break;
1165 }
1166
1167 case Primitive::kPrimFloat:
1168 case Primitive::kPrimDouble:
1169 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1170
1171 case Primitive::kPrimVoid:
1172 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1173 }
1174}
1175
1176void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
1177 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1178 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1179 if (value_type == Primitive::kPrimNot) {
1180 InvokeRuntimeCallingConvention calling_convention;
1181 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1182 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1183 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
1184 codegen_->MarkNotLeaf();
1185 } else {
1186 locations->SetInAt(0, Location::RequiresRegister());
1187 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1188 locations->SetInAt(2, Location::RequiresRegister());
1189 }
1190 instruction->SetLocations(locations);
1191}
1192
1193void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1194 LocationSummary* locations = instruction->GetLocations();
1195 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1196 Location index = locations->InAt(1);
1197 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1198
1199 switch (value_type) {
1200 case Primitive::kPrimBoolean:
1201 case Primitive::kPrimByte: {
1202 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1203 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1204 if (index.IsConstant()) {
1205 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1206 __ movb(Address(obj, offset), value);
1207 } else {
1208 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1209 }
1210 break;
1211 }
1212
1213 case Primitive::kPrimShort:
1214 case Primitive::kPrimChar: {
1215 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1216 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1217 if (index.IsConstant()) {
1218 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1219 __ movw(Address(obj, offset), value);
1220 } else {
1221 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1222 }
1223 break;
1224 }
1225
1226 case Primitive::kPrimInt: {
1227 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1228 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1229 if (index.IsConstant()) {
1230 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1231 __ movl(Address(obj, offset), value);
1232 } else {
1233 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1234 }
1235 break;
1236 }
1237
1238 case Primitive::kPrimNot: {
1239 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1240 DCHECK(!codegen_->IsLeafMethod());
1241 codegen_->RecordPcInfo(instruction->GetDexPc());
1242 break;
1243 }
1244
1245 case Primitive::kPrimLong: {
1246 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1247 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1248 if (index.IsConstant()) {
1249 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1250 __ movq(Address(obj, offset), value);
1251 } else {
1252 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1253 }
1254 break;
1255 }
1256
1257 case Primitive::kPrimFloat:
1258 case Primitive::kPrimDouble:
1259 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1260
1261 case Primitive::kPrimVoid:
1262 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1263 }
1264}
1265
1266void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
1267 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1268 locations->SetInAt(0, Location::RequiresRegister());
1269 locations->SetOut(Location::RequiresRegister());
1270 instruction->SetLocations(locations);
1271}
1272
1273void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1274 LocationSummary* locations = instruction->GetLocations();
1275 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1276 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1277 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1278 __ movl(out, Address(obj, offset));
1279}
1280
1281void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1282 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1283 locations->SetInAt(0, Location::RequiresRegister());
1284 locations->SetInAt(1, Location::RequiresRegister());
1285 // TODO: Have a normalization phase that makes this instruction never used.
1286 locations->SetOut(Location::SameAsFirstInput());
1287 instruction->SetLocations(locations);
1288}
1289
1290void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1291 LocationSummary* locations = instruction->GetLocations();
1292 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
1293 instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1294 codegen_->AddSlowPath(slow_path);
1295
1296 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1297 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1298
1299 __ cmpl(index, length);
1300 __ j(kAboveEqual, slow_path->GetEntryLabel());
1301}
1302
1303void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1304 CpuRegister card,
1305 CpuRegister object,
1306 CpuRegister value) {
1307 Label is_null;
1308 __ testl(value, value);
1309 __ j(kEqual, &is_null);
1310 __ gs()->movq(card, Address::Absolute(
1311 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1312 __ movq(temp, object);
1313 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1314 __ movb(Address(temp, card, TIMES_1, 0), card);
1315 __ Bind(&is_null);
1316}
1317
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001318void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1319 temp->SetLocations(nullptr);
1320}
1321
1322void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1323 // Nothing to do, this is driven by the code generator.
1324}
1325
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001326void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1327 LOG(FATAL) << "Unimplemented";
1328}
1329
1330void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001331 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1332}
1333
1334X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1335 return codegen_->GetAssembler();
1336}
1337
1338void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1339 MoveOperands* move = moves_.Get(index);
1340 Location source = move->GetSource();
1341 Location destination = move->GetDestination();
1342
1343 if (source.IsRegister()) {
1344 if (destination.IsRegister()) {
1345 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001346 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001347 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1348 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001349 } else {
1350 DCHECK(destination.IsDoubleStackSlot());
1351 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1352 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001353 }
1354 } else if (source.IsStackSlot()) {
1355 if (destination.IsRegister()) {
1356 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1357 Address(CpuRegister(RSP), source.GetStackIndex()));
1358 } else {
1359 DCHECK(destination.IsStackSlot());
1360 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1361 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1362 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001363 } else if (source.IsDoubleStackSlot()) {
1364 if (destination.IsRegister()) {
1365 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1366 Address(CpuRegister(RSP), source.GetStackIndex()));
1367 } else {
1368 DCHECK(destination.IsDoubleStackSlot());
1369 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1370 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1371 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001372 } else if (source.IsConstant()) {
1373 HConstant* constant = source.GetConstant();
1374 if (constant->IsIntConstant()) {
1375 Immediate imm(constant->AsIntConstant()->GetValue());
1376 if (destination.IsRegister()) {
1377 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1378 } else {
1379 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1380 }
1381 } else if (constant->IsLongConstant()) {
1382 int64_t value = constant->AsLongConstant()->GetValue();
1383 if (destination.IsRegister()) {
1384 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1385 } else {
1386 __ movq(CpuRegister(TMP), Immediate(value));
1387 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1388 }
1389 } else {
1390 LOG(FATAL) << "Unimplemented constant type";
1391 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001392 } else {
1393 LOG(FATAL) << "Unimplemented";
1394 }
1395}
1396
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001397void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001398 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001399 __ movl(Address(CpuRegister(RSP), mem), reg);
1400 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001401}
1402
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001403void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001404 ScratchRegisterScope ensure_scratch(
1405 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1406
1407 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1408 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1409 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1410 Address(CpuRegister(RSP), mem2 + stack_offset));
1411 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1412 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1413 CpuRegister(ensure_scratch.GetRegister()));
1414}
1415
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001416void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1417 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1418 __ movq(Address(CpuRegister(RSP), mem), reg);
1419 __ movq(reg, CpuRegister(TMP));
1420}
1421
1422void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1423 ScratchRegisterScope ensure_scratch(
1424 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1425
1426 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1427 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1428 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1429 Address(CpuRegister(RSP), mem2 + stack_offset));
1430 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1431 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1432 CpuRegister(ensure_scratch.GetRegister()));
1433}
1434
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001435void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1436 MoveOperands* move = moves_.Get(index);
1437 Location source = move->GetSource();
1438 Location destination = move->GetDestination();
1439
1440 if (source.IsRegister() && destination.IsRegister()) {
1441 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1442 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001443 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001444 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001445 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001446 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001447 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1448 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1449 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1450 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1451 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1452 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1453 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001454 } else {
1455 LOG(FATAL) << "Unimplemented";
1456 }
1457}
1458
1459
1460void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1461 __ pushq(CpuRegister(reg));
1462}
1463
1464
1465void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1466 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001467}
1468
1469} // namespace x86_64
1470} // namespace art