blob: 283d850ef0558de629ac202eeb276ddcef4c0cbe [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()) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100427 // Moves do not affect the eflags register, so if the condition is evaluated
428 // just before the if, we don't need to evaluate it again.
429 if (!condition->IsBeforeWhenDisregardMoves(if_instr)) {
430 // Materialized condition, compare against 0.
431 Location lhs = if_instr->GetLocations()->InAt(0);
432 if (lhs.IsRegister()) {
433 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
434 } else {
435 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
436 }
Dave Allison20dfc792014-06-16 20:44:29 -0700437 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100438 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700439 } else {
440 Location lhs = condition->GetLocations()->InAt(0);
441 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100442 if (rhs.IsRegister()) {
443 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
444 } else if (rhs.IsConstant()) {
445 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
446 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
447 } else {
448 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
449 }
Dave Allison20dfc792014-06-16 20:44:29 -0700450 __ j(X86_64Condition(condition->GetCondition()),
451 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
452 }
453 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
454 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100455 }
456}
457
458void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
459 local->SetLocations(nullptr);
460}
461
462void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
463 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
464}
465
466void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
467 local->SetLocations(nullptr);
468}
469
470void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
471 // Nothing to do, this is driven by the code generator.
472}
473
474void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100475 LocationSummary* locations =
476 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100477 switch (store->InputAt(1)->GetType()) {
478 case Primitive::kPrimBoolean:
479 case Primitive::kPrimByte:
480 case Primitive::kPrimChar:
481 case Primitive::kPrimShort:
482 case Primitive::kPrimInt:
483 case Primitive::kPrimNot:
484 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
485 break;
486
487 case Primitive::kPrimLong:
488 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
489 break;
490
491 default:
492 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
493 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100494}
495
496void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
497}
498
Dave Allison20dfc792014-06-16 20:44:29 -0700499void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100500 LocationSummary* locations =
501 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000502 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100503 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100504 if (comp->NeedsMaterialization()) {
505 locations->SetOut(Location::RequiresRegister());
506 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100507}
508
Dave Allison20dfc792014-06-16 20:44:29 -0700509void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
510 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100511 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100512 CpuRegister reg = locations->Out().AsX86_64().AsCpuRegister();
513 // Clear register: setcc only sets the low byte.
514 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100515 if (locations->InAt(1).IsRegister()) {
516 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
517 locations->InAt(1).AsX86_64().AsCpuRegister());
518 } else if (locations->InAt(1).IsConstant()) {
519 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
520 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
521 } else {
522 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
523 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
524 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100525 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700526 }
527}
528
529void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
530 VisitCondition(comp);
531}
532
533void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
534 VisitCondition(comp);
535}
536
537void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
538 VisitCondition(comp);
539}
540
541void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
542 VisitCondition(comp);
543}
544
545void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
546 VisitCondition(comp);
547}
548
549void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
550 VisitCondition(comp);
551}
552
553void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
554 VisitCondition(comp);
555}
556
557void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
558 VisitCondition(comp);
559}
560
561void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
562 VisitCondition(comp);
563}
564
565void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
566 VisitCondition(comp);
567}
568
569void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
570 VisitCondition(comp);
571}
572
573void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
574 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100575}
576
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100577void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100578 LocationSummary* locations =
579 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100580 locations->SetInAt(0, Location::RequiresRegister());
581 locations->SetInAt(1, Location::RequiresRegister());
582 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100583}
584
585void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
586 Label greater, done;
587 LocationSummary* locations = compare->GetLocations();
588 switch (compare->InputAt(0)->GetType()) {
589 case Primitive::kPrimLong:
590 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
591 locations->InAt(1).AsX86_64().AsCpuRegister());
592 break;
593 default:
594 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
595 }
596
597 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
598 __ j(kEqual, &done);
599 __ j(kGreater, &greater);
600
601 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
602 __ jmp(&done);
603
604 __ Bind(&greater);
605 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
606
607 __ Bind(&done);
608}
609
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100610void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100611 LocationSummary* locations =
612 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100613 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100614}
615
616void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100617}
618
619void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100620 LocationSummary* locations =
621 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100622 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100623}
624
625void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100626}
627
628void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
629 ret->SetLocations(nullptr);
630}
631
632void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
633 codegen_->GenerateFrameExit();
634 __ ret();
635}
636
637void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100638 LocationSummary* locations =
639 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100640 switch (ret->InputAt(0)->GetType()) {
641 case Primitive::kPrimBoolean:
642 case Primitive::kPrimByte:
643 case Primitive::kPrimChar:
644 case Primitive::kPrimShort:
645 case Primitive::kPrimInt:
646 case Primitive::kPrimNot:
647 case Primitive::kPrimLong:
648 locations->SetInAt(0, X86_64CpuLocation(RAX));
649 break;
650
651 default:
652 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
653 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100654}
655
656void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
657 if (kIsDebugBuild) {
658 switch (ret->InputAt(0)->GetType()) {
659 case Primitive::kPrimBoolean:
660 case Primitive::kPrimByte:
661 case Primitive::kPrimChar:
662 case Primitive::kPrimShort:
663 case Primitive::kPrimInt:
664 case Primitive::kPrimNot:
665 case Primitive::kPrimLong:
666 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
667 break;
668
669 default:
670 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
671 }
672 }
673 codegen_->GenerateFrameExit();
674 __ ret();
675}
676
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100677Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
678 switch (type) {
679 case Primitive::kPrimBoolean:
680 case Primitive::kPrimByte:
681 case Primitive::kPrimChar:
682 case Primitive::kPrimShort:
683 case Primitive::kPrimInt:
684 case Primitive::kPrimNot: {
685 uint32_t index = gp_index_++;
686 stack_index_++;
687 if (index < calling_convention.GetNumberOfRegisters()) {
688 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
689 } else {
690 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
691 }
692 }
693
694 case Primitive::kPrimLong: {
695 uint32_t index = gp_index_;
696 stack_index_ += 2;
697 if (index < calling_convention.GetNumberOfRegisters()) {
698 gp_index_ += 1;
699 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
700 } else {
701 gp_index_ += 2;
702 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
703 }
704 }
705
706 case Primitive::kPrimDouble:
707 case Primitive::kPrimFloat:
708 LOG(FATAL) << "Unimplemented parameter type " << type;
709 break;
710
711 case Primitive::kPrimVoid:
712 LOG(FATAL) << "Unexpected parameter type " << type;
713 break;
714 }
715 return Location();
716}
717
718void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100719 HandleInvoke(invoke);
720}
721
722void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
723 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
724 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
725 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
726 invoke->GetIndexInDexCache() * heap_reference_size;
727
728 // TODO: Implement all kinds of calls:
729 // 1) boot -> boot
730 // 2) app -> boot
731 // 3) app -> app
732 //
733 // Currently we implement the app -> app logic, which looks up in the resolve cache.
734
735 // temp = method;
736 LoadCurrentMethod(temp);
737 // temp = temp->dex_cache_resolved_methods_;
738 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
739 // temp = temp[index_in_cache]
740 __ movl(temp, Address(temp, index_in_cache));
741 // (temp + offset_of_quick_compiled_code)()
742 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
743
744 DCHECK(!codegen_->IsLeafMethod());
745 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
746}
747
748void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
749 HandleInvoke(invoke);
750}
751
752void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100753 LocationSummary* locations =
754 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100755 locations->AddTemp(X86_64CpuLocation(RDI));
756
757 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100758 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100759 HInstruction* input = invoke->InputAt(i);
760 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
761 }
762
763 switch (invoke->GetType()) {
764 case Primitive::kPrimBoolean:
765 case Primitive::kPrimByte:
766 case Primitive::kPrimChar:
767 case Primitive::kPrimShort:
768 case Primitive::kPrimInt:
769 case Primitive::kPrimNot:
770 case Primitive::kPrimLong:
771 locations->SetOut(X86_64CpuLocation(RAX));
772 break;
773
774 case Primitive::kPrimVoid:
775 break;
776
777 case Primitive::kPrimDouble:
778 case Primitive::kPrimFloat:
779 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
780 break;
781 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100782}
783
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100784void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100785 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100786 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
787 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
788 LocationSummary* locations = invoke->GetLocations();
789 Location receiver = locations->InAt(0);
790 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
791 // temp = object->GetClass();
792 if (receiver.IsStackSlot()) {
793 __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
794 __ movq(temp, Address(temp, class_offset));
795 } else {
796 __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
797 }
798 // temp = temp->GetMethodAt(method_offset);
799 __ movl(temp, Address(temp, method_offset));
800 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100801 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
802
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100803 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100804 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100805}
806
807void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100808 LocationSummary* locations =
809 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100810 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100811 case Primitive::kPrimInt: {
812 locations->SetInAt(0, Location::RequiresRegister());
813 locations->SetInAt(1, Location::Any());
814 locations->SetOut(Location::SameAsFirstInput());
815 break;
816 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100817 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000818 locations->SetInAt(0, Location::RequiresRegister());
819 locations->SetInAt(1, Location::RequiresRegister());
820 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100821 break;
822 }
823
824 case Primitive::kPrimBoolean:
825 case Primitive::kPrimByte:
826 case Primitive::kPrimChar:
827 case Primitive::kPrimShort:
828 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
829 break;
830
831 default:
832 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
833 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100834}
835
836void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
837 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000838 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
839 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000841 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100842 if (locations->InAt(1).IsRegister()) {
843 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
844 locations->InAt(1).AsX86_64().AsCpuRegister());
845 } else if (locations->InAt(1).IsConstant()) {
846 HConstant* instruction = locations->InAt(1).GetConstant();
847 Immediate imm(instruction->AsIntConstant()->GetValue());
848 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
849 } else {
850 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
851 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
852 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000853 break;
854 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100855 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100856 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
857 locations->InAt(1).AsX86_64().AsCpuRegister());
858 break;
859 }
860
861 case Primitive::kPrimBoolean:
862 case Primitive::kPrimByte:
863 case Primitive::kPrimChar:
864 case Primitive::kPrimShort:
865 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
866 break;
867
868 default:
869 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
870 }
871}
872
873void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100874 LocationSummary* locations =
875 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100876 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100877 case Primitive::kPrimInt: {
878 locations->SetInAt(0, Location::RequiresRegister());
879 locations->SetInAt(1, Location::Any());
880 locations->SetOut(Location::SameAsFirstInput());
881 break;
882 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100883 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000884 locations->SetInAt(0, Location::RequiresRegister());
885 locations->SetInAt(1, Location::RequiresRegister());
886 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887 break;
888 }
889
890 case Primitive::kPrimBoolean:
891 case Primitive::kPrimByte:
892 case Primitive::kPrimChar:
893 case Primitive::kPrimShort:
894 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
895 break;
896
897 default:
898 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
899 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100900}
901
902void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
903 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000904 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
905 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100906 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000907 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100908 if (locations->InAt(1).IsRegister()) {
909 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
910 locations->InAt(1).AsX86_64().AsCpuRegister());
911 } else if (locations->InAt(1).IsConstant()) {
912 HConstant* instruction = locations->InAt(1).GetConstant();
913 Immediate imm(instruction->AsIntConstant()->GetValue());
914 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
915 } else {
916 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
917 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
918 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000919 break;
920 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100921 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100922 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
923 locations->InAt(1).AsX86_64().AsCpuRegister());
924 break;
925 }
926
927 case Primitive::kPrimBoolean:
928 case Primitive::kPrimByte:
929 case Primitive::kPrimChar:
930 case Primitive::kPrimShort:
931 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
932 break;
933
934 default:
935 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
936 }
937}
938
939void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100940 LocationSummary* locations =
941 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100942 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943}
944
945void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
946 InvokeRuntimeCallingConvention calling_convention;
947 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
948 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
949
950 __ gs()->call(Address::Absolute(
951 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
952
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100953 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100954 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100955}
956
957void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 LocationSummary* locations =
959 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100960 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
961 if (location.IsStackSlot()) {
962 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
963 } else if (location.IsDoubleStackSlot()) {
964 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
965 }
966 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100967}
968
969void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
970 // Nothing to do, the parameter is already at its location.
971}
972
973void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100974 LocationSummary* locations =
975 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000976 locations->SetInAt(0, Location::RequiresRegister());
977 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100978}
979
980void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
981 LocationSummary* locations = instruction->GetLocations();
982 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
983 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
984 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
985}
986
987void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100988 LocationSummary* locations =
989 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100990 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
991 locations->SetInAt(i, Location::Any());
992 }
993 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100994}
995
996void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
997 LOG(FATAL) << "Unimplemented";
998}
999
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001000void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001001 LocationSummary* locations =
1002 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001003 locations->SetInAt(0, Location::RequiresRegister());
1004 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001005 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001006 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001007 locations->AddTemp(Location::RequiresRegister());
1008 locations->AddTemp(Location::RequiresRegister());
1009 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001010}
1011
1012void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1013 LocationSummary* locations = instruction->GetLocations();
1014 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1015 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
1016 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001017 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001018
1019 switch (field_type) {
1020 case Primitive::kPrimBoolean:
1021 case Primitive::kPrimByte: {
1022 __ movb(Address(obj, offset), value);
1023 break;
1024 }
1025
1026 case Primitive::kPrimShort:
1027 case Primitive::kPrimChar: {
1028 __ movw(Address(obj, offset), value);
1029 break;
1030 }
1031
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001032 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001033 case Primitive::kPrimNot: {
1034 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001035 if (field_type == Primitive::kPrimNot) {
1036 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
1037 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1038 codegen_->MarkGCCard(temp, card, obj, value);
1039 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001040 break;
1041 }
1042
1043 case Primitive::kPrimLong: {
1044 __ movq(Address(obj, offset), value);
1045 break;
1046 }
1047
1048 case Primitive::kPrimFloat:
1049 case Primitive::kPrimDouble:
1050 LOG(FATAL) << "Unimplemented register type " << field_type;
1051
1052 case Primitive::kPrimVoid:
1053 LOG(FATAL) << "Unreachable type " << field_type;
1054 }
1055}
1056
1057void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001058 LocationSummary* locations =
1059 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001060 locations->SetInAt(0, Location::RequiresRegister());
1061 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001062}
1063
1064void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1065 LocationSummary* locations = instruction->GetLocations();
1066 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1067 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1068 size_t offset = instruction->GetFieldOffset().SizeValue();
1069
1070 switch (instruction->GetType()) {
1071 case Primitive::kPrimBoolean: {
1072 __ movzxb(out, Address(obj, offset));
1073 break;
1074 }
1075
1076 case Primitive::kPrimByte: {
1077 __ movsxb(out, Address(obj, offset));
1078 break;
1079 }
1080
1081 case Primitive::kPrimShort: {
1082 __ movsxw(out, Address(obj, offset));
1083 break;
1084 }
1085
1086 case Primitive::kPrimChar: {
1087 __ movzxw(out, Address(obj, offset));
1088 break;
1089 }
1090
1091 case Primitive::kPrimInt:
1092 case Primitive::kPrimNot: {
1093 __ movl(out, Address(obj, offset));
1094 break;
1095 }
1096
1097 case Primitive::kPrimLong: {
1098 __ movq(out, Address(obj, offset));
1099 break;
1100 }
1101
1102 case Primitive::kPrimFloat:
1103 case Primitive::kPrimDouble:
1104 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1105
1106 case Primitive::kPrimVoid:
1107 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1108 }
1109}
1110
1111void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001112 LocationSummary* locations =
1113 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001114 locations->SetInAt(0, Location::Any());
1115 // TODO: Have a normalization phase that makes this instruction never used.
1116 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001117}
1118
1119void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001120 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001121 codegen_->AddSlowPath(slow_path);
1122
1123 LocationSummary* locations = instruction->GetLocations();
1124 Location obj = locations->InAt(0);
1125 DCHECK(obj.Equals(locations->Out()));
1126
1127 if (obj.IsRegister()) {
1128 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1129 } else {
1130 DCHECK(locations->InAt(0).IsStackSlot());
1131 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1132 }
1133 __ j(kEqual, slow_path->GetEntryLabel());
1134}
1135
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001136void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001137 LocationSummary* locations =
1138 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001139 locations->SetInAt(0, Location::RequiresRegister());
1140 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1141 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001142}
1143
1144void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1145 LocationSummary* locations = instruction->GetLocations();
1146 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1147 Location index = locations->InAt(1);
1148
1149 switch (instruction->GetType()) {
1150 case Primitive::kPrimBoolean: {
1151 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1152 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1153 if (index.IsConstant()) {
1154 __ movzxb(out, Address(obj,
1155 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1156 } else {
1157 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1158 }
1159 break;
1160 }
1161
1162 case Primitive::kPrimByte: {
1163 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1164 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1165 if (index.IsConstant()) {
1166 __ movsxb(out, Address(obj,
1167 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1168 } else {
1169 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1170 }
1171 break;
1172 }
1173
1174 case Primitive::kPrimShort: {
1175 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1176 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1177 if (index.IsConstant()) {
1178 __ movsxw(out, Address(obj,
1179 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1180 } else {
1181 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1182 }
1183 break;
1184 }
1185
1186 case Primitive::kPrimChar: {
1187 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1188 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1189 if (index.IsConstant()) {
1190 __ movzxw(out, Address(obj,
1191 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1192 } else {
1193 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1194 }
1195 break;
1196 }
1197
1198 case Primitive::kPrimInt:
1199 case Primitive::kPrimNot: {
1200 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1201 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1202 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1203 if (index.IsConstant()) {
1204 __ movl(out, Address(obj,
1205 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1206 } else {
1207 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1208 }
1209 break;
1210 }
1211
1212 case Primitive::kPrimLong: {
1213 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1214 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1215 if (index.IsConstant()) {
1216 __ movq(out, Address(obj,
1217 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1218 } else {
1219 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1220 }
1221 break;
1222 }
1223
1224 case Primitive::kPrimFloat:
1225 case Primitive::kPrimDouble:
1226 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1227
1228 case Primitive::kPrimVoid:
1229 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1230 }
1231}
1232
1233void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001234 Primitive::Type value_type = instruction->GetComponentType();
1235 bool is_object = value_type == Primitive::kPrimNot;
1236 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1237 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1238 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001239 InvokeRuntimeCallingConvention calling_convention;
1240 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1241 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1242 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001243 } else {
1244 locations->SetInAt(0, Location::RequiresRegister());
1245 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1246 locations->SetInAt(2, Location::RequiresRegister());
1247 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001248}
1249
1250void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1251 LocationSummary* locations = instruction->GetLocations();
1252 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1253 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001254 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001255
1256 switch (value_type) {
1257 case Primitive::kPrimBoolean:
1258 case Primitive::kPrimByte: {
1259 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1260 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1261 if (index.IsConstant()) {
1262 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1263 __ movb(Address(obj, offset), value);
1264 } else {
1265 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1266 }
1267 break;
1268 }
1269
1270 case Primitive::kPrimShort:
1271 case Primitive::kPrimChar: {
1272 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1273 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1274 if (index.IsConstant()) {
1275 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1276 __ movw(Address(obj, offset), value);
1277 } else {
1278 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1279 }
1280 break;
1281 }
1282
1283 case Primitive::kPrimInt: {
1284 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1285 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1286 if (index.IsConstant()) {
1287 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1288 __ movl(Address(obj, offset), value);
1289 } else {
1290 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1291 }
1292 break;
1293 }
1294
1295 case Primitive::kPrimNot: {
1296 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1297 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001298 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001299 break;
1300 }
1301
1302 case Primitive::kPrimLong: {
1303 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1304 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1305 if (index.IsConstant()) {
1306 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1307 __ movq(Address(obj, offset), value);
1308 } else {
1309 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1310 }
1311 break;
1312 }
1313
1314 case Primitive::kPrimFloat:
1315 case Primitive::kPrimDouble:
1316 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1317
1318 case Primitive::kPrimVoid:
1319 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1320 }
1321}
1322
1323void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001324 LocationSummary* locations =
1325 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001326 locations->SetInAt(0, Location::RequiresRegister());
1327 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001328}
1329
1330void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1331 LocationSummary* locations = instruction->GetLocations();
1332 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1333 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1334 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1335 __ movl(out, Address(obj, offset));
1336}
1337
1338void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001339 LocationSummary* locations =
1340 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001341 locations->SetInAt(0, Location::RequiresRegister());
1342 locations->SetInAt(1, Location::RequiresRegister());
1343 // TODO: Have a normalization phase that makes this instruction never used.
1344 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001345}
1346
1347void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1348 LocationSummary* locations = instruction->GetLocations();
1349 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001350 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001351 codegen_->AddSlowPath(slow_path);
1352
1353 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1354 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1355
1356 __ cmpl(index, length);
1357 __ j(kAboveEqual, slow_path->GetEntryLabel());
1358}
1359
1360void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1361 CpuRegister card,
1362 CpuRegister object,
1363 CpuRegister value) {
1364 Label is_null;
1365 __ testl(value, value);
1366 __ j(kEqual, &is_null);
1367 __ gs()->movq(card, Address::Absolute(
1368 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1369 __ movq(temp, object);
1370 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1371 __ movb(Address(temp, card, TIMES_1, 0), card);
1372 __ Bind(&is_null);
1373}
1374
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001375void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1376 temp->SetLocations(nullptr);
1377}
1378
1379void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1380 // Nothing to do, this is driven by the code generator.
1381}
1382
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001383void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1384 LOG(FATAL) << "Unimplemented";
1385}
1386
1387void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001388 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1389}
1390
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001391void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1392 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1393}
1394
1395void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1396 SuspendCheckSlowPathX86_64* slow_path =
1397 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction);
1398 codegen_->AddSlowPath(slow_path);
1399 __ gs()->cmpl(Address::Absolute(
1400 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
1401 __ j(kNotEqual, slow_path->GetEntryLabel());
1402 __ Bind(slow_path->GetReturnLabel());
1403}
1404
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001405X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1406 return codegen_->GetAssembler();
1407}
1408
1409void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1410 MoveOperands* move = moves_.Get(index);
1411 Location source = move->GetSource();
1412 Location destination = move->GetDestination();
1413
1414 if (source.IsRegister()) {
1415 if (destination.IsRegister()) {
1416 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001417 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001418 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1419 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001420 } else {
1421 DCHECK(destination.IsDoubleStackSlot());
1422 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1423 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001424 }
1425 } else if (source.IsStackSlot()) {
1426 if (destination.IsRegister()) {
1427 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1428 Address(CpuRegister(RSP), source.GetStackIndex()));
1429 } else {
1430 DCHECK(destination.IsStackSlot());
1431 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1432 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1433 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001434 } else if (source.IsDoubleStackSlot()) {
1435 if (destination.IsRegister()) {
1436 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1437 Address(CpuRegister(RSP), source.GetStackIndex()));
1438 } else {
1439 DCHECK(destination.IsDoubleStackSlot());
1440 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1441 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1442 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001443 } else if (source.IsConstant()) {
1444 HConstant* constant = source.GetConstant();
1445 if (constant->IsIntConstant()) {
1446 Immediate imm(constant->AsIntConstant()->GetValue());
1447 if (destination.IsRegister()) {
1448 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1449 } else {
1450 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1451 }
1452 } else if (constant->IsLongConstant()) {
1453 int64_t value = constant->AsLongConstant()->GetValue();
1454 if (destination.IsRegister()) {
1455 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1456 } else {
1457 __ movq(CpuRegister(TMP), Immediate(value));
1458 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1459 }
1460 } else {
1461 LOG(FATAL) << "Unimplemented constant type";
1462 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001463 } else {
1464 LOG(FATAL) << "Unimplemented";
1465 }
1466}
1467
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001468void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001469 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001470 __ movl(Address(CpuRegister(RSP), mem), reg);
1471 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001472}
1473
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001474void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001475 ScratchRegisterScope ensure_scratch(
1476 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1477
1478 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1479 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1480 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1481 Address(CpuRegister(RSP), mem2 + stack_offset));
1482 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1483 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1484 CpuRegister(ensure_scratch.GetRegister()));
1485}
1486
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001487void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1488 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1489 __ movq(Address(CpuRegister(RSP), mem), reg);
1490 __ movq(reg, CpuRegister(TMP));
1491}
1492
1493void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1494 ScratchRegisterScope ensure_scratch(
1495 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1496
1497 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1498 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1499 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1500 Address(CpuRegister(RSP), mem2 + stack_offset));
1501 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1502 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1503 CpuRegister(ensure_scratch.GetRegister()));
1504}
1505
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001506void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1507 MoveOperands* move = moves_.Get(index);
1508 Location source = move->GetSource();
1509 Location destination = move->GetDestination();
1510
1511 if (source.IsRegister() && destination.IsRegister()) {
1512 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1513 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001514 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001515 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001516 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001517 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001518 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1519 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1520 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1521 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1522 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1523 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1524 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001525 } else {
1526 LOG(FATAL) << "Unimplemented";
1527 }
1528}
1529
1530
1531void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1532 __ pushq(CpuRegister(reg));
1533}
1534
1535
1536void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1537 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001538}
1539
1540} // namespace x86_64
1541} // namespace art