blob: b2d81e35dd1c72fda5d35c83b16bc76d875d8d78 [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:
Nicolas Geoffray39468442014-09-02 15:17:15 +010068 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069
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 Geoffray39468442014-09-02 15:17:15 +010074 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075 }
76
77 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010078 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010079 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:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100100 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100101 Location index_location,
102 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100103 : instruction_(instruction),
104 index_location_(index_location),
105 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100106
107 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
108 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
109 __ Bind(GetEntryLabel());
110 InvokeRuntimeCallingConvention calling_convention;
111 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
112 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
113 __ gs()->call(Address::Absolute(
114 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100115 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100116 }
117
118 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100119 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100120 const Location index_location_;
121 const Location length_location_;
122
123 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
124};
125
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100126#undef __
127#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
128
Dave Allison20dfc792014-06-16 20:44:29 -0700129inline Condition X86_64Condition(IfCondition cond) {
130 switch (cond) {
131 case kCondEQ: return kEqual;
132 case kCondNE: return kNotEqual;
133 case kCondLT: return kLess;
134 case kCondLE: return kLessEqual;
135 case kCondGT: return kGreater;
136 case kCondGE: return kGreaterEqual;
137 default:
138 LOG(FATAL) << "Unknown if condition";
139 }
140 return kEqual;
141}
142
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100143void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
144 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
145}
146
147void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
148 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
149}
150
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100151CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
152 : CodeGenerator(graph, kNumberOfRegIds),
153 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000154 instruction_visitor_(graph, this),
155 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100156
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100157size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
158 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
159}
160
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100161InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
162 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100163 : HGraphVisitor(graph),
164 assembler_(codegen->GetAssembler()),
165 codegen_(codegen) {}
166
167ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
168 bool* blocked_registers) const {
169 switch (type) {
170 case Primitive::kPrimLong:
171 case Primitive::kPrimByte:
172 case Primitive::kPrimBoolean:
173 case Primitive::kPrimChar:
174 case Primitive::kPrimShort:
175 case Primitive::kPrimInt:
176 case Primitive::kPrimNot: {
177 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
178 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
179 }
180
181 case Primitive::kPrimFloat:
182 case Primitive::kPrimDouble:
183 LOG(FATAL) << "Unimplemented register type " << type;
184
185 case Primitive::kPrimVoid:
186 LOG(FATAL) << "Unreachable type " << type;
187 }
188
189 return ManagedRegister::NoRegister();
190}
191
192void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
193 // Stack register is always reserved.
194 blocked_registers[RSP] = true;
195
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000196 // Block the register used as TMP.
197 blocked_registers[TMP] = true;
198
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100199 // TODO: We currently don't use Quick's callee saved registers.
200 blocked_registers[RBX] = true;
201 blocked_registers[RBP] = true;
202 blocked_registers[R12] = true;
203 blocked_registers[R13] = true;
204 blocked_registers[R14] = true;
205 blocked_registers[R15] = true;
206}
207
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100208void CodeGeneratorX86_64::GenerateFrameEntry() {
209 // Create a fake register to mimic Quick.
210 static const int kFakeReturnRegister = 16;
211 core_spill_mask_ |= (1 << kFakeReturnRegister);
212
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100213 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700214 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100215
216 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
217 __ testq(CpuRegister(RAX), Address(
218 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100219 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100220 }
221
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100222 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100223 __ subq(CpuRegister(RSP),
224 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
225
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100226 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
227 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
228 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100229
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100230 __ gs()->cmpq(CpuRegister(RSP),
231 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
232 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100233 }
234
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100235 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
236}
237
238void CodeGeneratorX86_64::GenerateFrameExit() {
239 __ addq(CpuRegister(RSP),
240 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
241}
242
243void CodeGeneratorX86_64::Bind(Label* label) {
244 __ Bind(label);
245}
246
247void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
248 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
249}
250
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100251Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
252 switch (load->GetType()) {
253 case Primitive::kPrimLong:
254 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
255 break;
256
257 case Primitive::kPrimInt:
258 case Primitive::kPrimNot:
259 return Location::StackSlot(GetStackSlot(load->GetLocal()));
260
261 case Primitive::kPrimFloat:
262 case Primitive::kPrimDouble:
263 LOG(FATAL) << "Unimplemented type " << load->GetType();
264
265 case Primitive::kPrimBoolean:
266 case Primitive::kPrimByte:
267 case Primitive::kPrimChar:
268 case Primitive::kPrimShort:
269 case Primitive::kPrimVoid:
270 LOG(FATAL) << "Unexpected type " << load->GetType();
271 }
272
273 LOG(FATAL) << "Unreachable";
274 return Location();
275}
276
277void CodeGeneratorX86_64::Move(Location destination, Location source) {
278 if (source.Equals(destination)) {
279 return;
280 }
281 if (destination.IsRegister()) {
282 if (source.IsRegister()) {
283 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
284 } else if (source.IsStackSlot()) {
285 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
286 } else {
287 DCHECK(source.IsDoubleStackSlot());
288 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
289 }
290 } else if (destination.IsStackSlot()) {
291 if (source.IsRegister()) {
292 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
293 } else {
294 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000295 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
296 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100297 }
298 } else {
299 DCHECK(destination.IsDoubleStackSlot());
300 if (source.IsRegister()) {
301 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
302 } else {
303 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000304 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
305 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100306 }
307 }
308}
309
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100310void CodeGeneratorX86_64::Move(HInstruction* instruction,
311 Location location,
312 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100313 if (instruction->AsIntConstant() != nullptr) {
314 Immediate imm(instruction->AsIntConstant()->GetValue());
315 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000316 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100317 } else {
318 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
319 }
320 } else if (instruction->AsLongConstant() != nullptr) {
321 int64_t value = instruction->AsLongConstant()->GetValue();
322 if (location.IsRegister()) {
323 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
324 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000325 __ movq(CpuRegister(TMP), Immediate(value));
326 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100327 }
328 } else if (instruction->AsLoadLocal() != nullptr) {
329 switch (instruction->GetType()) {
330 case Primitive::kPrimBoolean:
331 case Primitive::kPrimByte:
332 case Primitive::kPrimChar:
333 case Primitive::kPrimShort:
334 case Primitive::kPrimInt:
335 case Primitive::kPrimNot:
336 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
337 break;
338
339 case Primitive::kPrimLong:
340 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
341 break;
342
343 default:
344 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
345 }
346 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100347 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100348 switch (instruction->GetType()) {
349 case Primitive::kPrimBoolean:
350 case Primitive::kPrimByte:
351 case Primitive::kPrimChar:
352 case Primitive::kPrimShort:
353 case Primitive::kPrimInt:
354 case Primitive::kPrimNot:
355 case Primitive::kPrimLong:
356 Move(location, instruction->GetLocations()->Out());
357 break;
358
359 default:
360 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
361 }
362 }
363}
364
365void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
366 got->SetLocations(nullptr);
367}
368
369void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
370 HBasicBlock* successor = got->GetSuccessor();
371 if (GetGraph()->GetExitBlock() == successor) {
372 codegen_->GenerateFrameExit();
373 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
374 __ jmp(codegen_->GetLabelOf(successor));
375 }
376}
377
378void LocationsBuilderX86_64::VisitExit(HExit* exit) {
379 exit->SetLocations(nullptr);
380}
381
382void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
383 if (kIsDebugBuild) {
384 __ Comment("Unreachable");
385 __ int3();
386 }
387}
388
389void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100390 LocationSummary* locations =
391 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100392 HInstruction* cond = if_instr->InputAt(0);
393 DCHECK(cond->IsCondition());
394 HCondition* condition = cond->AsCondition();
395 if (condition->NeedsMaterialization()) {
396 locations->SetInAt(0, Location::Any());
397 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398}
399
400void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700401 HInstruction* cond = if_instr->InputAt(0);
402 DCHECK(cond->IsCondition());
403 HCondition* condition = cond->AsCondition();
404 if (condition->NeedsMaterialization()) {
405 // Materialized condition, compare against 0.
406 Location lhs = if_instr->GetLocations()->InAt(0);
407 if (lhs.IsRegister()) {
408 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
409 } else {
410 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
411 }
412 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
413 } else {
414 Location lhs = condition->GetLocations()->InAt(0);
415 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100416 if (rhs.IsRegister()) {
417 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
418 } else if (rhs.IsConstant()) {
419 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
420 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
421 } else {
422 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
423 }
Dave Allison20dfc792014-06-16 20:44:29 -0700424 __ j(X86_64Condition(condition->GetCondition()),
425 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
426 }
427 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
428 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100429 }
430}
431
432void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
433 local->SetLocations(nullptr);
434}
435
436void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
437 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
438}
439
440void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
441 local->SetLocations(nullptr);
442}
443
444void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
445 // Nothing to do, this is driven by the code generator.
446}
447
448void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100449 LocationSummary* locations =
450 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100451 switch (store->InputAt(1)->GetType()) {
452 case Primitive::kPrimBoolean:
453 case Primitive::kPrimByte:
454 case Primitive::kPrimChar:
455 case Primitive::kPrimShort:
456 case Primitive::kPrimInt:
457 case Primitive::kPrimNot:
458 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
459 break;
460
461 case Primitive::kPrimLong:
462 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
463 break;
464
465 default:
466 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
467 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100468}
469
470void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
471}
472
Dave Allison20dfc792014-06-16 20:44:29 -0700473void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100474 LocationSummary* locations =
475 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000476 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100477 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100478 if (comp->NeedsMaterialization()) {
479 locations->SetOut(Location::RequiresRegister());
480 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100481}
482
Dave Allison20dfc792014-06-16 20:44:29 -0700483void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
484 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100485 LocationSummary* locations = comp->GetLocations();
486 if (locations->InAt(1).IsRegister()) {
487 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
488 locations->InAt(1).AsX86_64().AsCpuRegister());
489 } else if (locations->InAt(1).IsConstant()) {
490 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
491 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
492 } else {
493 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
494 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
495 }
Dave Allison20dfc792014-06-16 20:44:29 -0700496 __ setcc(X86_64Condition(comp->GetCondition()),
497 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
498 }
499}
500
501void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
502 VisitCondition(comp);
503}
504
505void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
506 VisitCondition(comp);
507}
508
509void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
510 VisitCondition(comp);
511}
512
513void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
514 VisitCondition(comp);
515}
516
517void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
518 VisitCondition(comp);
519}
520
521void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
522 VisitCondition(comp);
523}
524
525void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
526 VisitCondition(comp);
527}
528
529void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
530 VisitCondition(comp);
531}
532
533void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
534 VisitCondition(comp);
535}
536
537void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
538 VisitCondition(comp);
539}
540
541void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
542 VisitCondition(comp);
543}
544
545void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
546 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100547}
548
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100549void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100550 LocationSummary* locations =
551 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100552 locations->SetInAt(0, Location::RequiresRegister());
553 locations->SetInAt(1, Location::RequiresRegister());
554 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100555}
556
557void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
558 Label greater, done;
559 LocationSummary* locations = compare->GetLocations();
560 switch (compare->InputAt(0)->GetType()) {
561 case Primitive::kPrimLong:
562 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
563 locations->InAt(1).AsX86_64().AsCpuRegister());
564 break;
565 default:
566 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
567 }
568
569 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
570 __ j(kEqual, &done);
571 __ j(kGreater, &greater);
572
573 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
574 __ jmp(&done);
575
576 __ Bind(&greater);
577 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
578
579 __ Bind(&done);
580}
581
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100582void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100583 LocationSummary* locations =
584 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100585 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586}
587
588void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100589}
590
591void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100592 LocationSummary* locations =
593 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100594 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100595}
596
597void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100598}
599
600void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
601 ret->SetLocations(nullptr);
602}
603
604void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
605 codegen_->GenerateFrameExit();
606 __ ret();
607}
608
609void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100610 LocationSummary* locations =
611 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100612 switch (ret->InputAt(0)->GetType()) {
613 case Primitive::kPrimBoolean:
614 case Primitive::kPrimByte:
615 case Primitive::kPrimChar:
616 case Primitive::kPrimShort:
617 case Primitive::kPrimInt:
618 case Primitive::kPrimNot:
619 case Primitive::kPrimLong:
620 locations->SetInAt(0, X86_64CpuLocation(RAX));
621 break;
622
623 default:
624 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
625 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100626}
627
628void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
629 if (kIsDebugBuild) {
630 switch (ret->InputAt(0)->GetType()) {
631 case Primitive::kPrimBoolean:
632 case Primitive::kPrimByte:
633 case Primitive::kPrimChar:
634 case Primitive::kPrimShort:
635 case Primitive::kPrimInt:
636 case Primitive::kPrimNot:
637 case Primitive::kPrimLong:
638 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
639 break;
640
641 default:
642 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
643 }
644 }
645 codegen_->GenerateFrameExit();
646 __ ret();
647}
648
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100649Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
650 switch (type) {
651 case Primitive::kPrimBoolean:
652 case Primitive::kPrimByte:
653 case Primitive::kPrimChar:
654 case Primitive::kPrimShort:
655 case Primitive::kPrimInt:
656 case Primitive::kPrimNot: {
657 uint32_t index = gp_index_++;
658 stack_index_++;
659 if (index < calling_convention.GetNumberOfRegisters()) {
660 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
661 } else {
662 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
663 }
664 }
665
666 case Primitive::kPrimLong: {
667 uint32_t index = gp_index_;
668 stack_index_ += 2;
669 if (index < calling_convention.GetNumberOfRegisters()) {
670 gp_index_ += 1;
671 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
672 } else {
673 gp_index_ += 2;
674 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
675 }
676 }
677
678 case Primitive::kPrimDouble:
679 case Primitive::kPrimFloat:
680 LOG(FATAL) << "Unimplemented parameter type " << type;
681 break;
682
683 case Primitive::kPrimVoid:
684 LOG(FATAL) << "Unexpected parameter type " << type;
685 break;
686 }
687 return Location();
688}
689
690void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100691 LocationSummary* locations =
692 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100693 locations->AddTemp(X86_64CpuLocation(RDI));
694
695 InvokeDexCallingConventionVisitor calling_convention_visitor;
696 for (size_t i = 0; i < invoke->InputCount(); ++i) {
697 HInstruction* input = invoke->InputAt(i);
698 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
699 }
700
701 switch (invoke->GetType()) {
702 case Primitive::kPrimBoolean:
703 case Primitive::kPrimByte:
704 case Primitive::kPrimChar:
705 case Primitive::kPrimShort:
706 case Primitive::kPrimInt:
707 case Primitive::kPrimNot:
708 case Primitive::kPrimLong:
709 locations->SetOut(X86_64CpuLocation(RAX));
710 break;
711
712 case Primitive::kPrimVoid:
713 break;
714
715 case Primitive::kPrimDouble:
716 case Primitive::kPrimFloat:
717 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
718 break;
719 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100720}
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 Geoffray39468442014-09-02 15:17:15 +0100745 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100746}
747
748void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100749 LocationSummary* locations =
750 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100751 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100752 case Primitive::kPrimInt: {
753 locations->SetInAt(0, Location::RequiresRegister());
754 locations->SetInAt(1, Location::Any());
755 locations->SetOut(Location::SameAsFirstInput());
756 break;
757 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100758 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000759 locations->SetInAt(0, Location::RequiresRegister());
760 locations->SetInAt(1, Location::RequiresRegister());
761 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100762 break;
763 }
764
765 case Primitive::kPrimBoolean:
766 case Primitive::kPrimByte:
767 case Primitive::kPrimChar:
768 case Primitive::kPrimShort:
769 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
770 break;
771
772 default:
773 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
774 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100775}
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100815 LocationSummary* locations =
816 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100817 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100818 case Primitive::kPrimInt: {
819 locations->SetInAt(0, Location::RequiresRegister());
820 locations->SetInAt(1, Location::Any());
821 locations->SetOut(Location::SameAsFirstInput());
822 break;
823 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100824 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000825 locations->SetInAt(0, Location::RequiresRegister());
826 locations->SetInAt(1, Location::RequiresRegister());
827 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100828 break;
829 }
830
831 case Primitive::kPrimBoolean:
832 case Primitive::kPrimByte:
833 case Primitive::kPrimChar:
834 case Primitive::kPrimShort:
835 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
836 break;
837
838 default:
839 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
840 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100841}
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 Geoffray39468442014-09-02 15:17:15 +0100881 LocationSummary* locations =
882 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100883 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100884}
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 Geoffray39468442014-09-02 15:17:15 +0100895 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100896}
897
898void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100899 LocationSummary* locations =
900 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100901 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);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100908}
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100915 LocationSummary* locations =
916 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
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}
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100929 LocationSummary* locations =
930 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100931 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
932 locations->SetInAt(i, Location::Any());
933 }
934 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100935}
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100942 LocationSummary* locations =
943 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100944 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.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100947 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100948 locations->AddTemp(Location::RequiresRegister());
949 locations->AddTemp(Location::RequiresRegister());
950 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100951}
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();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100959
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100999 LocationSummary* locations =
1000 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001001 locations->SetInAt(0, Location::RequiresRegister());
1002 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001003}
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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001053 LocationSummary* locations =
1054 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001055 locations->SetInAt(0, Location::Any());
1056 // TODO: Have a normalization phase that makes this instruction never used.
1057 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001058}
1059
1060void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001061 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001062 codegen_->AddSlowPath(slow_path);
1063
1064 LocationSummary* locations = instruction->GetLocations();
1065 Location obj = locations->InAt(0);
1066 DCHECK(obj.Equals(locations->Out()));
1067
1068 if (obj.IsRegister()) {
1069 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1070 } else {
1071 DCHECK(locations->InAt(0).IsStackSlot());
1072 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1073 }
1074 __ j(kEqual, slow_path->GetEntryLabel());
1075}
1076
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001077void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001078 LocationSummary* locations =
1079 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001080 locations->SetInAt(0, Location::RequiresRegister());
1081 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1082 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001083}
1084
1085void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1086 LocationSummary* locations = instruction->GetLocations();
1087 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1088 Location index = locations->InAt(1);
1089
1090 switch (instruction->GetType()) {
1091 case Primitive::kPrimBoolean: {
1092 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1093 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1094 if (index.IsConstant()) {
1095 __ movzxb(out, Address(obj,
1096 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1097 } else {
1098 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1099 }
1100 break;
1101 }
1102
1103 case Primitive::kPrimByte: {
1104 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1105 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1106 if (index.IsConstant()) {
1107 __ movsxb(out, Address(obj,
1108 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1109 } else {
1110 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1111 }
1112 break;
1113 }
1114
1115 case Primitive::kPrimShort: {
1116 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1117 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1118 if (index.IsConstant()) {
1119 __ movsxw(out, Address(obj,
1120 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1121 } else {
1122 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1123 }
1124 break;
1125 }
1126
1127 case Primitive::kPrimChar: {
1128 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1129 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1130 if (index.IsConstant()) {
1131 __ movzxw(out, Address(obj,
1132 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1133 } else {
1134 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1135 }
1136 break;
1137 }
1138
1139 case Primitive::kPrimInt:
1140 case Primitive::kPrimNot: {
1141 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1142 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1143 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1144 if (index.IsConstant()) {
1145 __ movl(out, Address(obj,
1146 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1147 } else {
1148 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1149 }
1150 break;
1151 }
1152
1153 case Primitive::kPrimLong: {
1154 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1155 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1156 if (index.IsConstant()) {
1157 __ movq(out, Address(obj,
1158 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1159 } else {
1160 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1161 }
1162 break;
1163 }
1164
1165 case Primitive::kPrimFloat:
1166 case Primitive::kPrimDouble:
1167 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1168
1169 case Primitive::kPrimVoid:
1170 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1171 }
1172}
1173
1174void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001175 Primitive::Type value_type = instruction->GetComponentType();
1176 bool is_object = value_type == Primitive::kPrimNot;
1177 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1178 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1179 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001180 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)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001184 } else {
1185 locations->SetInAt(0, Location::RequiresRegister());
1186 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1187 locations->SetInAt(2, Location::RequiresRegister());
1188 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001189}
1190
1191void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1192 LocationSummary* locations = instruction->GetLocations();
1193 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1194 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001195 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001196
1197 switch (value_type) {
1198 case Primitive::kPrimBoolean:
1199 case Primitive::kPrimByte: {
1200 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1201 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1202 if (index.IsConstant()) {
1203 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1204 __ movb(Address(obj, offset), value);
1205 } else {
1206 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1207 }
1208 break;
1209 }
1210
1211 case Primitive::kPrimShort:
1212 case Primitive::kPrimChar: {
1213 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1214 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1215 if (index.IsConstant()) {
1216 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1217 __ movw(Address(obj, offset), value);
1218 } else {
1219 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1220 }
1221 break;
1222 }
1223
1224 case Primitive::kPrimInt: {
1225 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1226 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1227 if (index.IsConstant()) {
1228 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1229 __ movl(Address(obj, offset), value);
1230 } else {
1231 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1232 }
1233 break;
1234 }
1235
1236 case Primitive::kPrimNot: {
1237 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1238 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001239 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001240 break;
1241 }
1242
1243 case Primitive::kPrimLong: {
1244 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1245 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1246 if (index.IsConstant()) {
1247 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1248 __ movq(Address(obj, offset), value);
1249 } else {
1250 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1251 }
1252 break;
1253 }
1254
1255 case Primitive::kPrimFloat:
1256 case Primitive::kPrimDouble:
1257 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1258
1259 case Primitive::kPrimVoid:
1260 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1261 }
1262}
1263
1264void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001265 LocationSummary* locations =
1266 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001267 locations->SetInAt(0, Location::RequiresRegister());
1268 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001269}
1270
1271void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1272 LocationSummary* locations = instruction->GetLocations();
1273 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1274 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1275 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1276 __ movl(out, Address(obj, offset));
1277}
1278
1279void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001280 LocationSummary* locations =
1281 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001282 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());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001286}
1287
1288void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1289 LocationSummary* locations = instruction->GetLocations();
1290 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001291 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001292 codegen_->AddSlowPath(slow_path);
1293
1294 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1295 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1296
1297 __ cmpl(index, length);
1298 __ j(kAboveEqual, slow_path->GetEntryLabel());
1299}
1300
1301void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1302 CpuRegister card,
1303 CpuRegister object,
1304 CpuRegister value) {
1305 Label is_null;
1306 __ testl(value, value);
1307 __ j(kEqual, &is_null);
1308 __ gs()->movq(card, Address::Absolute(
1309 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1310 __ movq(temp, object);
1311 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1312 __ movb(Address(temp, card, TIMES_1, 0), card);
1313 __ Bind(&is_null);
1314}
1315
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001316void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1317 temp->SetLocations(nullptr);
1318}
1319
1320void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1321 // Nothing to do, this is driven by the code generator.
1322}
1323
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001324void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1325 LOG(FATAL) << "Unimplemented";
1326}
1327
1328void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001329 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1330}
1331
1332X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1333 return codegen_->GetAssembler();
1334}
1335
1336void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1337 MoveOperands* move = moves_.Get(index);
1338 Location source = move->GetSource();
1339 Location destination = move->GetDestination();
1340
1341 if (source.IsRegister()) {
1342 if (destination.IsRegister()) {
1343 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001344 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001345 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1346 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001347 } else {
1348 DCHECK(destination.IsDoubleStackSlot());
1349 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1350 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001351 }
1352 } else if (source.IsStackSlot()) {
1353 if (destination.IsRegister()) {
1354 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1355 Address(CpuRegister(RSP), source.GetStackIndex()));
1356 } else {
1357 DCHECK(destination.IsStackSlot());
1358 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1359 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1360 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001361 } else if (source.IsDoubleStackSlot()) {
1362 if (destination.IsRegister()) {
1363 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1364 Address(CpuRegister(RSP), source.GetStackIndex()));
1365 } else {
1366 DCHECK(destination.IsDoubleStackSlot());
1367 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1368 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1369 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001370 } else if (source.IsConstant()) {
1371 HConstant* constant = source.GetConstant();
1372 if (constant->IsIntConstant()) {
1373 Immediate imm(constant->AsIntConstant()->GetValue());
1374 if (destination.IsRegister()) {
1375 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1376 } else {
1377 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1378 }
1379 } else if (constant->IsLongConstant()) {
1380 int64_t value = constant->AsLongConstant()->GetValue();
1381 if (destination.IsRegister()) {
1382 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1383 } else {
1384 __ movq(CpuRegister(TMP), Immediate(value));
1385 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1386 }
1387 } else {
1388 LOG(FATAL) << "Unimplemented constant type";
1389 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001390 } else {
1391 LOG(FATAL) << "Unimplemented";
1392 }
1393}
1394
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001395void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001396 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001397 __ movl(Address(CpuRegister(RSP), mem), reg);
1398 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001399}
1400
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001401void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001402 ScratchRegisterScope ensure_scratch(
1403 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1404
1405 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1406 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1407 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1408 Address(CpuRegister(RSP), mem2 + stack_offset));
1409 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1410 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1411 CpuRegister(ensure_scratch.GetRegister()));
1412}
1413
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001414void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1415 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1416 __ movq(Address(CpuRegister(RSP), mem), reg);
1417 __ movq(reg, CpuRegister(TMP));
1418}
1419
1420void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1421 ScratchRegisterScope ensure_scratch(
1422 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1423
1424 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1425 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1426 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1427 Address(CpuRegister(RSP), mem2 + stack_offset));
1428 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1429 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1430 CpuRegister(ensure_scratch.GetRegister()));
1431}
1432
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001433void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1434 MoveOperands* move = moves_.Get(index);
1435 Location source = move->GetSource();
1436 Location destination = move->GetDestination();
1437
1438 if (source.IsRegister() && destination.IsRegister()) {
1439 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1440 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001441 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001442 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001443 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001444 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001445 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1446 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1447 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1448 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1449 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1450 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1451 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001452 } else {
1453 LOG(FATAL) << "Unimplemented";
1454 }
1455}
1456
1457
1458void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1459 __ pushq(CpuRegister(reg));
1460}
1461
1462
1463void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1464 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001465}
1466
1467} // namespace x86_64
1468} // namespace art