blob: 2f352e08384446fde98aabcb1df7e053ea29df96 [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 Geoffrayfbc695f2014-09-15 15:33:30 +000098class SuspendCheckSlowPathX86_64 : public SlowPathCode {
99 public:
100 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction)
101 : instruction_(instruction) {}
102
103 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
104 __ Bind(GetEntryLabel());
105 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
106 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
107 __ jmp(GetReturnLabel());
108 }
109
110 Label* GetReturnLabel() { return &return_label_; }
111
112 private:
113 HSuspendCheck* const instruction_;
114 Label return_label_;
115
116 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
117};
118
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100119class BoundsCheckSlowPathX86_64 : public SlowPathCode {
120 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100121 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100122 Location index_location,
123 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100124 : instruction_(instruction),
125 index_location_(index_location),
126 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127
128 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
129 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
130 __ Bind(GetEntryLabel());
131 InvokeRuntimeCallingConvention calling_convention;
132 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
133 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
134 __ gs()->call(Address::Absolute(
135 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100136 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100137 }
138
139 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100140 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100141 const Location index_location_;
142 const Location length_location_;
143
144 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
145};
146
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100147#undef __
148#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
149
Dave Allison20dfc792014-06-16 20:44:29 -0700150inline Condition X86_64Condition(IfCondition cond) {
151 switch (cond) {
152 case kCondEQ: return kEqual;
153 case kCondNE: return kNotEqual;
154 case kCondLT: return kLess;
155 case kCondLE: return kLessEqual;
156 case kCondGT: return kGreater;
157 case kCondGE: return kGreaterEqual;
158 default:
159 LOG(FATAL) << "Unknown if condition";
160 }
161 return kEqual;
162}
163
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100164void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
165 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
166}
167
168void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
169 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
170}
171
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100172CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
173 : CodeGenerator(graph, kNumberOfRegIds),
174 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000175 instruction_visitor_(graph, this),
176 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100177
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100178size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
179 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
180}
181
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100182InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
183 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100184 : HGraphVisitor(graph),
185 assembler_(codegen->GetAssembler()),
186 codegen_(codegen) {}
187
188ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
189 bool* blocked_registers) const {
190 switch (type) {
191 case Primitive::kPrimLong:
192 case Primitive::kPrimByte:
193 case Primitive::kPrimBoolean:
194 case Primitive::kPrimChar:
195 case Primitive::kPrimShort:
196 case Primitive::kPrimInt:
197 case Primitive::kPrimNot: {
198 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
199 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
200 }
201
202 case Primitive::kPrimFloat:
203 case Primitive::kPrimDouble:
204 LOG(FATAL) << "Unimplemented register type " << type;
205
206 case Primitive::kPrimVoid:
207 LOG(FATAL) << "Unreachable type " << type;
208 }
209
210 return ManagedRegister::NoRegister();
211}
212
213void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
214 // Stack register is always reserved.
215 blocked_registers[RSP] = true;
216
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000217 // Block the register used as TMP.
218 blocked_registers[TMP] = true;
219
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100220 // TODO: We currently don't use Quick's callee saved registers.
221 blocked_registers[RBX] = true;
222 blocked_registers[RBP] = true;
223 blocked_registers[R12] = true;
224 blocked_registers[R13] = true;
225 blocked_registers[R14] = true;
226 blocked_registers[R15] = true;
227}
228
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100229void CodeGeneratorX86_64::GenerateFrameEntry() {
230 // Create a fake register to mimic Quick.
231 static const int kFakeReturnRegister = 16;
232 core_spill_mask_ |= (1 << kFakeReturnRegister);
233
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100234 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700235 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100236
237 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
238 __ testq(CpuRegister(RAX), Address(
239 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100240 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100241 }
242
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100243 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100244 __ subq(CpuRegister(RSP),
245 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
246
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100247 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
248 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
249 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100250
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100251 __ gs()->cmpq(CpuRegister(RSP),
252 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
253 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100254 }
255
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100256 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
257}
258
259void CodeGeneratorX86_64::GenerateFrameExit() {
260 __ addq(CpuRegister(RSP),
261 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
262}
263
264void CodeGeneratorX86_64::Bind(Label* label) {
265 __ Bind(label);
266}
267
268void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
269 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
270}
271
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100272Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
273 switch (load->GetType()) {
274 case Primitive::kPrimLong:
275 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
276 break;
277
278 case Primitive::kPrimInt:
279 case Primitive::kPrimNot:
280 return Location::StackSlot(GetStackSlot(load->GetLocal()));
281
282 case Primitive::kPrimFloat:
283 case Primitive::kPrimDouble:
284 LOG(FATAL) << "Unimplemented type " << load->GetType();
285
286 case Primitive::kPrimBoolean:
287 case Primitive::kPrimByte:
288 case Primitive::kPrimChar:
289 case Primitive::kPrimShort:
290 case Primitive::kPrimVoid:
291 LOG(FATAL) << "Unexpected type " << load->GetType();
292 }
293
294 LOG(FATAL) << "Unreachable";
295 return Location();
296}
297
298void CodeGeneratorX86_64::Move(Location destination, Location source) {
299 if (source.Equals(destination)) {
300 return;
301 }
302 if (destination.IsRegister()) {
303 if (source.IsRegister()) {
304 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
305 } else if (source.IsStackSlot()) {
306 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
307 } else {
308 DCHECK(source.IsDoubleStackSlot());
309 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
310 }
311 } else if (destination.IsStackSlot()) {
312 if (source.IsRegister()) {
313 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
314 } else {
315 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000316 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
317 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100318 }
319 } else {
320 DCHECK(destination.IsDoubleStackSlot());
321 if (source.IsRegister()) {
322 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
323 } else {
324 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000325 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
326 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100327 }
328 }
329}
330
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100331void CodeGeneratorX86_64::Move(HInstruction* instruction,
332 Location location,
333 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100334 if (instruction->AsIntConstant() != nullptr) {
335 Immediate imm(instruction->AsIntConstant()->GetValue());
336 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000337 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100338 } else {
339 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
340 }
341 } else if (instruction->AsLongConstant() != nullptr) {
342 int64_t value = instruction->AsLongConstant()->GetValue();
343 if (location.IsRegister()) {
344 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
345 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000346 __ movq(CpuRegister(TMP), Immediate(value));
347 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100348 }
349 } else if (instruction->AsLoadLocal() != nullptr) {
350 switch (instruction->GetType()) {
351 case Primitive::kPrimBoolean:
352 case Primitive::kPrimByte:
353 case Primitive::kPrimChar:
354 case Primitive::kPrimShort:
355 case Primitive::kPrimInt:
356 case Primitive::kPrimNot:
357 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
358 break;
359
360 case Primitive::kPrimLong:
361 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
362 break;
363
364 default:
365 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
366 }
367 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100368 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100369 switch (instruction->GetType()) {
370 case Primitive::kPrimBoolean:
371 case Primitive::kPrimByte:
372 case Primitive::kPrimChar:
373 case Primitive::kPrimShort:
374 case Primitive::kPrimInt:
375 case Primitive::kPrimNot:
376 case Primitive::kPrimLong:
377 Move(location, instruction->GetLocations()->Out());
378 break;
379
380 default:
381 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
382 }
383 }
384}
385
386void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
387 got->SetLocations(nullptr);
388}
389
390void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
391 HBasicBlock* successor = got->GetSuccessor();
392 if (GetGraph()->GetExitBlock() == successor) {
393 codegen_->GenerateFrameExit();
394 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
395 __ jmp(codegen_->GetLabelOf(successor));
396 }
397}
398
399void LocationsBuilderX86_64::VisitExit(HExit* exit) {
400 exit->SetLocations(nullptr);
401}
402
403void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
404 if (kIsDebugBuild) {
405 __ Comment("Unreachable");
406 __ int3();
407 }
408}
409
410void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100411 LocationSummary* locations =
412 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100413 HInstruction* cond = if_instr->InputAt(0);
414 DCHECK(cond->IsCondition());
415 HCondition* condition = cond->AsCondition();
416 if (condition->NeedsMaterialization()) {
417 locations->SetInAt(0, Location::Any());
418 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100419}
420
421void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700422 HInstruction* cond = if_instr->InputAt(0);
423 DCHECK(cond->IsCondition());
424 HCondition* condition = cond->AsCondition();
425 if (condition->NeedsMaterialization()) {
426 // Materialized condition, compare against 0.
427 Location lhs = if_instr->GetLocations()->InAt(0);
428 if (lhs.IsRegister()) {
429 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
430 } else {
431 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
432 }
433 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
434 } else {
435 Location lhs = condition->GetLocations()->InAt(0);
436 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100437 if (rhs.IsRegister()) {
438 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
439 } else if (rhs.IsConstant()) {
440 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
441 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
442 } else {
443 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
444 }
Dave Allison20dfc792014-06-16 20:44:29 -0700445 __ j(X86_64Condition(condition->GetCondition()),
446 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
447 }
448 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
449 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100450 }
451}
452
453void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
454 local->SetLocations(nullptr);
455}
456
457void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
458 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
459}
460
461void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
462 local->SetLocations(nullptr);
463}
464
465void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
466 // Nothing to do, this is driven by the code generator.
467}
468
469void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100470 LocationSummary* locations =
471 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100472 switch (store->InputAt(1)->GetType()) {
473 case Primitive::kPrimBoolean:
474 case Primitive::kPrimByte:
475 case Primitive::kPrimChar:
476 case Primitive::kPrimShort:
477 case Primitive::kPrimInt:
478 case Primitive::kPrimNot:
479 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
480 break;
481
482 case Primitive::kPrimLong:
483 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
484 break;
485
486 default:
487 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
488 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100489}
490
491void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
492}
493
Dave Allison20dfc792014-06-16 20:44:29 -0700494void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100495 LocationSummary* locations =
496 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000497 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100498 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100499 if (comp->NeedsMaterialization()) {
500 locations->SetOut(Location::RequiresRegister());
501 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100502}
503
Dave Allison20dfc792014-06-16 20:44:29 -0700504void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
505 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100506 LocationSummary* locations = comp->GetLocations();
507 if (locations->InAt(1).IsRegister()) {
508 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
509 locations->InAt(1).AsX86_64().AsCpuRegister());
510 } else if (locations->InAt(1).IsConstant()) {
511 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
512 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
513 } else {
514 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
515 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
516 }
Dave Allison20dfc792014-06-16 20:44:29 -0700517 __ setcc(X86_64Condition(comp->GetCondition()),
518 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
519 }
520}
521
522void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
523 VisitCondition(comp);
524}
525
526void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
527 VisitCondition(comp);
528}
529
530void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
531 VisitCondition(comp);
532}
533
534void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
535 VisitCondition(comp);
536}
537
538void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
539 VisitCondition(comp);
540}
541
542void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
543 VisitCondition(comp);
544}
545
546void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
547 VisitCondition(comp);
548}
549
550void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
551 VisitCondition(comp);
552}
553
554void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
555 VisitCondition(comp);
556}
557
558void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
559 VisitCondition(comp);
560}
561
562void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
563 VisitCondition(comp);
564}
565
566void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
567 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100568}
569
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100570void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100571 LocationSummary* locations =
572 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100573 locations->SetInAt(0, Location::RequiresRegister());
574 locations->SetInAt(1, Location::RequiresRegister());
575 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100576}
577
578void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
579 Label greater, done;
580 LocationSummary* locations = compare->GetLocations();
581 switch (compare->InputAt(0)->GetType()) {
582 case Primitive::kPrimLong:
583 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
584 locations->InAt(1).AsX86_64().AsCpuRegister());
585 break;
586 default:
587 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
588 }
589
590 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
591 __ j(kEqual, &done);
592 __ j(kGreater, &greater);
593
594 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
595 __ jmp(&done);
596
597 __ Bind(&greater);
598 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
599
600 __ Bind(&done);
601}
602
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100603void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100604 LocationSummary* locations =
605 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100606 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100607}
608
609void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100610}
611
612void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100613 LocationSummary* locations =
614 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100615 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100616}
617
618void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100619}
620
621void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
622 ret->SetLocations(nullptr);
623}
624
625void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
626 codegen_->GenerateFrameExit();
627 __ ret();
628}
629
630void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100631 LocationSummary* locations =
632 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100633 switch (ret->InputAt(0)->GetType()) {
634 case Primitive::kPrimBoolean:
635 case Primitive::kPrimByte:
636 case Primitive::kPrimChar:
637 case Primitive::kPrimShort:
638 case Primitive::kPrimInt:
639 case Primitive::kPrimNot:
640 case Primitive::kPrimLong:
641 locations->SetInAt(0, X86_64CpuLocation(RAX));
642 break;
643
644 default:
645 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
646 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100647}
648
649void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
650 if (kIsDebugBuild) {
651 switch (ret->InputAt(0)->GetType()) {
652 case Primitive::kPrimBoolean:
653 case Primitive::kPrimByte:
654 case Primitive::kPrimChar:
655 case Primitive::kPrimShort:
656 case Primitive::kPrimInt:
657 case Primitive::kPrimNot:
658 case Primitive::kPrimLong:
659 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
660 break;
661
662 default:
663 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
664 }
665 }
666 codegen_->GenerateFrameExit();
667 __ ret();
668}
669
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100670Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
671 switch (type) {
672 case Primitive::kPrimBoolean:
673 case Primitive::kPrimByte:
674 case Primitive::kPrimChar:
675 case Primitive::kPrimShort:
676 case Primitive::kPrimInt:
677 case Primitive::kPrimNot: {
678 uint32_t index = gp_index_++;
679 stack_index_++;
680 if (index < calling_convention.GetNumberOfRegisters()) {
681 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
682 } else {
683 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
684 }
685 }
686
687 case Primitive::kPrimLong: {
688 uint32_t index = gp_index_;
689 stack_index_ += 2;
690 if (index < calling_convention.GetNumberOfRegisters()) {
691 gp_index_ += 1;
692 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
693 } else {
694 gp_index_ += 2;
695 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
696 }
697 }
698
699 case Primitive::kPrimDouble:
700 case Primitive::kPrimFloat:
701 LOG(FATAL) << "Unimplemented parameter type " << type;
702 break;
703
704 case Primitive::kPrimVoid:
705 LOG(FATAL) << "Unexpected parameter type " << type;
706 break;
707 }
708 return Location();
709}
710
711void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100712 LocationSummary* locations =
713 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100714 locations->AddTemp(X86_64CpuLocation(RDI));
715
716 InvokeDexCallingConventionVisitor calling_convention_visitor;
717 for (size_t i = 0; i < invoke->InputCount(); ++i) {
718 HInstruction* input = invoke->InputAt(i);
719 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
720 }
721
722 switch (invoke->GetType()) {
723 case Primitive::kPrimBoolean:
724 case Primitive::kPrimByte:
725 case Primitive::kPrimChar:
726 case Primitive::kPrimShort:
727 case Primitive::kPrimInt:
728 case Primitive::kPrimNot:
729 case Primitive::kPrimLong:
730 locations->SetOut(X86_64CpuLocation(RAX));
731 break;
732
733 case Primitive::kPrimVoid:
734 break;
735
736 case Primitive::kPrimDouble:
737 case Primitive::kPrimFloat:
738 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
739 break;
740 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100741}
742
743void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
744 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
745 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
746 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
747 invoke->GetIndexInDexCache() * heap_reference_size;
748
749 // TODO: Implement all kinds of calls:
750 // 1) boot -> boot
751 // 2) app -> boot
752 // 3) app -> app
753 //
754 // Currently we implement the app -> app logic, which looks up in the resolve cache.
755
756 // temp = method;
757 LoadCurrentMethod(temp);
758 // temp = temp->dex_cache_resolved_methods_;
759 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
760 // temp = temp[index_in_cache]
761 __ movl(temp, Address(temp, index_in_cache));
762 // (temp + offset_of_quick_compiled_code)()
763 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
764
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100765 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100766 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100767}
768
769void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100770 LocationSummary* locations =
771 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100772 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100773 case Primitive::kPrimInt: {
774 locations->SetInAt(0, Location::RequiresRegister());
775 locations->SetInAt(1, Location::Any());
776 locations->SetOut(Location::SameAsFirstInput());
777 break;
778 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100779 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000780 locations->SetInAt(0, Location::RequiresRegister());
781 locations->SetInAt(1, Location::RequiresRegister());
782 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100783 break;
784 }
785
786 case Primitive::kPrimBoolean:
787 case Primitive::kPrimByte:
788 case Primitive::kPrimChar:
789 case Primitive::kPrimShort:
790 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
791 break;
792
793 default:
794 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
795 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100796}
797
798void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
799 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000800 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
801 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100802 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000803 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100804 if (locations->InAt(1).IsRegister()) {
805 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
806 locations->InAt(1).AsX86_64().AsCpuRegister());
807 } else if (locations->InAt(1).IsConstant()) {
808 HConstant* instruction = locations->InAt(1).GetConstant();
809 Immediate imm(instruction->AsIntConstant()->GetValue());
810 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
811 } else {
812 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
813 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
814 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000815 break;
816 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100817 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100818 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
819 locations->InAt(1).AsX86_64().AsCpuRegister());
820 break;
821 }
822
823 case Primitive::kPrimBoolean:
824 case Primitive::kPrimByte:
825 case Primitive::kPrimChar:
826 case Primitive::kPrimShort:
827 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
828 break;
829
830 default:
831 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
832 }
833}
834
835void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100836 LocationSummary* locations =
837 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100838 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100839 case Primitive::kPrimInt: {
840 locations->SetInAt(0, Location::RequiresRegister());
841 locations->SetInAt(1, Location::Any());
842 locations->SetOut(Location::SameAsFirstInput());
843 break;
844 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100845 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000846 locations->SetInAt(0, Location::RequiresRegister());
847 locations->SetInAt(1, Location::RequiresRegister());
848 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100849 break;
850 }
851
852 case Primitive::kPrimBoolean:
853 case Primitive::kPrimByte:
854 case Primitive::kPrimChar:
855 case Primitive::kPrimShort:
856 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
857 break;
858
859 default:
860 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
861 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100862}
863
864void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
865 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000866 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
867 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100868 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000869 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100870 if (locations->InAt(1).IsRegister()) {
871 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
872 locations->InAt(1).AsX86_64().AsCpuRegister());
873 } else if (locations->InAt(1).IsConstant()) {
874 HConstant* instruction = locations->InAt(1).GetConstant();
875 Immediate imm(instruction->AsIntConstant()->GetValue());
876 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
877 } else {
878 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
879 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
880 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000881 break;
882 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100883 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100884 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
885 locations->InAt(1).AsX86_64().AsCpuRegister());
886 break;
887 }
888
889 case Primitive::kPrimBoolean:
890 case Primitive::kPrimByte:
891 case Primitive::kPrimChar:
892 case Primitive::kPrimShort:
893 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
894 break;
895
896 default:
897 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
898 }
899}
900
901void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100902 LocationSummary* locations =
903 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100904 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100905}
906
907void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
908 InvokeRuntimeCallingConvention calling_convention;
909 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
910 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
911
912 __ gs()->call(Address::Absolute(
913 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
914
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100915 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100916 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100917}
918
919void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100920 LocationSummary* locations =
921 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100922 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
923 if (location.IsStackSlot()) {
924 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
925 } else if (location.IsDoubleStackSlot()) {
926 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
927 }
928 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100929}
930
931void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
932 // Nothing to do, the parameter is already at its location.
933}
934
935void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100936 LocationSummary* locations =
937 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000938 locations->SetInAt(0, Location::RequiresRegister());
939 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940}
941
942void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
943 LocationSummary* locations = instruction->GetLocations();
944 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
945 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
946 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
947}
948
949void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100950 LocationSummary* locations =
951 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100952 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
953 locations->SetInAt(i, Location::Any());
954 }
955 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100956}
957
958void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
959 LOG(FATAL) << "Unimplemented";
960}
961
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100962void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100963 LocationSummary* locations =
964 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100965 locations->SetInAt(0, Location::RequiresRegister());
966 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100967 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +0100968 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100969 locations->AddTemp(Location::RequiresRegister());
970 locations->AddTemp(Location::RequiresRegister());
971 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100972}
973
974void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
975 LocationSummary* locations = instruction->GetLocations();
976 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
977 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
978 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100979 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100980
981 switch (field_type) {
982 case Primitive::kPrimBoolean:
983 case Primitive::kPrimByte: {
984 __ movb(Address(obj, offset), value);
985 break;
986 }
987
988 case Primitive::kPrimShort:
989 case Primitive::kPrimChar: {
990 __ movw(Address(obj, offset), value);
991 break;
992 }
993
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100994 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100995 case Primitive::kPrimNot: {
996 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100997 if (field_type == Primitive::kPrimNot) {
998 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
999 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1000 codegen_->MarkGCCard(temp, card, obj, value);
1001 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001002 break;
1003 }
1004
1005 case Primitive::kPrimLong: {
1006 __ movq(Address(obj, offset), value);
1007 break;
1008 }
1009
1010 case Primitive::kPrimFloat:
1011 case Primitive::kPrimDouble:
1012 LOG(FATAL) << "Unimplemented register type " << field_type;
1013
1014 case Primitive::kPrimVoid:
1015 LOG(FATAL) << "Unreachable type " << field_type;
1016 }
1017}
1018
1019void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001020 LocationSummary* locations =
1021 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001022 locations->SetInAt(0, Location::RequiresRegister());
1023 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001024}
1025
1026void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1027 LocationSummary* locations = instruction->GetLocations();
1028 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1029 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1030 size_t offset = instruction->GetFieldOffset().SizeValue();
1031
1032 switch (instruction->GetType()) {
1033 case Primitive::kPrimBoolean: {
1034 __ movzxb(out, Address(obj, offset));
1035 break;
1036 }
1037
1038 case Primitive::kPrimByte: {
1039 __ movsxb(out, Address(obj, offset));
1040 break;
1041 }
1042
1043 case Primitive::kPrimShort: {
1044 __ movsxw(out, Address(obj, offset));
1045 break;
1046 }
1047
1048 case Primitive::kPrimChar: {
1049 __ movzxw(out, Address(obj, offset));
1050 break;
1051 }
1052
1053 case Primitive::kPrimInt:
1054 case Primitive::kPrimNot: {
1055 __ movl(out, Address(obj, offset));
1056 break;
1057 }
1058
1059 case Primitive::kPrimLong: {
1060 __ movq(out, Address(obj, offset));
1061 break;
1062 }
1063
1064 case Primitive::kPrimFloat:
1065 case Primitive::kPrimDouble:
1066 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1067
1068 case Primitive::kPrimVoid:
1069 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1070 }
1071}
1072
1073void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001074 LocationSummary* locations =
1075 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001076 locations->SetInAt(0, Location::Any());
1077 // TODO: Have a normalization phase that makes this instruction never used.
1078 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001079}
1080
1081void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001082 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001083 codegen_->AddSlowPath(slow_path);
1084
1085 LocationSummary* locations = instruction->GetLocations();
1086 Location obj = locations->InAt(0);
1087 DCHECK(obj.Equals(locations->Out()));
1088
1089 if (obj.IsRegister()) {
1090 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1091 } else {
1092 DCHECK(locations->InAt(0).IsStackSlot());
1093 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1094 }
1095 __ j(kEqual, slow_path->GetEntryLabel());
1096}
1097
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001098void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001099 LocationSummary* locations =
1100 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001101 locations->SetInAt(0, Location::RequiresRegister());
1102 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1103 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001104}
1105
1106void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1107 LocationSummary* locations = instruction->GetLocations();
1108 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1109 Location index = locations->InAt(1);
1110
1111 switch (instruction->GetType()) {
1112 case Primitive::kPrimBoolean: {
1113 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1114 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1115 if (index.IsConstant()) {
1116 __ movzxb(out, Address(obj,
1117 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1118 } else {
1119 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1120 }
1121 break;
1122 }
1123
1124 case Primitive::kPrimByte: {
1125 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1126 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1127 if (index.IsConstant()) {
1128 __ movsxb(out, Address(obj,
1129 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1130 } else {
1131 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1132 }
1133 break;
1134 }
1135
1136 case Primitive::kPrimShort: {
1137 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1138 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1139 if (index.IsConstant()) {
1140 __ movsxw(out, Address(obj,
1141 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1142 } else {
1143 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1144 }
1145 break;
1146 }
1147
1148 case Primitive::kPrimChar: {
1149 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1150 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1151 if (index.IsConstant()) {
1152 __ movzxw(out, Address(obj,
1153 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1154 } else {
1155 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1156 }
1157 break;
1158 }
1159
1160 case Primitive::kPrimInt:
1161 case Primitive::kPrimNot: {
1162 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1163 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1164 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1165 if (index.IsConstant()) {
1166 __ movl(out, Address(obj,
1167 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1168 } else {
1169 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1170 }
1171 break;
1172 }
1173
1174 case Primitive::kPrimLong: {
1175 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1176 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1177 if (index.IsConstant()) {
1178 __ movq(out, Address(obj,
1179 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1180 } else {
1181 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1182 }
1183 break;
1184 }
1185
1186 case Primitive::kPrimFloat:
1187 case Primitive::kPrimDouble:
1188 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1189
1190 case Primitive::kPrimVoid:
1191 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1192 }
1193}
1194
1195void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001196 Primitive::Type value_type = instruction->GetComponentType();
1197 bool is_object = value_type == Primitive::kPrimNot;
1198 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1199 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1200 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001201 InvokeRuntimeCallingConvention calling_convention;
1202 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1203 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1204 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001205 } else {
1206 locations->SetInAt(0, Location::RequiresRegister());
1207 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1208 locations->SetInAt(2, Location::RequiresRegister());
1209 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001210}
1211
1212void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1213 LocationSummary* locations = instruction->GetLocations();
1214 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1215 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001216 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001217
1218 switch (value_type) {
1219 case Primitive::kPrimBoolean:
1220 case Primitive::kPrimByte: {
1221 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1222 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1223 if (index.IsConstant()) {
1224 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1225 __ movb(Address(obj, offset), value);
1226 } else {
1227 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1228 }
1229 break;
1230 }
1231
1232 case Primitive::kPrimShort:
1233 case Primitive::kPrimChar: {
1234 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1235 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1236 if (index.IsConstant()) {
1237 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1238 __ movw(Address(obj, offset), value);
1239 } else {
1240 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1241 }
1242 break;
1243 }
1244
1245 case Primitive::kPrimInt: {
1246 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1247 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1248 if (index.IsConstant()) {
1249 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1250 __ movl(Address(obj, offset), value);
1251 } else {
1252 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1253 }
1254 break;
1255 }
1256
1257 case Primitive::kPrimNot: {
1258 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1259 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001260 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001261 break;
1262 }
1263
1264 case Primitive::kPrimLong: {
1265 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1266 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1267 if (index.IsConstant()) {
1268 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1269 __ movq(Address(obj, offset), value);
1270 } else {
1271 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1272 }
1273 break;
1274 }
1275
1276 case Primitive::kPrimFloat:
1277 case Primitive::kPrimDouble:
1278 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1279
1280 case Primitive::kPrimVoid:
1281 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1282 }
1283}
1284
1285void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001286 LocationSummary* locations =
1287 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001288 locations->SetInAt(0, Location::RequiresRegister());
1289 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001290}
1291
1292void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1293 LocationSummary* locations = instruction->GetLocations();
1294 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1295 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1296 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1297 __ movl(out, Address(obj, offset));
1298}
1299
1300void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001301 LocationSummary* locations =
1302 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001303 locations->SetInAt(0, Location::RequiresRegister());
1304 locations->SetInAt(1, Location::RequiresRegister());
1305 // TODO: Have a normalization phase that makes this instruction never used.
1306 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001307}
1308
1309void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1310 LocationSummary* locations = instruction->GetLocations();
1311 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001312 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001313 codegen_->AddSlowPath(slow_path);
1314
1315 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1316 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1317
1318 __ cmpl(index, length);
1319 __ j(kAboveEqual, slow_path->GetEntryLabel());
1320}
1321
1322void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1323 CpuRegister card,
1324 CpuRegister object,
1325 CpuRegister value) {
1326 Label is_null;
1327 __ testl(value, value);
1328 __ j(kEqual, &is_null);
1329 __ gs()->movq(card, Address::Absolute(
1330 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1331 __ movq(temp, object);
1332 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1333 __ movb(Address(temp, card, TIMES_1, 0), card);
1334 __ Bind(&is_null);
1335}
1336
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001337void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1338 temp->SetLocations(nullptr);
1339}
1340
1341void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1342 // Nothing to do, this is driven by the code generator.
1343}
1344
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001345void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1346 LOG(FATAL) << "Unimplemented";
1347}
1348
1349void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001350 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1351}
1352
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001353void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1354 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1355}
1356
1357void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1358 SuspendCheckSlowPathX86_64* slow_path =
1359 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction);
1360 codegen_->AddSlowPath(slow_path);
1361 __ gs()->cmpl(Address::Absolute(
1362 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
1363 __ j(kNotEqual, slow_path->GetEntryLabel());
1364 __ Bind(slow_path->GetReturnLabel());
1365}
1366
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001367X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1368 return codegen_->GetAssembler();
1369}
1370
1371void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1372 MoveOperands* move = moves_.Get(index);
1373 Location source = move->GetSource();
1374 Location destination = move->GetDestination();
1375
1376 if (source.IsRegister()) {
1377 if (destination.IsRegister()) {
1378 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001379 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001380 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1381 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001382 } else {
1383 DCHECK(destination.IsDoubleStackSlot());
1384 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1385 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001386 }
1387 } else if (source.IsStackSlot()) {
1388 if (destination.IsRegister()) {
1389 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1390 Address(CpuRegister(RSP), source.GetStackIndex()));
1391 } else {
1392 DCHECK(destination.IsStackSlot());
1393 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1394 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1395 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001396 } else if (source.IsDoubleStackSlot()) {
1397 if (destination.IsRegister()) {
1398 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1399 Address(CpuRegister(RSP), source.GetStackIndex()));
1400 } else {
1401 DCHECK(destination.IsDoubleStackSlot());
1402 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1403 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1404 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001405 } else if (source.IsConstant()) {
1406 HConstant* constant = source.GetConstant();
1407 if (constant->IsIntConstant()) {
1408 Immediate imm(constant->AsIntConstant()->GetValue());
1409 if (destination.IsRegister()) {
1410 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1411 } else {
1412 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1413 }
1414 } else if (constant->IsLongConstant()) {
1415 int64_t value = constant->AsLongConstant()->GetValue();
1416 if (destination.IsRegister()) {
1417 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1418 } else {
1419 __ movq(CpuRegister(TMP), Immediate(value));
1420 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1421 }
1422 } else {
1423 LOG(FATAL) << "Unimplemented constant type";
1424 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001425 } else {
1426 LOG(FATAL) << "Unimplemented";
1427 }
1428}
1429
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001430void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001431 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001432 __ movl(Address(CpuRegister(RSP), mem), reg);
1433 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001434}
1435
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001436void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001437 ScratchRegisterScope ensure_scratch(
1438 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1439
1440 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1441 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1442 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1443 Address(CpuRegister(RSP), mem2 + stack_offset));
1444 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1445 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1446 CpuRegister(ensure_scratch.GetRegister()));
1447}
1448
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001449void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1450 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1451 __ movq(Address(CpuRegister(RSP), mem), reg);
1452 __ movq(reg, CpuRegister(TMP));
1453}
1454
1455void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1456 ScratchRegisterScope ensure_scratch(
1457 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1458
1459 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1460 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1461 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1462 Address(CpuRegister(RSP), mem2 + stack_offset));
1463 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1464 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1465 CpuRegister(ensure_scratch.GetRegister()));
1466}
1467
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001468void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1469 MoveOperands* move = moves_.Get(index);
1470 Location source = move->GetSource();
1471 Location destination = move->GetDestination();
1472
1473 if (source.IsRegister() && destination.IsRegister()) {
1474 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1475 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001476 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001477 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001478 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001479 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001480 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1481 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1482 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1483 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1484 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1485 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1486 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001487 } else {
1488 LOG(FATAL) << "Unimplemented";
1489 }
1490}
1491
1492
1493void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1494 __ pushq(CpuRegister(reg));
1495}
1496
1497
1498void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1499 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001500}
1501
1502} // namespace x86_64
1503} // namespace art