blob: 065f9813fdef8d0a49f861fe602fd6d38a1f94ba [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());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100106 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000107 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
108 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100109 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000110 __ jmp(GetReturnLabel());
111 }
112
113 Label* GetReturnLabel() { return &return_label_; }
114
115 private:
116 HSuspendCheck* const instruction_;
117 Label return_label_;
118
119 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
120};
121
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100122class BoundsCheckSlowPathX86_64 : public SlowPathCode {
123 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100124 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100125 Location index_location,
126 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100127 : instruction_(instruction),
128 index_location_(index_location),
129 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100130
131 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
132 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
133 __ Bind(GetEntryLabel());
134 InvokeRuntimeCallingConvention calling_convention;
135 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
136 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
137 __ gs()->call(Address::Absolute(
138 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100139 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140 }
141
142 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100143 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100144 const Location index_location_;
145 const Location length_location_;
146
147 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
148};
149
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100150#undef __
151#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
152
Dave Allison20dfc792014-06-16 20:44:29 -0700153inline Condition X86_64Condition(IfCondition cond) {
154 switch (cond) {
155 case kCondEQ: return kEqual;
156 case kCondNE: return kNotEqual;
157 case kCondLT: return kLess;
158 case kCondLE: return kLessEqual;
159 case kCondGT: return kGreater;
160 case kCondGE: return kGreaterEqual;
161 default:
162 LOG(FATAL) << "Unknown if condition";
163 }
164 return kEqual;
165}
166
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100167void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
168 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
169}
170
171void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
172 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
173}
174
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100175void CodeGeneratorX86_64::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
176 __ movq(Address(CpuRegister(RSP), stack_location.GetStackIndex()), CpuRegister(reg_id));
177}
178
179void CodeGeneratorX86_64::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
180 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_location.GetStackIndex()));
181}
182
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100183CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
184 : CodeGenerator(graph, kNumberOfRegIds),
185 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000186 instruction_visitor_(graph, this),
187 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100188
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100189size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
190 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
191}
192
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100193InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
194 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100195 : HGraphVisitor(graph),
196 assembler_(codegen->GetAssembler()),
197 codegen_(codegen) {}
198
199ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
200 bool* blocked_registers) const {
201 switch (type) {
202 case Primitive::kPrimLong:
203 case Primitive::kPrimByte:
204 case Primitive::kPrimBoolean:
205 case Primitive::kPrimChar:
206 case Primitive::kPrimShort:
207 case Primitive::kPrimInt:
208 case Primitive::kPrimNot: {
209 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
210 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
211 }
212
213 case Primitive::kPrimFloat:
214 case Primitive::kPrimDouble:
215 LOG(FATAL) << "Unimplemented register type " << type;
216
217 case Primitive::kPrimVoid:
218 LOG(FATAL) << "Unreachable type " << type;
219 }
220
221 return ManagedRegister::NoRegister();
222}
223
224void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
225 // Stack register is always reserved.
226 blocked_registers[RSP] = true;
227
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000228 // Block the register used as TMP.
229 blocked_registers[TMP] = true;
230
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100231 // TODO: We currently don't use Quick's callee saved registers.
232 blocked_registers[RBX] = true;
233 blocked_registers[RBP] = true;
234 blocked_registers[R12] = true;
235 blocked_registers[R13] = true;
236 blocked_registers[R14] = true;
237 blocked_registers[R15] = true;
238}
239
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100240void CodeGeneratorX86_64::GenerateFrameEntry() {
241 // Create a fake register to mimic Quick.
242 static const int kFakeReturnRegister = 16;
243 core_spill_mask_ |= (1 << kFakeReturnRegister);
244
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100245 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700246 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100247
248 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
249 __ testq(CpuRegister(RAX), Address(
250 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100251 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100252 }
253
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100254 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100255 __ subq(CpuRegister(RSP),
256 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
257
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100258 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
259 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
260 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100261
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100262 __ gs()->cmpq(CpuRegister(RSP),
263 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
264 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100265 }
266
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100267 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
268}
269
270void CodeGeneratorX86_64::GenerateFrameExit() {
271 __ addq(CpuRegister(RSP),
272 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
273}
274
275void CodeGeneratorX86_64::Bind(Label* label) {
276 __ Bind(label);
277}
278
279void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
280 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
281}
282
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100283Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
284 switch (load->GetType()) {
285 case Primitive::kPrimLong:
286 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
287 break;
288
289 case Primitive::kPrimInt:
290 case Primitive::kPrimNot:
291 return Location::StackSlot(GetStackSlot(load->GetLocal()));
292
293 case Primitive::kPrimFloat:
294 case Primitive::kPrimDouble:
295 LOG(FATAL) << "Unimplemented type " << load->GetType();
296
297 case Primitive::kPrimBoolean:
298 case Primitive::kPrimByte:
299 case Primitive::kPrimChar:
300 case Primitive::kPrimShort:
301 case Primitive::kPrimVoid:
302 LOG(FATAL) << "Unexpected type " << load->GetType();
303 }
304
305 LOG(FATAL) << "Unreachable";
306 return Location();
307}
308
309void CodeGeneratorX86_64::Move(Location destination, Location source) {
310 if (source.Equals(destination)) {
311 return;
312 }
313 if (destination.IsRegister()) {
314 if (source.IsRegister()) {
315 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
316 } else if (source.IsStackSlot()) {
317 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
318 } else {
319 DCHECK(source.IsDoubleStackSlot());
320 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
321 }
322 } else if (destination.IsStackSlot()) {
323 if (source.IsRegister()) {
324 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
325 } else {
326 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000327 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
328 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100329 }
330 } else {
331 DCHECK(destination.IsDoubleStackSlot());
332 if (source.IsRegister()) {
333 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
334 } else {
335 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000336 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
337 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100338 }
339 }
340}
341
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100342void CodeGeneratorX86_64::Move(HInstruction* instruction,
343 Location location,
344 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100345 if (instruction->AsIntConstant() != nullptr) {
346 Immediate imm(instruction->AsIntConstant()->GetValue());
347 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000348 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100349 } else {
350 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
351 }
352 } else if (instruction->AsLongConstant() != nullptr) {
353 int64_t value = instruction->AsLongConstant()->GetValue();
354 if (location.IsRegister()) {
355 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
356 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000357 __ movq(CpuRegister(TMP), Immediate(value));
358 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100359 }
360 } else if (instruction->AsLoadLocal() != nullptr) {
361 switch (instruction->GetType()) {
362 case Primitive::kPrimBoolean:
363 case Primitive::kPrimByte:
364 case Primitive::kPrimChar:
365 case Primitive::kPrimShort:
366 case Primitive::kPrimInt:
367 case Primitive::kPrimNot:
368 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
369 break;
370
371 case Primitive::kPrimLong:
372 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
373 break;
374
375 default:
376 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
377 }
378 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100379 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100380 switch (instruction->GetType()) {
381 case Primitive::kPrimBoolean:
382 case Primitive::kPrimByte:
383 case Primitive::kPrimChar:
384 case Primitive::kPrimShort:
385 case Primitive::kPrimInt:
386 case Primitive::kPrimNot:
387 case Primitive::kPrimLong:
388 Move(location, instruction->GetLocations()->Out());
389 break;
390
391 default:
392 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
393 }
394 }
395}
396
397void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
398 got->SetLocations(nullptr);
399}
400
401void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
402 HBasicBlock* successor = got->GetSuccessor();
403 if (GetGraph()->GetExitBlock() == successor) {
404 codegen_->GenerateFrameExit();
405 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
406 __ jmp(codegen_->GetLabelOf(successor));
407 }
408}
409
410void LocationsBuilderX86_64::VisitExit(HExit* exit) {
411 exit->SetLocations(nullptr);
412}
413
414void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
415 if (kIsDebugBuild) {
416 __ Comment("Unreachable");
417 __ int3();
418 }
419}
420
421void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100422 LocationSummary* locations =
423 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100424 HInstruction* cond = if_instr->InputAt(0);
425 DCHECK(cond->IsCondition());
426 HCondition* condition = cond->AsCondition();
427 if (condition->NeedsMaterialization()) {
428 locations->SetInAt(0, Location::Any());
429 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100430}
431
432void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700433 HInstruction* cond = if_instr->InputAt(0);
434 DCHECK(cond->IsCondition());
435 HCondition* condition = cond->AsCondition();
436 if (condition->NeedsMaterialization()) {
437 // Materialized condition, compare against 0.
438 Location lhs = if_instr->GetLocations()->InAt(0);
439 if (lhs.IsRegister()) {
440 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
441 } else {
442 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
443 }
444 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
445 } else {
446 Location lhs = condition->GetLocations()->InAt(0);
447 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100448 if (rhs.IsRegister()) {
449 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
450 } else if (rhs.IsConstant()) {
451 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
452 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
453 } else {
454 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
455 }
Dave Allison20dfc792014-06-16 20:44:29 -0700456 __ j(X86_64Condition(condition->GetCondition()),
457 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
458 }
459 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
460 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100461 }
462}
463
464void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
465 local->SetLocations(nullptr);
466}
467
468void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
469 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
470}
471
472void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
473 local->SetLocations(nullptr);
474}
475
476void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
477 // Nothing to do, this is driven by the code generator.
478}
479
480void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100481 LocationSummary* locations =
482 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100483 switch (store->InputAt(1)->GetType()) {
484 case Primitive::kPrimBoolean:
485 case Primitive::kPrimByte:
486 case Primitive::kPrimChar:
487 case Primitive::kPrimShort:
488 case Primitive::kPrimInt:
489 case Primitive::kPrimNot:
490 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
491 break;
492
493 case Primitive::kPrimLong:
494 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
495 break;
496
497 default:
498 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
499 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100500}
501
502void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
503}
504
Dave Allison20dfc792014-06-16 20:44:29 -0700505void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100506 LocationSummary* locations =
507 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000508 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100509 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100510 if (comp->NeedsMaterialization()) {
511 locations->SetOut(Location::RequiresRegister());
512 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100513}
514
Dave Allison20dfc792014-06-16 20:44:29 -0700515void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
516 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100517 LocationSummary* locations = comp->GetLocations();
518 if (locations->InAt(1).IsRegister()) {
519 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
520 locations->InAt(1).AsX86_64().AsCpuRegister());
521 } else if (locations->InAt(1).IsConstant()) {
522 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
523 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
524 } else {
525 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
526 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
527 }
Dave Allison20dfc792014-06-16 20:44:29 -0700528 __ setcc(X86_64Condition(comp->GetCondition()),
529 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
530 }
531}
532
533void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
534 VisitCondition(comp);
535}
536
537void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
538 VisitCondition(comp);
539}
540
541void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
542 VisitCondition(comp);
543}
544
545void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
546 VisitCondition(comp);
547}
548
549void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
550 VisitCondition(comp);
551}
552
553void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
554 VisitCondition(comp);
555}
556
557void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
558 VisitCondition(comp);
559}
560
561void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
562 VisitCondition(comp);
563}
564
565void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
566 VisitCondition(comp);
567}
568
569void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
570 VisitCondition(comp);
571}
572
573void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
574 VisitCondition(comp);
575}
576
577void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
578 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100579}
580
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100581void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100582 LocationSummary* locations =
583 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100584 locations->SetInAt(0, Location::RequiresRegister());
585 locations->SetInAt(1, Location::RequiresRegister());
586 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100587}
588
589void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
590 Label greater, done;
591 LocationSummary* locations = compare->GetLocations();
592 switch (compare->InputAt(0)->GetType()) {
593 case Primitive::kPrimLong:
594 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
595 locations->InAt(1).AsX86_64().AsCpuRegister());
596 break;
597 default:
598 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
599 }
600
601 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
602 __ j(kEqual, &done);
603 __ j(kGreater, &greater);
604
605 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
606 __ jmp(&done);
607
608 __ Bind(&greater);
609 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
610
611 __ Bind(&done);
612}
613
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100614void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100615 LocationSummary* locations =
616 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100617 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100618}
619
620void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100621}
622
623void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100624 LocationSummary* locations =
625 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100626 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100627}
628
629void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100630}
631
632void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
633 ret->SetLocations(nullptr);
634}
635
636void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
637 codegen_->GenerateFrameExit();
638 __ ret();
639}
640
641void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100642 LocationSummary* locations =
643 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100644 switch (ret->InputAt(0)->GetType()) {
645 case Primitive::kPrimBoolean:
646 case Primitive::kPrimByte:
647 case Primitive::kPrimChar:
648 case Primitive::kPrimShort:
649 case Primitive::kPrimInt:
650 case Primitive::kPrimNot:
651 case Primitive::kPrimLong:
652 locations->SetInAt(0, X86_64CpuLocation(RAX));
653 break;
654
655 default:
656 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
657 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100658}
659
660void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
661 if (kIsDebugBuild) {
662 switch (ret->InputAt(0)->GetType()) {
663 case Primitive::kPrimBoolean:
664 case Primitive::kPrimByte:
665 case Primitive::kPrimChar:
666 case Primitive::kPrimShort:
667 case Primitive::kPrimInt:
668 case Primitive::kPrimNot:
669 case Primitive::kPrimLong:
670 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
671 break;
672
673 default:
674 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
675 }
676 }
677 codegen_->GenerateFrameExit();
678 __ ret();
679}
680
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100681Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
682 switch (type) {
683 case Primitive::kPrimBoolean:
684 case Primitive::kPrimByte:
685 case Primitive::kPrimChar:
686 case Primitive::kPrimShort:
687 case Primitive::kPrimInt:
688 case Primitive::kPrimNot: {
689 uint32_t index = gp_index_++;
690 stack_index_++;
691 if (index < calling_convention.GetNumberOfRegisters()) {
692 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
693 } else {
694 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
695 }
696 }
697
698 case Primitive::kPrimLong: {
699 uint32_t index = gp_index_;
700 stack_index_ += 2;
701 if (index < calling_convention.GetNumberOfRegisters()) {
702 gp_index_ += 1;
703 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
704 } else {
705 gp_index_ += 2;
706 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
707 }
708 }
709
710 case Primitive::kPrimDouble:
711 case Primitive::kPrimFloat:
712 LOG(FATAL) << "Unimplemented parameter type " << type;
713 break;
714
715 case Primitive::kPrimVoid:
716 LOG(FATAL) << "Unexpected parameter type " << type;
717 break;
718 }
719 return Location();
720}
721
722void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100723 HandleInvoke(invoke);
724}
725
726void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
727 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
728 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
729 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
730 invoke->GetIndexInDexCache() * heap_reference_size;
731
732 // TODO: Implement all kinds of calls:
733 // 1) boot -> boot
734 // 2) app -> boot
735 // 3) app -> app
736 //
737 // Currently we implement the app -> app logic, which looks up in the resolve cache.
738
739 // temp = method;
740 LoadCurrentMethod(temp);
741 // temp = temp->dex_cache_resolved_methods_;
742 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
743 // temp = temp[index_in_cache]
744 __ movl(temp, Address(temp, index_in_cache));
745 // (temp + offset_of_quick_compiled_code)()
746 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
747
748 DCHECK(!codegen_->IsLeafMethod());
749 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
750}
751
752void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
753 HandleInvoke(invoke);
754}
755
756void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100757 LocationSummary* locations =
758 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100759 locations->AddTemp(X86_64CpuLocation(RDI));
760
761 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100762 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100763 HInstruction* input = invoke->InputAt(i);
764 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
765 }
766
767 switch (invoke->GetType()) {
768 case Primitive::kPrimBoolean:
769 case Primitive::kPrimByte:
770 case Primitive::kPrimChar:
771 case Primitive::kPrimShort:
772 case Primitive::kPrimInt:
773 case Primitive::kPrimNot:
774 case Primitive::kPrimLong:
775 locations->SetOut(X86_64CpuLocation(RAX));
776 break;
777
778 case Primitive::kPrimVoid:
779 break;
780
781 case Primitive::kPrimDouble:
782 case Primitive::kPrimFloat:
783 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
784 break;
785 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100786}
787
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100788void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100789 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100790 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
791 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
792 LocationSummary* locations = invoke->GetLocations();
793 Location receiver = locations->InAt(0);
794 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
795 // temp = object->GetClass();
796 if (receiver.IsStackSlot()) {
797 __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
798 __ movq(temp, Address(temp, class_offset));
799 } else {
800 __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
801 }
802 // temp = temp->GetMethodAt(method_offset);
803 __ movl(temp, Address(temp, method_offset));
804 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100805 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
806
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100807 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100808 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100809}
810
811void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100812 LocationSummary* locations =
813 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100814 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100815 case Primitive::kPrimInt: {
816 locations->SetInAt(0, Location::RequiresRegister());
817 locations->SetInAt(1, Location::Any());
818 locations->SetOut(Location::SameAsFirstInput());
819 break;
820 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100821 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000822 locations->SetInAt(0, Location::RequiresRegister());
823 locations->SetInAt(1, Location::RequiresRegister());
824 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100825 break;
826 }
827
828 case Primitive::kPrimBoolean:
829 case Primitive::kPrimByte:
830 case Primitive::kPrimChar:
831 case Primitive::kPrimShort:
832 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
833 break;
834
835 default:
836 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
837 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100838}
839
840void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
841 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000842 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
843 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100844 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000845 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100846 if (locations->InAt(1).IsRegister()) {
847 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
848 locations->InAt(1).AsX86_64().AsCpuRegister());
849 } else if (locations->InAt(1).IsConstant()) {
850 HConstant* instruction = locations->InAt(1).GetConstant();
851 Immediate imm(instruction->AsIntConstant()->GetValue());
852 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
853 } else {
854 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
855 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
856 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000857 break;
858 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100859 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100860 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
861 locations->InAt(1).AsX86_64().AsCpuRegister());
862 break;
863 }
864
865 case Primitive::kPrimBoolean:
866 case Primitive::kPrimByte:
867 case Primitive::kPrimChar:
868 case Primitive::kPrimShort:
869 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
870 break;
871
872 default:
873 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
874 }
875}
876
877void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100878 LocationSummary* locations =
879 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100880 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100881 case Primitive::kPrimInt: {
882 locations->SetInAt(0, Location::RequiresRegister());
883 locations->SetInAt(1, Location::Any());
884 locations->SetOut(Location::SameAsFirstInput());
885 break;
886 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000888 locations->SetInAt(0, Location::RequiresRegister());
889 locations->SetInAt(1, Location::RequiresRegister());
890 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100891 break;
892 }
893
894 case Primitive::kPrimBoolean:
895 case Primitive::kPrimByte:
896 case Primitive::kPrimChar:
897 case Primitive::kPrimShort:
898 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
899 break;
900
901 default:
902 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
903 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100904}
905
906void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
907 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000908 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
909 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100910 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000911 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100912 if (locations->InAt(1).IsRegister()) {
913 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
914 locations->InAt(1).AsX86_64().AsCpuRegister());
915 } else if (locations->InAt(1).IsConstant()) {
916 HConstant* instruction = locations->InAt(1).GetConstant();
917 Immediate imm(instruction->AsIntConstant()->GetValue());
918 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
919 } else {
920 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
921 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
922 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000923 break;
924 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100925 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100926 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
927 locations->InAt(1).AsX86_64().AsCpuRegister());
928 break;
929 }
930
931 case Primitive::kPrimBoolean:
932 case Primitive::kPrimByte:
933 case Primitive::kPrimChar:
934 case Primitive::kPrimShort:
935 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
936 break;
937
938 default:
939 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
940 }
941}
942
943void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100944 LocationSummary* locations =
945 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100946 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100947}
948
949void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
950 InvokeRuntimeCallingConvention calling_convention;
951 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
952 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
953
954 __ gs()->call(Address::Absolute(
955 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
956
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100957 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100959}
960
961void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100962 LocationSummary* locations =
963 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100964 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
965 if (location.IsStackSlot()) {
966 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
967 } else if (location.IsDoubleStackSlot()) {
968 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
969 }
970 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100971}
972
973void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
974 // Nothing to do, the parameter is already at its location.
975}
976
977void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100978 LocationSummary* locations =
979 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000980 locations->SetInAt(0, Location::RequiresRegister());
981 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100982}
983
984void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
985 LocationSummary* locations = instruction->GetLocations();
986 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
987 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
988 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
989}
990
991void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100992 LocationSummary* locations =
993 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100994 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
995 locations->SetInAt(i, Location::Any());
996 }
997 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100998}
999
1000void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
1001 LOG(FATAL) << "Unimplemented";
1002}
1003
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001004void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001005 LocationSummary* locations =
1006 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001007 locations->SetInAt(0, Location::RequiresRegister());
1008 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001009 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001010 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001011 locations->AddTemp(Location::RequiresRegister());
1012 locations->AddTemp(Location::RequiresRegister());
1013 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001014}
1015
1016void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1017 LocationSummary* locations = instruction->GetLocations();
1018 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1019 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
1020 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001021 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001022
1023 switch (field_type) {
1024 case Primitive::kPrimBoolean:
1025 case Primitive::kPrimByte: {
1026 __ movb(Address(obj, offset), value);
1027 break;
1028 }
1029
1030 case Primitive::kPrimShort:
1031 case Primitive::kPrimChar: {
1032 __ movw(Address(obj, offset), value);
1033 break;
1034 }
1035
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001036 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001037 case Primitive::kPrimNot: {
1038 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001039 if (field_type == Primitive::kPrimNot) {
1040 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
1041 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1042 codegen_->MarkGCCard(temp, card, obj, value);
1043 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001044 break;
1045 }
1046
1047 case Primitive::kPrimLong: {
1048 __ movq(Address(obj, offset), value);
1049 break;
1050 }
1051
1052 case Primitive::kPrimFloat:
1053 case Primitive::kPrimDouble:
1054 LOG(FATAL) << "Unimplemented register type " << field_type;
1055
1056 case Primitive::kPrimVoid:
1057 LOG(FATAL) << "Unreachable type " << field_type;
1058 }
1059}
1060
1061void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001062 LocationSummary* locations =
1063 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001064 locations->SetInAt(0, Location::RequiresRegister());
1065 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001066}
1067
1068void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1069 LocationSummary* locations = instruction->GetLocations();
1070 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1071 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1072 size_t offset = instruction->GetFieldOffset().SizeValue();
1073
1074 switch (instruction->GetType()) {
1075 case Primitive::kPrimBoolean: {
1076 __ movzxb(out, Address(obj, offset));
1077 break;
1078 }
1079
1080 case Primitive::kPrimByte: {
1081 __ movsxb(out, Address(obj, offset));
1082 break;
1083 }
1084
1085 case Primitive::kPrimShort: {
1086 __ movsxw(out, Address(obj, offset));
1087 break;
1088 }
1089
1090 case Primitive::kPrimChar: {
1091 __ movzxw(out, Address(obj, offset));
1092 break;
1093 }
1094
1095 case Primitive::kPrimInt:
1096 case Primitive::kPrimNot: {
1097 __ movl(out, Address(obj, offset));
1098 break;
1099 }
1100
1101 case Primitive::kPrimLong: {
1102 __ movq(out, Address(obj, offset));
1103 break;
1104 }
1105
1106 case Primitive::kPrimFloat:
1107 case Primitive::kPrimDouble:
1108 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1109
1110 case Primitive::kPrimVoid:
1111 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1112 }
1113}
1114
1115void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001116 LocationSummary* locations =
1117 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001118 locations->SetInAt(0, Location::Any());
1119 // TODO: Have a normalization phase that makes this instruction never used.
1120 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001121}
1122
1123void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001124 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001125 codegen_->AddSlowPath(slow_path);
1126
1127 LocationSummary* locations = instruction->GetLocations();
1128 Location obj = locations->InAt(0);
1129 DCHECK(obj.Equals(locations->Out()));
1130
1131 if (obj.IsRegister()) {
1132 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1133 } else {
1134 DCHECK(locations->InAt(0).IsStackSlot());
1135 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1136 }
1137 __ j(kEqual, slow_path->GetEntryLabel());
1138}
1139
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001140void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001141 LocationSummary* locations =
1142 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001143 locations->SetInAt(0, Location::RequiresRegister());
1144 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1145 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001146}
1147
1148void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1149 LocationSummary* locations = instruction->GetLocations();
1150 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1151 Location index = locations->InAt(1);
1152
1153 switch (instruction->GetType()) {
1154 case Primitive::kPrimBoolean: {
1155 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1156 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1157 if (index.IsConstant()) {
1158 __ movzxb(out, Address(obj,
1159 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1160 } else {
1161 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1162 }
1163 break;
1164 }
1165
1166 case Primitive::kPrimByte: {
1167 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1168 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1169 if (index.IsConstant()) {
1170 __ movsxb(out, Address(obj,
1171 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1172 } else {
1173 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1174 }
1175 break;
1176 }
1177
1178 case Primitive::kPrimShort: {
1179 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1180 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1181 if (index.IsConstant()) {
1182 __ movsxw(out, Address(obj,
1183 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1184 } else {
1185 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1186 }
1187 break;
1188 }
1189
1190 case Primitive::kPrimChar: {
1191 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1192 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1193 if (index.IsConstant()) {
1194 __ movzxw(out, Address(obj,
1195 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1196 } else {
1197 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1198 }
1199 break;
1200 }
1201
1202 case Primitive::kPrimInt:
1203 case Primitive::kPrimNot: {
1204 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1205 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1206 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1207 if (index.IsConstant()) {
1208 __ movl(out, Address(obj,
1209 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1210 } else {
1211 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1212 }
1213 break;
1214 }
1215
1216 case Primitive::kPrimLong: {
1217 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1218 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1219 if (index.IsConstant()) {
1220 __ movq(out, Address(obj,
1221 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1222 } else {
1223 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1224 }
1225 break;
1226 }
1227
1228 case Primitive::kPrimFloat:
1229 case Primitive::kPrimDouble:
1230 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1231
1232 case Primitive::kPrimVoid:
1233 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1234 }
1235}
1236
1237void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001238 Primitive::Type value_type = instruction->GetComponentType();
1239 bool is_object = value_type == Primitive::kPrimNot;
1240 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1241 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1242 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001243 InvokeRuntimeCallingConvention calling_convention;
1244 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1245 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1246 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001247 } else {
1248 locations->SetInAt(0, Location::RequiresRegister());
1249 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1250 locations->SetInAt(2, Location::RequiresRegister());
1251 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001252}
1253
1254void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1255 LocationSummary* locations = instruction->GetLocations();
1256 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1257 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001258 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001259
1260 switch (value_type) {
1261 case Primitive::kPrimBoolean:
1262 case Primitive::kPrimByte: {
1263 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1264 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1265 if (index.IsConstant()) {
1266 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1267 __ movb(Address(obj, offset), value);
1268 } else {
1269 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1270 }
1271 break;
1272 }
1273
1274 case Primitive::kPrimShort:
1275 case Primitive::kPrimChar: {
1276 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1277 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1278 if (index.IsConstant()) {
1279 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1280 __ movw(Address(obj, offset), value);
1281 } else {
1282 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1283 }
1284 break;
1285 }
1286
1287 case Primitive::kPrimInt: {
1288 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1289 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1290 if (index.IsConstant()) {
1291 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1292 __ movl(Address(obj, offset), value);
1293 } else {
1294 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1295 }
1296 break;
1297 }
1298
1299 case Primitive::kPrimNot: {
1300 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1301 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001302 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001303 break;
1304 }
1305
1306 case Primitive::kPrimLong: {
1307 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1308 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1309 if (index.IsConstant()) {
1310 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1311 __ movq(Address(obj, offset), value);
1312 } else {
1313 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1314 }
1315 break;
1316 }
1317
1318 case Primitive::kPrimFloat:
1319 case Primitive::kPrimDouble:
1320 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1321
1322 case Primitive::kPrimVoid:
1323 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1324 }
1325}
1326
1327void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001328 LocationSummary* locations =
1329 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001330 locations->SetInAt(0, Location::RequiresRegister());
1331 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001332}
1333
1334void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1335 LocationSummary* locations = instruction->GetLocations();
1336 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1337 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1338 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1339 __ movl(out, Address(obj, offset));
1340}
1341
1342void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001343 LocationSummary* locations =
1344 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001345 locations->SetInAt(0, Location::RequiresRegister());
1346 locations->SetInAt(1, Location::RequiresRegister());
1347 // TODO: Have a normalization phase that makes this instruction never used.
1348 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001349}
1350
1351void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1352 LocationSummary* locations = instruction->GetLocations();
1353 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001354 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001355 codegen_->AddSlowPath(slow_path);
1356
1357 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1358 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1359
1360 __ cmpl(index, length);
1361 __ j(kAboveEqual, slow_path->GetEntryLabel());
1362}
1363
1364void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1365 CpuRegister card,
1366 CpuRegister object,
1367 CpuRegister value) {
1368 Label is_null;
1369 __ testl(value, value);
1370 __ j(kEqual, &is_null);
1371 __ gs()->movq(card, Address::Absolute(
1372 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1373 __ movq(temp, object);
1374 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1375 __ movb(Address(temp, card, TIMES_1, 0), card);
1376 __ Bind(&is_null);
1377}
1378
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001379void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1380 temp->SetLocations(nullptr);
1381}
1382
1383void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1384 // Nothing to do, this is driven by the code generator.
1385}
1386
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001387void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1388 LOG(FATAL) << "Unimplemented";
1389}
1390
1391void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001392 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1393}
1394
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001395void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1396 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1397}
1398
1399void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1400 SuspendCheckSlowPathX86_64* slow_path =
1401 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction);
1402 codegen_->AddSlowPath(slow_path);
1403 __ gs()->cmpl(Address::Absolute(
1404 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
1405 __ j(kNotEqual, slow_path->GetEntryLabel());
1406 __ Bind(slow_path->GetReturnLabel());
1407}
1408
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001409X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1410 return codegen_->GetAssembler();
1411}
1412
1413void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1414 MoveOperands* move = moves_.Get(index);
1415 Location source = move->GetSource();
1416 Location destination = move->GetDestination();
1417
1418 if (source.IsRegister()) {
1419 if (destination.IsRegister()) {
1420 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001421 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001422 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1423 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001424 } else {
1425 DCHECK(destination.IsDoubleStackSlot());
1426 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1427 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001428 }
1429 } else if (source.IsStackSlot()) {
1430 if (destination.IsRegister()) {
1431 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1432 Address(CpuRegister(RSP), source.GetStackIndex()));
1433 } else {
1434 DCHECK(destination.IsStackSlot());
1435 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1436 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1437 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001438 } else if (source.IsDoubleStackSlot()) {
1439 if (destination.IsRegister()) {
1440 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1441 Address(CpuRegister(RSP), source.GetStackIndex()));
1442 } else {
1443 DCHECK(destination.IsDoubleStackSlot());
1444 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1445 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1446 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001447 } else if (source.IsConstant()) {
1448 HConstant* constant = source.GetConstant();
1449 if (constant->IsIntConstant()) {
1450 Immediate imm(constant->AsIntConstant()->GetValue());
1451 if (destination.IsRegister()) {
1452 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1453 } else {
1454 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1455 }
1456 } else if (constant->IsLongConstant()) {
1457 int64_t value = constant->AsLongConstant()->GetValue();
1458 if (destination.IsRegister()) {
1459 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1460 } else {
1461 __ movq(CpuRegister(TMP), Immediate(value));
1462 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1463 }
1464 } else {
1465 LOG(FATAL) << "Unimplemented constant type";
1466 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001467 } else {
1468 LOG(FATAL) << "Unimplemented";
1469 }
1470}
1471
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001472void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001473 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001474 __ movl(Address(CpuRegister(RSP), mem), reg);
1475 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001476}
1477
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001478void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001479 ScratchRegisterScope ensure_scratch(
1480 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1481
1482 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1483 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1484 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1485 Address(CpuRegister(RSP), mem2 + stack_offset));
1486 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1487 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1488 CpuRegister(ensure_scratch.GetRegister()));
1489}
1490
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001491void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1492 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1493 __ movq(Address(CpuRegister(RSP), mem), reg);
1494 __ movq(reg, CpuRegister(TMP));
1495}
1496
1497void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1498 ScratchRegisterScope ensure_scratch(
1499 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1500
1501 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1502 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1503 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1504 Address(CpuRegister(RSP), mem2 + stack_offset));
1505 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1506 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1507 CpuRegister(ensure_scratch.GetRegister()));
1508}
1509
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001510void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1511 MoveOperands* move = moves_.Get(index);
1512 Location source = move->GetSource();
1513 Location destination = move->GetDestination();
1514
1515 if (source.IsRegister() && destination.IsRegister()) {
1516 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1517 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001518 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001519 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001520 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001521 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001522 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1523 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1524 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1525 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1526 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1527 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1528 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001529 } else {
1530 LOG(FATAL) << "Unimplemented";
1531 }
1532}
1533
1534
1535void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1536 __ pushq(CpuRegister(reg));
1537}
1538
1539
1540void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1541 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001542}
1543
1544} // namespace x86_64
1545} // namespace art