blob: ca03af8e9f5065c056fa0f35e20edc47aae4ca30 [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"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "mirror/object_reference.h"
25#include "thread.h"
26#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010027#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "utils/x86_64/assembler_x86_64.h"
29#include "utils/x86_64/managed_register_x86_64.h"
30
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010031namespace art {
32
33x86_64::X86_64ManagedRegister Location::AsX86_64() const {
34 return reg().AsX86_64();
35}
36
37namespace x86_64 {
38
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010039static constexpr bool kExplicitStackOverflowCheck = false;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040
41// Some x86_64 instructions require a register to be available as temp.
42static constexpr Register TMP = R11;
43
44static constexpr int kNumberOfPushedRegistersAtEntry = 1;
45static constexpr int kCurrentMethodStackOffset = 0;
46
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010047static Location X86_64CpuLocation(Register reg) {
48 return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
49}
50
51static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
52static constexpr size_t kRuntimeParameterCoreRegistersLength =
53 arraysize(kRuntimeParameterCoreRegisters);
54
55class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
56 public:
57 InvokeRuntimeCallingConvention()
58 : CallingConvention(kRuntimeParameterCoreRegisters,
59 kRuntimeParameterCoreRegistersLength) {}
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010064
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
66
67class NullCheckSlowPathX86_64 : public SlowPathCode {
68 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070
71 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
72 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010073 __ gs()->call(
74 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 }
77
78 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
81};
82
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010083class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
84 public:
85 StackOverflowCheckSlowPathX86_64() {}
86
87 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
88 __ Bind(GetEntryLabel());
89 __ addq(CpuRegister(RSP),
90 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
91 __ gs()->jmp(
92 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
93 }
94
95 private:
96 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
97};
98
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000099class SuspendCheckSlowPathX86_64 : public SlowPathCode {
100 public:
101 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction)
102 : instruction_(instruction) {}
103
104 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
105 __ Bind(GetEntryLabel());
106 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
107 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
108 __ jmp(GetReturnLabel());
109 }
110
111 Label* GetReturnLabel() { return &return_label_; }
112
113 private:
114 HSuspendCheck* const instruction_;
115 Label return_label_;
116
117 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
118};
119
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100120class BoundsCheckSlowPathX86_64 : public SlowPathCode {
121 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100122 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100123 Location index_location,
124 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100125 : instruction_(instruction),
126 index_location_(index_location),
127 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100128
129 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
130 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
131 __ Bind(GetEntryLabel());
132 InvokeRuntimeCallingConvention calling_convention;
133 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
134 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
135 __ gs()->call(Address::Absolute(
136 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100137 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138 }
139
140 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100141 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100142 const Location index_location_;
143 const Location length_location_;
144
145 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
146};
147
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100148#undef __
149#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
150
Dave Allison20dfc792014-06-16 20:44:29 -0700151inline Condition X86_64Condition(IfCondition cond) {
152 switch (cond) {
153 case kCondEQ: return kEqual;
154 case kCondNE: return kNotEqual;
155 case kCondLT: return kLess;
156 case kCondLE: return kLessEqual;
157 case kCondGT: return kGreater;
158 case kCondGE: return kGreaterEqual;
159 default:
160 LOG(FATAL) << "Unknown if condition";
161 }
162 return kEqual;
163}
164
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100165void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
166 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
167}
168
169void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
170 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
171}
172
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100173CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
174 : CodeGenerator(graph, kNumberOfRegIds),
175 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000176 instruction_visitor_(graph, this),
177 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100178
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100179size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
180 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
181}
182
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
184 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100185 : HGraphVisitor(graph),
186 assembler_(codegen->GetAssembler()),
187 codegen_(codegen) {}
188
189ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
190 bool* blocked_registers) const {
191 switch (type) {
192 case Primitive::kPrimLong:
193 case Primitive::kPrimByte:
194 case Primitive::kPrimBoolean:
195 case Primitive::kPrimChar:
196 case Primitive::kPrimShort:
197 case Primitive::kPrimInt:
198 case Primitive::kPrimNot: {
199 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
200 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
201 }
202
203 case Primitive::kPrimFloat:
204 case Primitive::kPrimDouble:
205 LOG(FATAL) << "Unimplemented register type " << type;
206
207 case Primitive::kPrimVoid:
208 LOG(FATAL) << "Unreachable type " << type;
209 }
210
211 return ManagedRegister::NoRegister();
212}
213
214void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
215 // Stack register is always reserved.
216 blocked_registers[RSP] = true;
217
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000218 // Block the register used as TMP.
219 blocked_registers[TMP] = true;
220
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100221 // TODO: We currently don't use Quick's callee saved registers.
222 blocked_registers[RBX] = true;
223 blocked_registers[RBP] = true;
224 blocked_registers[R12] = true;
225 blocked_registers[R13] = true;
226 blocked_registers[R14] = true;
227 blocked_registers[R15] = true;
228}
229
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100230void CodeGeneratorX86_64::GenerateFrameEntry() {
231 // Create a fake register to mimic Quick.
232 static const int kFakeReturnRegister = 16;
233 core_spill_mask_ |= (1 << kFakeReturnRegister);
234
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100235 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700236 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100237
238 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
239 __ testq(CpuRegister(RAX), Address(
240 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100241 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100242 }
243
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100244 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100245 __ subq(CpuRegister(RSP),
246 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
247
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100248 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
249 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
250 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100251
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100252 __ gs()->cmpq(CpuRegister(RSP),
253 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
254 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100255 }
256
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100257 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
258}
259
260void CodeGeneratorX86_64::GenerateFrameExit() {
261 __ addq(CpuRegister(RSP),
262 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
263}
264
265void CodeGeneratorX86_64::Bind(Label* label) {
266 __ Bind(label);
267}
268
269void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
270 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
271}
272
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100273Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
274 switch (load->GetType()) {
275 case Primitive::kPrimLong:
276 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
277 break;
278
279 case Primitive::kPrimInt:
280 case Primitive::kPrimNot:
281 return Location::StackSlot(GetStackSlot(load->GetLocal()));
282
283 case Primitive::kPrimFloat:
284 case Primitive::kPrimDouble:
285 LOG(FATAL) << "Unimplemented type " << load->GetType();
286
287 case Primitive::kPrimBoolean:
288 case Primitive::kPrimByte:
289 case Primitive::kPrimChar:
290 case Primitive::kPrimShort:
291 case Primitive::kPrimVoid:
292 LOG(FATAL) << "Unexpected type " << load->GetType();
293 }
294
295 LOG(FATAL) << "Unreachable";
296 return Location();
297}
298
299void CodeGeneratorX86_64::Move(Location destination, Location source) {
300 if (source.Equals(destination)) {
301 return;
302 }
303 if (destination.IsRegister()) {
304 if (source.IsRegister()) {
305 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
306 } else if (source.IsStackSlot()) {
307 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
308 } else {
309 DCHECK(source.IsDoubleStackSlot());
310 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
311 }
312 } else if (destination.IsStackSlot()) {
313 if (source.IsRegister()) {
314 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
315 } else {
316 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000317 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
318 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100319 }
320 } else {
321 DCHECK(destination.IsDoubleStackSlot());
322 if (source.IsRegister()) {
323 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
324 } else {
325 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000326 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
327 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100328 }
329 }
330}
331
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100332void CodeGeneratorX86_64::Move(HInstruction* instruction,
333 Location location,
334 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100335 if (instruction->AsIntConstant() != nullptr) {
336 Immediate imm(instruction->AsIntConstant()->GetValue());
337 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000338 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100339 } else {
340 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
341 }
342 } else if (instruction->AsLongConstant() != nullptr) {
343 int64_t value = instruction->AsLongConstant()->GetValue();
344 if (location.IsRegister()) {
345 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
346 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000347 __ movq(CpuRegister(TMP), Immediate(value));
348 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100349 }
350 } else if (instruction->AsLoadLocal() != nullptr) {
351 switch (instruction->GetType()) {
352 case Primitive::kPrimBoolean:
353 case Primitive::kPrimByte:
354 case Primitive::kPrimChar:
355 case Primitive::kPrimShort:
356 case Primitive::kPrimInt:
357 case Primitive::kPrimNot:
358 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
359 break;
360
361 case Primitive::kPrimLong:
362 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
363 break;
364
365 default:
366 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
367 }
368 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100369 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100370 switch (instruction->GetType()) {
371 case Primitive::kPrimBoolean:
372 case Primitive::kPrimByte:
373 case Primitive::kPrimChar:
374 case Primitive::kPrimShort:
375 case Primitive::kPrimInt:
376 case Primitive::kPrimNot:
377 case Primitive::kPrimLong:
378 Move(location, instruction->GetLocations()->Out());
379 break;
380
381 default:
382 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
383 }
384 }
385}
386
387void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
388 got->SetLocations(nullptr);
389}
390
391void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
392 HBasicBlock* successor = got->GetSuccessor();
393 if (GetGraph()->GetExitBlock() == successor) {
394 codegen_->GenerateFrameExit();
395 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
396 __ jmp(codegen_->GetLabelOf(successor));
397 }
398}
399
400void LocationsBuilderX86_64::VisitExit(HExit* exit) {
401 exit->SetLocations(nullptr);
402}
403
404void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
405 if (kIsDebugBuild) {
406 __ Comment("Unreachable");
407 __ int3();
408 }
409}
410
411void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100412 LocationSummary* locations =
413 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100414 HInstruction* cond = if_instr->InputAt(0);
415 DCHECK(cond->IsCondition());
416 HCondition* condition = cond->AsCondition();
417 if (condition->NeedsMaterialization()) {
418 locations->SetInAt(0, Location::Any());
419 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100420}
421
422void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700423 HInstruction* cond = if_instr->InputAt(0);
424 DCHECK(cond->IsCondition());
425 HCondition* condition = cond->AsCondition();
426 if (condition->NeedsMaterialization()) {
427 // Materialized condition, compare against 0.
428 Location lhs = if_instr->GetLocations()->InAt(0);
429 if (lhs.IsRegister()) {
430 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
431 } else {
432 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
433 }
434 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
435 } else {
436 Location lhs = condition->GetLocations()->InAt(0);
437 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100438 if (rhs.IsRegister()) {
439 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
440 } else if (rhs.IsConstant()) {
441 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
442 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
443 } else {
444 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
445 }
Dave Allison20dfc792014-06-16 20:44:29 -0700446 __ j(X86_64Condition(condition->GetCondition()),
447 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
448 }
449 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
450 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100451 }
452}
453
454void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
455 local->SetLocations(nullptr);
456}
457
458void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
459 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
460}
461
462void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
463 local->SetLocations(nullptr);
464}
465
466void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
467 // Nothing to do, this is driven by the code generator.
468}
469
470void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100471 LocationSummary* locations =
472 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100473 switch (store->InputAt(1)->GetType()) {
474 case Primitive::kPrimBoolean:
475 case Primitive::kPrimByte:
476 case Primitive::kPrimChar:
477 case Primitive::kPrimShort:
478 case Primitive::kPrimInt:
479 case Primitive::kPrimNot:
480 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
481 break;
482
483 case Primitive::kPrimLong:
484 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
485 break;
486
487 default:
488 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
489 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100490}
491
492void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
493}
494
Dave Allison20dfc792014-06-16 20:44:29 -0700495void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100496 LocationSummary* locations =
497 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000498 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100499 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100500 if (comp->NeedsMaterialization()) {
501 locations->SetOut(Location::RequiresRegister());
502 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100503}
504
Dave Allison20dfc792014-06-16 20:44:29 -0700505void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
506 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100507 LocationSummary* locations = comp->GetLocations();
508 if (locations->InAt(1).IsRegister()) {
509 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
510 locations->InAt(1).AsX86_64().AsCpuRegister());
511 } else if (locations->InAt(1).IsConstant()) {
512 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
513 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
514 } else {
515 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
516 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
517 }
Dave Allison20dfc792014-06-16 20:44:29 -0700518 __ setcc(X86_64Condition(comp->GetCondition()),
519 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
520 }
521}
522
523void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
524 VisitCondition(comp);
525}
526
527void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
528 VisitCondition(comp);
529}
530
531void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
532 VisitCondition(comp);
533}
534
535void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
536 VisitCondition(comp);
537}
538
539void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
540 VisitCondition(comp);
541}
542
543void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
544 VisitCondition(comp);
545}
546
547void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
548 VisitCondition(comp);
549}
550
551void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
552 VisitCondition(comp);
553}
554
555void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
556 VisitCondition(comp);
557}
558
559void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
560 VisitCondition(comp);
561}
562
563void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
564 VisitCondition(comp);
565}
566
567void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
568 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100569}
570
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100571void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100572 LocationSummary* locations =
573 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100574 locations->SetInAt(0, Location::RequiresRegister());
575 locations->SetInAt(1, Location::RequiresRegister());
576 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100577}
578
579void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
580 Label greater, done;
581 LocationSummary* locations = compare->GetLocations();
582 switch (compare->InputAt(0)->GetType()) {
583 case Primitive::kPrimLong:
584 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
585 locations->InAt(1).AsX86_64().AsCpuRegister());
586 break;
587 default:
588 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
589 }
590
591 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
592 __ j(kEqual, &done);
593 __ j(kGreater, &greater);
594
595 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
596 __ jmp(&done);
597
598 __ Bind(&greater);
599 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
600
601 __ Bind(&done);
602}
603
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100604void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100605 LocationSummary* locations =
606 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100607 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100608}
609
610void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100611}
612
613void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100614 LocationSummary* locations =
615 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100616 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100617}
618
619void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100620}
621
622void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
623 ret->SetLocations(nullptr);
624}
625
626void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
627 codegen_->GenerateFrameExit();
628 __ ret();
629}
630
631void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100632 LocationSummary* locations =
633 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100634 switch (ret->InputAt(0)->GetType()) {
635 case Primitive::kPrimBoolean:
636 case Primitive::kPrimByte:
637 case Primitive::kPrimChar:
638 case Primitive::kPrimShort:
639 case Primitive::kPrimInt:
640 case Primitive::kPrimNot:
641 case Primitive::kPrimLong:
642 locations->SetInAt(0, X86_64CpuLocation(RAX));
643 break;
644
645 default:
646 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
647 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100648}
649
650void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
651 if (kIsDebugBuild) {
652 switch (ret->InputAt(0)->GetType()) {
653 case Primitive::kPrimBoolean:
654 case Primitive::kPrimByte:
655 case Primitive::kPrimChar:
656 case Primitive::kPrimShort:
657 case Primitive::kPrimInt:
658 case Primitive::kPrimNot:
659 case Primitive::kPrimLong:
660 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
661 break;
662
663 default:
664 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
665 }
666 }
667 codegen_->GenerateFrameExit();
668 __ ret();
669}
670
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100671Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
672 switch (type) {
673 case Primitive::kPrimBoolean:
674 case Primitive::kPrimByte:
675 case Primitive::kPrimChar:
676 case Primitive::kPrimShort:
677 case Primitive::kPrimInt:
678 case Primitive::kPrimNot: {
679 uint32_t index = gp_index_++;
680 stack_index_++;
681 if (index < calling_convention.GetNumberOfRegisters()) {
682 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
683 } else {
684 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
685 }
686 }
687
688 case Primitive::kPrimLong: {
689 uint32_t index = gp_index_;
690 stack_index_ += 2;
691 if (index < calling_convention.GetNumberOfRegisters()) {
692 gp_index_ += 1;
693 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
694 } else {
695 gp_index_ += 2;
696 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
697 }
698 }
699
700 case Primitive::kPrimDouble:
701 case Primitive::kPrimFloat:
702 LOG(FATAL) << "Unimplemented parameter type " << type;
703 break;
704
705 case Primitive::kPrimVoid:
706 LOG(FATAL) << "Unexpected parameter type " << type;
707 break;
708 }
709 return Location();
710}
711
712void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100713 HandleInvoke(invoke);
714}
715
716void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
717 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
718 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
719 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
720 invoke->GetIndexInDexCache() * heap_reference_size;
721
722 // TODO: Implement all kinds of calls:
723 // 1) boot -> boot
724 // 2) app -> boot
725 // 3) app -> app
726 //
727 // Currently we implement the app -> app logic, which looks up in the resolve cache.
728
729 // temp = method;
730 LoadCurrentMethod(temp);
731 // temp = temp->dex_cache_resolved_methods_;
732 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
733 // temp = temp[index_in_cache]
734 __ movl(temp, Address(temp, index_in_cache));
735 // (temp + offset_of_quick_compiled_code)()
736 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
737
738 DCHECK(!codegen_->IsLeafMethod());
739 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
740}
741
742void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
743 HandleInvoke(invoke);
744}
745
746void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100747 LocationSummary* locations =
748 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100749 locations->AddTemp(X86_64CpuLocation(RDI));
750
751 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100752 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100753 HInstruction* input = invoke->InputAt(i);
754 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
755 }
756
757 switch (invoke->GetType()) {
758 case Primitive::kPrimBoolean:
759 case Primitive::kPrimByte:
760 case Primitive::kPrimChar:
761 case Primitive::kPrimShort:
762 case Primitive::kPrimInt:
763 case Primitive::kPrimNot:
764 case Primitive::kPrimLong:
765 locations->SetOut(X86_64CpuLocation(RAX));
766 break;
767
768 case Primitive::kPrimVoid:
769 break;
770
771 case Primitive::kPrimDouble:
772 case Primitive::kPrimFloat:
773 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
774 break;
775 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100776}
777
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100778void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100779 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100780 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
781 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
782 LocationSummary* locations = invoke->GetLocations();
783 Location receiver = locations->InAt(0);
784 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
785 // temp = object->GetClass();
786 if (receiver.IsStackSlot()) {
787 __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
788 __ movq(temp, Address(temp, class_offset));
789 } else {
790 __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
791 }
792 // temp = temp->GetMethodAt(method_offset);
793 __ movl(temp, Address(temp, method_offset));
794 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100795 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
796
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100797 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100798 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100799}
800
801void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100802 LocationSummary* locations =
803 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100804 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100805 case Primitive::kPrimInt: {
806 locations->SetInAt(0, Location::RequiresRegister());
807 locations->SetInAt(1, Location::Any());
808 locations->SetOut(Location::SameAsFirstInput());
809 break;
810 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100811 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000812 locations->SetInAt(0, Location::RequiresRegister());
813 locations->SetInAt(1, Location::RequiresRegister());
814 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100815 break;
816 }
817
818 case Primitive::kPrimBoolean:
819 case Primitive::kPrimByte:
820 case Primitive::kPrimChar:
821 case Primitive::kPrimShort:
822 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
823 break;
824
825 default:
826 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
827 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100828}
829
830void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
831 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000832 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
833 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100834 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000835 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100836 if (locations->InAt(1).IsRegister()) {
837 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
838 locations->InAt(1).AsX86_64().AsCpuRegister());
839 } else if (locations->InAt(1).IsConstant()) {
840 HConstant* instruction = locations->InAt(1).GetConstant();
841 Immediate imm(instruction->AsIntConstant()->GetValue());
842 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
843 } else {
844 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
845 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
846 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000847 break;
848 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100849 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100850 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
851 locations->InAt(1).AsX86_64().AsCpuRegister());
852 break;
853 }
854
855 case Primitive::kPrimBoolean:
856 case Primitive::kPrimByte:
857 case Primitive::kPrimChar:
858 case Primitive::kPrimShort:
859 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
860 break;
861
862 default:
863 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
864 }
865}
866
867void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100868 LocationSummary* locations =
869 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100870 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100871 case Primitive::kPrimInt: {
872 locations->SetInAt(0, Location::RequiresRegister());
873 locations->SetInAt(1, Location::Any());
874 locations->SetOut(Location::SameAsFirstInput());
875 break;
876 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100877 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000878 locations->SetInAt(0, Location::RequiresRegister());
879 locations->SetInAt(1, Location::RequiresRegister());
880 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100881 break;
882 }
883
884 case Primitive::kPrimBoolean:
885 case Primitive::kPrimByte:
886 case Primitive::kPrimChar:
887 case Primitive::kPrimShort:
888 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
889 break;
890
891 default:
892 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
893 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100894}
895
896void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
897 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000898 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
899 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100900 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000901 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100902 if (locations->InAt(1).IsRegister()) {
903 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
904 locations->InAt(1).AsX86_64().AsCpuRegister());
905 } else if (locations->InAt(1).IsConstant()) {
906 HConstant* instruction = locations->InAt(1).GetConstant();
907 Immediate imm(instruction->AsIntConstant()->GetValue());
908 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
909 } else {
910 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
911 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
912 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000913 break;
914 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100915 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100916 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
917 locations->InAt(1).AsX86_64().AsCpuRegister());
918 break;
919 }
920
921 case Primitive::kPrimBoolean:
922 case Primitive::kPrimByte:
923 case Primitive::kPrimChar:
924 case Primitive::kPrimShort:
925 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
926 break;
927
928 default:
929 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
930 }
931}
932
933void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100934 LocationSummary* locations =
935 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100936 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100937}
938
939void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
940 InvokeRuntimeCallingConvention calling_convention;
941 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
942 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
943
944 __ gs()->call(Address::Absolute(
945 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
946
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100947 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100948 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100949}
950
951void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100952 LocationSummary* locations =
953 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100954 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
955 if (location.IsStackSlot()) {
956 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
957 } else if (location.IsDoubleStackSlot()) {
958 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
959 }
960 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100961}
962
963void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
964 // Nothing to do, the parameter is already at its location.
965}
966
967void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100968 LocationSummary* locations =
969 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000970 locations->SetInAt(0, Location::RequiresRegister());
971 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100972}
973
974void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
975 LocationSummary* locations = instruction->GetLocations();
976 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
977 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
978 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
979}
980
981void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100982 LocationSummary* locations =
983 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100984 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
985 locations->SetInAt(i, Location::Any());
986 }
987 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100988}
989
990void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
991 LOG(FATAL) << "Unimplemented";
992}
993
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100994void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100995 LocationSummary* locations =
996 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100997 locations->SetInAt(0, Location::RequiresRegister());
998 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100999 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001000 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001001 locations->AddTemp(Location::RequiresRegister());
1002 locations->AddTemp(Location::RequiresRegister());
1003 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001004}
1005
1006void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1007 LocationSummary* locations = instruction->GetLocations();
1008 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1009 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
1010 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001011 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001012
1013 switch (field_type) {
1014 case Primitive::kPrimBoolean:
1015 case Primitive::kPrimByte: {
1016 __ movb(Address(obj, offset), value);
1017 break;
1018 }
1019
1020 case Primitive::kPrimShort:
1021 case Primitive::kPrimChar: {
1022 __ movw(Address(obj, offset), value);
1023 break;
1024 }
1025
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001026 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001027 case Primitive::kPrimNot: {
1028 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001029 if (field_type == Primitive::kPrimNot) {
1030 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
1031 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1032 codegen_->MarkGCCard(temp, card, obj, value);
1033 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001034 break;
1035 }
1036
1037 case Primitive::kPrimLong: {
1038 __ movq(Address(obj, offset), value);
1039 break;
1040 }
1041
1042 case Primitive::kPrimFloat:
1043 case Primitive::kPrimDouble:
1044 LOG(FATAL) << "Unimplemented register type " << field_type;
1045
1046 case Primitive::kPrimVoid:
1047 LOG(FATAL) << "Unreachable type " << field_type;
1048 }
1049}
1050
1051void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001052 LocationSummary* locations =
1053 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001054 locations->SetInAt(0, Location::RequiresRegister());
1055 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001056}
1057
1058void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1059 LocationSummary* locations = instruction->GetLocations();
1060 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1061 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1062 size_t offset = instruction->GetFieldOffset().SizeValue();
1063
1064 switch (instruction->GetType()) {
1065 case Primitive::kPrimBoolean: {
1066 __ movzxb(out, Address(obj, offset));
1067 break;
1068 }
1069
1070 case Primitive::kPrimByte: {
1071 __ movsxb(out, Address(obj, offset));
1072 break;
1073 }
1074
1075 case Primitive::kPrimShort: {
1076 __ movsxw(out, Address(obj, offset));
1077 break;
1078 }
1079
1080 case Primitive::kPrimChar: {
1081 __ movzxw(out, Address(obj, offset));
1082 break;
1083 }
1084
1085 case Primitive::kPrimInt:
1086 case Primitive::kPrimNot: {
1087 __ movl(out, Address(obj, offset));
1088 break;
1089 }
1090
1091 case Primitive::kPrimLong: {
1092 __ movq(out, Address(obj, offset));
1093 break;
1094 }
1095
1096 case Primitive::kPrimFloat:
1097 case Primitive::kPrimDouble:
1098 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1099
1100 case Primitive::kPrimVoid:
1101 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1102 }
1103}
1104
1105void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001106 LocationSummary* locations =
1107 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001108 locations->SetInAt(0, Location::Any());
1109 // TODO: Have a normalization phase that makes this instruction never used.
1110 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001111}
1112
1113void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001114 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001115 codegen_->AddSlowPath(slow_path);
1116
1117 LocationSummary* locations = instruction->GetLocations();
1118 Location obj = locations->InAt(0);
1119 DCHECK(obj.Equals(locations->Out()));
1120
1121 if (obj.IsRegister()) {
1122 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1123 } else {
1124 DCHECK(locations->InAt(0).IsStackSlot());
1125 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1126 }
1127 __ j(kEqual, slow_path->GetEntryLabel());
1128}
1129
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001130void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001131 LocationSummary* locations =
1132 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001133 locations->SetInAt(0, Location::RequiresRegister());
1134 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1135 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001136}
1137
1138void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1139 LocationSummary* locations = instruction->GetLocations();
1140 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1141 Location index = locations->InAt(1);
1142
1143 switch (instruction->GetType()) {
1144 case Primitive::kPrimBoolean: {
1145 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1146 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1147 if (index.IsConstant()) {
1148 __ movzxb(out, Address(obj,
1149 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1150 } else {
1151 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1152 }
1153 break;
1154 }
1155
1156 case Primitive::kPrimByte: {
1157 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1158 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1159 if (index.IsConstant()) {
1160 __ movsxb(out, Address(obj,
1161 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1162 } else {
1163 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1164 }
1165 break;
1166 }
1167
1168 case Primitive::kPrimShort: {
1169 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1170 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1171 if (index.IsConstant()) {
1172 __ movsxw(out, Address(obj,
1173 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1174 } else {
1175 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1176 }
1177 break;
1178 }
1179
1180 case Primitive::kPrimChar: {
1181 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1182 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1183 if (index.IsConstant()) {
1184 __ movzxw(out, Address(obj,
1185 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1186 } else {
1187 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1188 }
1189 break;
1190 }
1191
1192 case Primitive::kPrimInt:
1193 case Primitive::kPrimNot: {
1194 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1195 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1196 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1197 if (index.IsConstant()) {
1198 __ movl(out, Address(obj,
1199 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1200 } else {
1201 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1202 }
1203 break;
1204 }
1205
1206 case Primitive::kPrimLong: {
1207 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1208 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1209 if (index.IsConstant()) {
1210 __ movq(out, Address(obj,
1211 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1212 } else {
1213 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1214 }
1215 break;
1216 }
1217
1218 case Primitive::kPrimFloat:
1219 case Primitive::kPrimDouble:
1220 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1221
1222 case Primitive::kPrimVoid:
1223 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1224 }
1225}
1226
1227void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001228 Primitive::Type value_type = instruction->GetComponentType();
1229 bool is_object = value_type == Primitive::kPrimNot;
1230 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1231 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1232 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001233 InvokeRuntimeCallingConvention calling_convention;
1234 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1235 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1236 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001237 } else {
1238 locations->SetInAt(0, Location::RequiresRegister());
1239 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1240 locations->SetInAt(2, Location::RequiresRegister());
1241 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001242}
1243
1244void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1245 LocationSummary* locations = instruction->GetLocations();
1246 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1247 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001248 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001249
1250 switch (value_type) {
1251 case Primitive::kPrimBoolean:
1252 case Primitive::kPrimByte: {
1253 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1254 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1255 if (index.IsConstant()) {
1256 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1257 __ movb(Address(obj, offset), value);
1258 } else {
1259 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1260 }
1261 break;
1262 }
1263
1264 case Primitive::kPrimShort:
1265 case Primitive::kPrimChar: {
1266 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1267 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1268 if (index.IsConstant()) {
1269 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1270 __ movw(Address(obj, offset), value);
1271 } else {
1272 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1273 }
1274 break;
1275 }
1276
1277 case Primitive::kPrimInt: {
1278 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1279 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1280 if (index.IsConstant()) {
1281 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1282 __ movl(Address(obj, offset), value);
1283 } else {
1284 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1285 }
1286 break;
1287 }
1288
1289 case Primitive::kPrimNot: {
1290 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1291 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001292 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001293 break;
1294 }
1295
1296 case Primitive::kPrimLong: {
1297 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1298 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1299 if (index.IsConstant()) {
1300 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1301 __ movq(Address(obj, offset), value);
1302 } else {
1303 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1304 }
1305 break;
1306 }
1307
1308 case Primitive::kPrimFloat:
1309 case Primitive::kPrimDouble:
1310 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1311
1312 case Primitive::kPrimVoid:
1313 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1314 }
1315}
1316
1317void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001318 LocationSummary* locations =
1319 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001320 locations->SetInAt(0, Location::RequiresRegister());
1321 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001322}
1323
1324void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1325 LocationSummary* locations = instruction->GetLocations();
1326 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1327 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1328 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1329 __ movl(out, Address(obj, offset));
1330}
1331
1332void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001333 LocationSummary* locations =
1334 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001335 locations->SetInAt(0, Location::RequiresRegister());
1336 locations->SetInAt(1, Location::RequiresRegister());
1337 // TODO: Have a normalization phase that makes this instruction never used.
1338 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001339}
1340
1341void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1342 LocationSummary* locations = instruction->GetLocations();
1343 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001344 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001345 codegen_->AddSlowPath(slow_path);
1346
1347 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1348 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1349
1350 __ cmpl(index, length);
1351 __ j(kAboveEqual, slow_path->GetEntryLabel());
1352}
1353
1354void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1355 CpuRegister card,
1356 CpuRegister object,
1357 CpuRegister value) {
1358 Label is_null;
1359 __ testl(value, value);
1360 __ j(kEqual, &is_null);
1361 __ gs()->movq(card, Address::Absolute(
1362 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1363 __ movq(temp, object);
1364 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1365 __ movb(Address(temp, card, TIMES_1, 0), card);
1366 __ Bind(&is_null);
1367}
1368
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001369void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1370 temp->SetLocations(nullptr);
1371}
1372
1373void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1374 // Nothing to do, this is driven by the code generator.
1375}
1376
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001377void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1378 LOG(FATAL) << "Unimplemented";
1379}
1380
1381void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001382 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1383}
1384
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001385void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1386 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1387}
1388
1389void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1390 SuspendCheckSlowPathX86_64* slow_path =
1391 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction);
1392 codegen_->AddSlowPath(slow_path);
1393 __ gs()->cmpl(Address::Absolute(
1394 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
1395 __ j(kNotEqual, slow_path->GetEntryLabel());
1396 __ Bind(slow_path->GetReturnLabel());
1397}
1398
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001399X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1400 return codegen_->GetAssembler();
1401}
1402
1403void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1404 MoveOperands* move = moves_.Get(index);
1405 Location source = move->GetSource();
1406 Location destination = move->GetDestination();
1407
1408 if (source.IsRegister()) {
1409 if (destination.IsRegister()) {
1410 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001411 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001412 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1413 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001414 } else {
1415 DCHECK(destination.IsDoubleStackSlot());
1416 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1417 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001418 }
1419 } else if (source.IsStackSlot()) {
1420 if (destination.IsRegister()) {
1421 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1422 Address(CpuRegister(RSP), source.GetStackIndex()));
1423 } else {
1424 DCHECK(destination.IsStackSlot());
1425 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1426 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1427 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001428 } else if (source.IsDoubleStackSlot()) {
1429 if (destination.IsRegister()) {
1430 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1431 Address(CpuRegister(RSP), source.GetStackIndex()));
1432 } else {
1433 DCHECK(destination.IsDoubleStackSlot());
1434 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1435 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1436 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001437 } else if (source.IsConstant()) {
1438 HConstant* constant = source.GetConstant();
1439 if (constant->IsIntConstant()) {
1440 Immediate imm(constant->AsIntConstant()->GetValue());
1441 if (destination.IsRegister()) {
1442 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1443 } else {
1444 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1445 }
1446 } else if (constant->IsLongConstant()) {
1447 int64_t value = constant->AsLongConstant()->GetValue();
1448 if (destination.IsRegister()) {
1449 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1450 } else {
1451 __ movq(CpuRegister(TMP), Immediate(value));
1452 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1453 }
1454 } else {
1455 LOG(FATAL) << "Unimplemented constant type";
1456 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001457 } else {
1458 LOG(FATAL) << "Unimplemented";
1459 }
1460}
1461
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001462void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001463 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001464 __ movl(Address(CpuRegister(RSP), mem), reg);
1465 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001466}
1467
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001468void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001469 ScratchRegisterScope ensure_scratch(
1470 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1471
1472 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1473 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1474 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1475 Address(CpuRegister(RSP), mem2 + stack_offset));
1476 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1477 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1478 CpuRegister(ensure_scratch.GetRegister()));
1479}
1480
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001481void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1482 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1483 __ movq(Address(CpuRegister(RSP), mem), reg);
1484 __ movq(reg, CpuRegister(TMP));
1485}
1486
1487void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1488 ScratchRegisterScope ensure_scratch(
1489 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1490
1491 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1492 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1493 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1494 Address(CpuRegister(RSP), mem2 + stack_offset));
1495 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1496 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1497 CpuRegister(ensure_scratch.GetRegister()));
1498}
1499
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001500void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1501 MoveOperands* move = moves_.Get(index);
1502 Location source = move->GetSource();
1503 Location destination = move->GetDestination();
1504
1505 if (source.IsRegister() && destination.IsRegister()) {
1506 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1507 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001508 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001509 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001510 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001511 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001512 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1513 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1514 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1515 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1516 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1517 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1518 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001519 } else {
1520 LOG(FATAL) << "Unimplemented";
1521 }
1522}
1523
1524
1525void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1526 __ pushq(CpuRegister(reg));
1527}
1528
1529
1530void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1531 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001532}
1533
1534} // namespace x86_64
1535} // namespace art