blob: f5437a17cbfef6bd348f93d0bf333c91007c7265 [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"
Ian Rogers7e70b002014-10-08 11:47:24 -070021#include "mirror/array-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010022#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);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010054static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { };
55static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010057class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010058 public:
59 InvokeRuntimeCallingConvention()
60 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010061 kRuntimeParameterCoreRegistersLength,
62 kRuntimeParameterFpuRegisters,
63 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010064
65 private:
66 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
67};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010068
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
70
71class NullCheckSlowPathX86_64 : public SlowPathCode {
72 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010073 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074
75 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
76 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010077 __ gs()->call(
78 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 }
81
82 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010083 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010084 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
85};
86
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010087class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
88 public:
89 StackOverflowCheckSlowPathX86_64() {}
90
91 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
92 __ Bind(GetEntryLabel());
93 __ addq(CpuRegister(RSP),
94 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
95 __ gs()->jmp(
96 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
97 }
98
99 private:
100 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
101};
102
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000103class SuspendCheckSlowPathX86_64 : public SlowPathCode {
104 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100105 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
106 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000107
108 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
109 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100110 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000111 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
112 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100113 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100114 if (successor_ == nullptr) {
115 __ jmp(GetReturnLabel());
116 } else {
117 __ jmp(codegen->GetLabelOf(successor_));
118 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000119 }
120
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 Label* GetReturnLabel() {
122 DCHECK(successor_ == nullptr);
123 return &return_label_;
124 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125
126 private:
127 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100128 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000129 Label return_label_;
130
131 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
132};
133
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100134class BoundsCheckSlowPathX86_64 : public SlowPathCode {
135 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100136 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
137 Location index_location,
138 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100139 : instruction_(instruction),
140 index_location_(index_location),
141 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100142
143 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
144 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
145 __ Bind(GetEntryLabel());
146 InvokeRuntimeCallingConvention calling_convention;
147 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
148 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
149 __ gs()->call(Address::Absolute(
150 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 }
153
154 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100155 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 const Location index_location_;
157 const Location length_location_;
158
159 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
160};
161
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100162#undef __
163#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
164
Dave Allison20dfc792014-06-16 20:44:29 -0700165inline Condition X86_64Condition(IfCondition cond) {
166 switch (cond) {
167 case kCondEQ: return kEqual;
168 case kCondNE: return kNotEqual;
169 case kCondLT: return kLess;
170 case kCondLE: return kLessEqual;
171 case kCondGT: return kGreater;
172 case kCondGE: return kGreaterEqual;
173 default:
174 LOG(FATAL) << "Unknown if condition";
175 }
176 return kEqual;
177}
178
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100179void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
180 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
181}
182
183void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
184 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
185}
186
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100187void CodeGeneratorX86_64::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
188 __ movq(Address(CpuRegister(RSP), stack_location.GetStackIndex()), CpuRegister(reg_id));
189}
190
191void CodeGeneratorX86_64::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
192 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_location.GetStackIndex()));
193}
194
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100195CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
196 : CodeGenerator(graph, kNumberOfRegIds),
197 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000198 instruction_visitor_(graph, this),
199 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100200
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100201size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
202 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
203}
204
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100205InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
206 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100207 : HGraphVisitor(graph),
208 assembler_(codegen->GetAssembler()),
209 codegen_(codegen) {}
210
211ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
212 bool* blocked_registers) const {
213 switch (type) {
214 case Primitive::kPrimLong:
215 case Primitive::kPrimByte:
216 case Primitive::kPrimBoolean:
217 case Primitive::kPrimChar:
218 case Primitive::kPrimShort:
219 case Primitive::kPrimInt:
220 case Primitive::kPrimNot: {
221 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
222 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
223 }
224
225 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100226 case Primitive::kPrimDouble: {
227 size_t reg = AllocateFreeRegisterInternal(
228 blocked_registers + kNumberOfCpuRegisters, kNumberOfFloatRegisters);
229 return X86_64ManagedRegister::FromXmmRegister(static_cast<FloatRegister>(reg));
230 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100231
232 case Primitive::kPrimVoid:
233 LOG(FATAL) << "Unreachable type " << type;
234 }
235
236 return ManagedRegister::NoRegister();
237}
238
239void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
240 // Stack register is always reserved.
241 blocked_registers[RSP] = true;
242
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000243 // Block the register used as TMP.
244 blocked_registers[TMP] = true;
245
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100246 // TODO: We currently don't use Quick's callee saved registers.
247 blocked_registers[RBX] = true;
248 blocked_registers[RBP] = true;
249 blocked_registers[R12] = true;
250 blocked_registers[R13] = true;
251 blocked_registers[R14] = true;
252 blocked_registers[R15] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100253
254 bool* blocked_xmm_registers = blocked_registers + kNumberOfCpuRegisters;
255 blocked_xmm_registers[XMM12] = true;
256 blocked_xmm_registers[XMM13] = true;
257 blocked_xmm_registers[XMM14] = true;
258 blocked_xmm_registers[XMM15] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100259}
260
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100261void CodeGeneratorX86_64::GenerateFrameEntry() {
262 // Create a fake register to mimic Quick.
263 static const int kFakeReturnRegister = 16;
264 core_spill_mask_ |= (1 << kFakeReturnRegister);
265
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100266 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700267 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100268
269 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
270 __ testq(CpuRegister(RAX), Address(
271 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100272 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100273 }
274
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100275 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100276 __ subq(CpuRegister(RSP),
277 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
278
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100279 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
280 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
281 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100282
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100283 __ gs()->cmpq(CpuRegister(RSP),
284 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
285 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100286 }
287
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100288 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
289}
290
291void CodeGeneratorX86_64::GenerateFrameExit() {
292 __ addq(CpuRegister(RSP),
293 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
294}
295
296void CodeGeneratorX86_64::Bind(Label* label) {
297 __ Bind(label);
298}
299
300void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
301 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
302}
303
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100304Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
305 switch (load->GetType()) {
306 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100307 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100308 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
309 break;
310
311 case Primitive::kPrimInt:
312 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100313 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100314 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100315
316 case Primitive::kPrimBoolean:
317 case Primitive::kPrimByte:
318 case Primitive::kPrimChar:
319 case Primitive::kPrimShort:
320 case Primitive::kPrimVoid:
321 LOG(FATAL) << "Unexpected type " << load->GetType();
322 }
323
324 LOG(FATAL) << "Unreachable";
325 return Location();
326}
327
328void CodeGeneratorX86_64::Move(Location destination, Location source) {
329 if (source.Equals(destination)) {
330 return;
331 }
332 if (destination.IsRegister()) {
333 if (source.IsRegister()) {
334 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100335 } else if (source.IsFpuRegister()) {
336 __ movd(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsXmmRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100337 } else if (source.IsStackSlot()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100338 __ movl(destination.AsX86_64().AsCpuRegister(),
339 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100340 } else {
341 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100342 __ movq(destination.AsX86_64().AsCpuRegister(),
343 Address(CpuRegister(RSP), source.GetStackIndex()));
344 }
345 } else if (destination.IsFpuRegister()) {
346 if (source.IsRegister()) {
347 __ movd(destination.AsX86_64().AsXmmRegister(), source.AsX86_64().AsCpuRegister());
348 } else if (source.IsFpuRegister()) {
349 __ movaps(destination.AsX86_64().AsXmmRegister(), source.AsX86_64().AsXmmRegister());
350 } else if (source.IsStackSlot()) {
351 __ movss(destination.AsX86_64().AsXmmRegister(),
352 Address(CpuRegister(RSP), source.GetStackIndex()));
353 } else {
354 DCHECK(source.IsDoubleStackSlot());
355 __ movsd(destination.AsX86_64().AsXmmRegister(),
356 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100357 }
358 } else if (destination.IsStackSlot()) {
359 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100360 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
361 source.AsX86_64().AsCpuRegister());
362 } else if (source.IsFpuRegister()) {
363 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
364 source.AsX86_64().AsXmmRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100365 } else {
366 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000367 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
368 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100369 }
370 } else {
371 DCHECK(destination.IsDoubleStackSlot());
372 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100373 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
374 source.AsX86_64().AsCpuRegister());
375 } else if (source.IsFpuRegister()) {
376 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
377 source.AsX86_64().AsXmmRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100378 } else {
379 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000380 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
381 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100382 }
383 }
384}
385
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100386void CodeGeneratorX86_64::Move(HInstruction* instruction,
387 Location location,
388 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100389 if (instruction->AsIntConstant() != nullptr) {
390 Immediate imm(instruction->AsIntConstant()->GetValue());
391 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000392 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100393 } else {
394 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
395 }
396 } else if (instruction->AsLongConstant() != nullptr) {
397 int64_t value = instruction->AsLongConstant()->GetValue();
398 if (location.IsRegister()) {
399 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
400 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000401 __ movq(CpuRegister(TMP), Immediate(value));
402 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100403 }
404 } else if (instruction->AsLoadLocal() != nullptr) {
405 switch (instruction->GetType()) {
406 case Primitive::kPrimBoolean:
407 case Primitive::kPrimByte:
408 case Primitive::kPrimChar:
409 case Primitive::kPrimShort:
410 case Primitive::kPrimInt:
411 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100412 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100413 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
414 break;
415
416 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100417 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100418 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
419 break;
420
421 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100422 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100423 }
424 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100425 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426 switch (instruction->GetType()) {
427 case Primitive::kPrimBoolean:
428 case Primitive::kPrimByte:
429 case Primitive::kPrimChar:
430 case Primitive::kPrimShort:
431 case Primitive::kPrimInt:
432 case Primitive::kPrimNot:
433 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100434 case Primitive::kPrimFloat:
435 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100436 Move(location, instruction->GetLocations()->Out());
437 break;
438
439 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100440 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100441 }
442 }
443}
444
445void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
446 got->SetLocations(nullptr);
447}
448
449void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
450 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100451 DCHECK(!successor->IsExitBlock());
452
453 HBasicBlock* block = got->GetBlock();
454 HInstruction* previous = got->GetPrevious();
455
456 HLoopInformation* info = block->GetLoopInformation();
457 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
458 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
459 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
460 return;
461 }
462
463 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
464 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
465 }
466 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100467 __ jmp(codegen_->GetLabelOf(successor));
468 }
469}
470
471void LocationsBuilderX86_64::VisitExit(HExit* exit) {
472 exit->SetLocations(nullptr);
473}
474
475void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
476 if (kIsDebugBuild) {
477 __ Comment("Unreachable");
478 __ int3();
479 }
480}
481
482void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100483 LocationSummary* locations =
484 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100485 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100486 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100487 locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100488 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100489}
490
491void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700492 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100493 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100494 // Moves do not affect the eflags register, so if the condition is evaluated
495 // just before the if, we don't need to evaluate it again.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100496 if (!cond->IsCondition() || !cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr)) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100497 // Materialized condition, compare against 0.
498 Location lhs = if_instr->GetLocations()->InAt(0);
499 if (lhs.IsRegister()) {
500 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
501 } else {
502 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
503 }
Dave Allison20dfc792014-06-16 20:44:29 -0700504 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100505 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700506 } else {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100507 Location lhs = cond->GetLocations()->InAt(0);
508 Location rhs = cond->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100509 if (rhs.IsRegister()) {
510 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
511 } else if (rhs.IsConstant()) {
512 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
513 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
514 } else {
515 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
516 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100517 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
Dave Allison20dfc792014-06-16 20:44:29 -0700518 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
519 }
520 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
521 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100522 }
523}
524
525void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
526 local->SetLocations(nullptr);
527}
528
529void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
530 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
531}
532
533void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
534 local->SetLocations(nullptr);
535}
536
537void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
538 // Nothing to do, this is driven by the code generator.
539}
540
541void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100542 LocationSummary* locations =
543 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100544 switch (store->InputAt(1)->GetType()) {
545 case Primitive::kPrimBoolean:
546 case Primitive::kPrimByte:
547 case Primitive::kPrimChar:
548 case Primitive::kPrimShort:
549 case Primitive::kPrimInt:
550 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100551 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100552 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
553 break;
554
555 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100556 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100557 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
558 break;
559
560 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100561 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100562 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100563}
564
565void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
566}
567
Dave Allison20dfc792014-06-16 20:44:29 -0700568void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100569 LocationSummary* locations =
570 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100571 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
572 locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100573 if (comp->NeedsMaterialization()) {
574 locations->SetOut(Location::RequiresRegister());
575 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100576}
577
Dave Allison20dfc792014-06-16 20:44:29 -0700578void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
579 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100580 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100581 CpuRegister reg = locations->Out().AsX86_64().AsCpuRegister();
582 // Clear register: setcc only sets the low byte.
583 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100584 if (locations->InAt(1).IsRegister()) {
585 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
586 locations->InAt(1).AsX86_64().AsCpuRegister());
587 } else if (locations->InAt(1).IsConstant()) {
588 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
589 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
590 } else {
591 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
592 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
593 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100594 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700595 }
596}
597
598void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
599 VisitCondition(comp);
600}
601
602void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
603 VisitCondition(comp);
604}
605
606void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
607 VisitCondition(comp);
608}
609
610void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
611 VisitCondition(comp);
612}
613
614void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
615 VisitCondition(comp);
616}
617
618void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
619 VisitCondition(comp);
620}
621
622void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
623 VisitCondition(comp);
624}
625
626void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
627 VisitCondition(comp);
628}
629
630void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
631 VisitCondition(comp);
632}
633
634void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
635 VisitCondition(comp);
636}
637
638void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
639 VisitCondition(comp);
640}
641
642void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
643 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100644}
645
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100646void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100647 LocationSummary* locations =
648 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100649 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
650 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100651 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100652}
653
654void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
655 Label greater, done;
656 LocationSummary* locations = compare->GetLocations();
657 switch (compare->InputAt(0)->GetType()) {
658 case Primitive::kPrimLong:
659 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
660 locations->InAt(1).AsX86_64().AsCpuRegister());
661 break;
662 default:
663 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
664 }
665
666 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
667 __ j(kEqual, &done);
668 __ j(kGreater, &greater);
669
670 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
671 __ jmp(&done);
672
673 __ Bind(&greater);
674 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
675
676 __ Bind(&done);
677}
678
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100679void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100680 LocationSummary* locations =
681 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100682 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100683}
684
685void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100686}
687
688void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100689 LocationSummary* locations =
690 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100691 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100692}
693
694void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100695}
696
697void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
698 ret->SetLocations(nullptr);
699}
700
701void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
702 codegen_->GenerateFrameExit();
703 __ ret();
704}
705
706void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100707 LocationSummary* locations =
708 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100709 switch (ret->InputAt(0)->GetType()) {
710 case Primitive::kPrimBoolean:
711 case Primitive::kPrimByte:
712 case Primitive::kPrimChar:
713 case Primitive::kPrimShort:
714 case Primitive::kPrimInt:
715 case Primitive::kPrimNot:
716 case Primitive::kPrimLong:
717 locations->SetInAt(0, X86_64CpuLocation(RAX));
718 break;
719
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100720 case Primitive::kPrimFloat:
721 case Primitive::kPrimDouble:
722 locations->SetInAt(0,
723 Location::FpuRegisterLocation(X86_64ManagedRegister::FromXmmRegister(XMM0)));
724 break;
725
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100726 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100727 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100728 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100729}
730
731void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
732 if (kIsDebugBuild) {
733 switch (ret->InputAt(0)->GetType()) {
734 case Primitive::kPrimBoolean:
735 case Primitive::kPrimByte:
736 case Primitive::kPrimChar:
737 case Primitive::kPrimShort:
738 case Primitive::kPrimInt:
739 case Primitive::kPrimNot:
740 case Primitive::kPrimLong:
741 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
742 break;
743
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100744 case Primitive::kPrimFloat:
745 case Primitive::kPrimDouble:
746 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsXmmRegister().AsFloatRegister(),
747 XMM0);
748 break;
749
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100750 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100751 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100752 }
753 }
754 codegen_->GenerateFrameExit();
755 __ ret();
756}
757
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100758Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
759 switch (type) {
760 case Primitive::kPrimBoolean:
761 case Primitive::kPrimByte:
762 case Primitive::kPrimChar:
763 case Primitive::kPrimShort:
764 case Primitive::kPrimInt:
765 case Primitive::kPrimNot: {
766 uint32_t index = gp_index_++;
767 stack_index_++;
768 if (index < calling_convention.GetNumberOfRegisters()) {
769 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
770 } else {
771 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
772 }
773 }
774
775 case Primitive::kPrimLong: {
776 uint32_t index = gp_index_;
777 stack_index_ += 2;
778 if (index < calling_convention.GetNumberOfRegisters()) {
779 gp_index_ += 1;
780 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
781 } else {
782 gp_index_ += 2;
783 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
784 }
785 }
786
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100787 case Primitive::kPrimFloat: {
788 uint32_t index = fp_index_++;
789 stack_index_++;
790 if (index < calling_convention.GetNumberOfFpuRegisters()) {
791 return Location::FpuRegisterLocation(X86_64ManagedRegister::FromXmmRegister(
792 calling_convention.GetFpuRegisterAt(index)));
793 } else {
794 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
795 }
796 }
797
798 case Primitive::kPrimDouble: {
799 uint32_t index = fp_index_++;
800 stack_index_ += 2;
801 if (index < calling_convention.GetNumberOfFpuRegisters()) {
802 return Location::FpuRegisterLocation(X86_64ManagedRegister::FromXmmRegister(
803 calling_convention.GetFpuRegisterAt(index)));
804 } else {
805 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
806 }
807 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100808
809 case Primitive::kPrimVoid:
810 LOG(FATAL) << "Unexpected parameter type " << type;
811 break;
812 }
813 return Location();
814}
815
816void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100817 HandleInvoke(invoke);
818}
819
820void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
821 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
822 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
823 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
824 invoke->GetIndexInDexCache() * heap_reference_size;
825
826 // TODO: Implement all kinds of calls:
827 // 1) boot -> boot
828 // 2) app -> boot
829 // 3) app -> app
830 //
831 // Currently we implement the app -> app logic, which looks up in the resolve cache.
832
833 // temp = method;
834 LoadCurrentMethod(temp);
835 // temp = temp->dex_cache_resolved_methods_;
836 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
837 // temp = temp[index_in_cache]
838 __ movl(temp, Address(temp, index_in_cache));
839 // (temp + offset_of_quick_compiled_code)()
840 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
841
842 DCHECK(!codegen_->IsLeafMethod());
843 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
844}
845
846void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
847 HandleInvoke(invoke);
848}
849
850void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100851 LocationSummary* locations =
852 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100853 locations->AddTemp(X86_64CpuLocation(RDI));
854
855 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100856 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100857 HInstruction* input = invoke->InputAt(i);
858 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
859 }
860
861 switch (invoke->GetType()) {
862 case Primitive::kPrimBoolean:
863 case Primitive::kPrimByte:
864 case Primitive::kPrimChar:
865 case Primitive::kPrimShort:
866 case Primitive::kPrimInt:
867 case Primitive::kPrimNot:
868 case Primitive::kPrimLong:
869 locations->SetOut(X86_64CpuLocation(RAX));
870 break;
871
872 case Primitive::kPrimVoid:
873 break;
874
875 case Primitive::kPrimDouble:
876 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100877 locations->SetOut(
878 Location::FpuRegisterLocation(X86_64ManagedRegister::FromXmmRegister(XMM0)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100879 break;
880 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100881}
882
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100883void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100884 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100885 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
886 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
887 LocationSummary* locations = invoke->GetLocations();
888 Location receiver = locations->InAt(0);
889 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
890 // temp = object->GetClass();
891 if (receiver.IsStackSlot()) {
892 __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
893 __ movq(temp, Address(temp, class_offset));
894 } else {
895 __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
896 }
897 // temp = temp->GetMethodAt(method_offset);
898 __ movl(temp, Address(temp, method_offset));
899 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100900 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
901
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100902 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100903 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100904}
905
906void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100907 LocationSummary* locations =
908 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100909 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100910 case Primitive::kPrimInt: {
911 locations->SetInAt(0, Location::RequiresRegister());
912 locations->SetInAt(1, Location::Any());
913 locations->SetOut(Location::SameAsFirstInput());
914 break;
915 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100916
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100917 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000918 locations->SetInAt(0, Location::RequiresRegister());
919 locations->SetInAt(1, Location::RequiresRegister());
920 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100921 break;
922 }
923
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100924 case Primitive::kPrimDouble:
925 case Primitive::kPrimFloat: {
926 locations->SetInAt(0, Location::RequiresFpuRegister());
927 locations->SetInAt(1, Location::Any());
928 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100929 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100930 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100931
932 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100933 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100934 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100935}
936
937void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
938 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100939 Location first = locations->InAt(0);
940 Location second = locations->InAt(1);
941
942 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000944 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100945 if (second.IsRegister()) {
946 __ addl(first.AsX86_64().AsCpuRegister(), second.AsX86_64().AsCpuRegister());
947 } else if (second.IsConstant()) {
948 HConstant* instruction = second.GetConstant();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100949 Immediate imm(instruction->AsIntConstant()->GetValue());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100950 __ addl(first.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100951 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100952 __ addl(first.AsX86_64().AsCpuRegister(),
953 Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100954 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000955 break;
956 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100957
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100958 case Primitive::kPrimLong: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100959 __ addq(first.AsX86_64().AsCpuRegister(), second.AsX86_64().AsCpuRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100960 break;
961 }
962
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100963 case Primitive::kPrimFloat: {
964 if (second.IsFpuRegister()) {
965 __ addss(first.AsX86_64().AsXmmRegister(), second.AsX86_64().AsXmmRegister());
966 } else {
967 __ addss(first.AsX86_64().AsXmmRegister(),
968 Address(CpuRegister(RSP), second.GetStackIndex()));
969 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100970 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100971 }
972
973 case Primitive::kPrimDouble: {
974 if (second.IsFpuRegister()) {
975 __ addsd(first.AsX86_64().AsXmmRegister(), second.AsX86_64().AsXmmRegister());
976 } else {
977 __ addsd(first.AsX86_64().AsXmmRegister(),
978 Address(CpuRegister(RSP), second.GetStackIndex()));
979 }
980 break;
981 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100982
983 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100984 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100985 }
986}
987
988void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100989 LocationSummary* locations =
990 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100991 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100992 case Primitive::kPrimInt: {
993 locations->SetInAt(0, Location::RequiresRegister());
994 locations->SetInAt(1, Location::Any());
995 locations->SetOut(Location::SameAsFirstInput());
996 break;
997 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100998 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000999 locations->SetInAt(0, Location::RequiresRegister());
1000 locations->SetInAt(1, Location::RequiresRegister());
1001 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001002 break;
1003 }
1004
1005 case Primitive::kPrimBoolean:
1006 case Primitive::kPrimByte:
1007 case Primitive::kPrimChar:
1008 case Primitive::kPrimShort:
1009 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1010 break;
1011
1012 default:
1013 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1014 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001015}
1016
1017void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1018 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001019 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
1020 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001021 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001022 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001023 if (locations->InAt(1).IsRegister()) {
1024 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
1025 locations->InAt(1).AsX86_64().AsCpuRegister());
1026 } else if (locations->InAt(1).IsConstant()) {
1027 HConstant* instruction = locations->InAt(1).GetConstant();
1028 Immediate imm(instruction->AsIntConstant()->GetValue());
1029 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
1030 } else {
1031 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
1032 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
1033 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001034 break;
1035 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001036 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001037 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
1038 locations->InAt(1).AsX86_64().AsCpuRegister());
1039 break;
1040 }
1041
1042 case Primitive::kPrimBoolean:
1043 case Primitive::kPrimByte:
1044 case Primitive::kPrimChar:
1045 case Primitive::kPrimShort:
1046 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1047 break;
1048
1049 default:
1050 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1051 }
1052}
1053
1054void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001055 LocationSummary* locations =
1056 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001057 InvokeRuntimeCallingConvention calling_convention;
1058 locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1059 locations->AddTemp(X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001060 locations->SetOut(X86_64CpuLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001061}
1062
1063void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
1064 InvokeRuntimeCallingConvention calling_convention;
1065 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
1066 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
1067
1068 __ gs()->call(Address::Absolute(
1069 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
1070
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001071 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001072 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001073}
1074
1075void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001076 LocationSummary* locations =
1077 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001078 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1079 if (location.IsStackSlot()) {
1080 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1081 } else if (location.IsDoubleStackSlot()) {
1082 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1083 }
1084 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001085}
1086
1087void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
1088 // Nothing to do, the parameter is already at its location.
1089}
1090
1091void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001092 LocationSummary* locations =
1093 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001094 locations->SetInAt(0, Location::RequiresRegister());
1095 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001096}
1097
1098void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
1099 LocationSummary* locations = instruction->GetLocations();
1100 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
1101 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
1102 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
1103}
1104
1105void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001106 LocationSummary* locations =
1107 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001108 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1109 locations->SetInAt(i, Location::Any());
1110 }
1111 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001112}
1113
1114void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
1115 LOG(FATAL) << "Unimplemented";
1116}
1117
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001118void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001119 LocationSummary* locations =
1120 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001121 Primitive::Type field_type = instruction->GetFieldType();
1122 bool is_object_type = field_type == Primitive::kPrimNot;
1123 bool dies_at_entry = !is_object_type;
1124 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1125 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
1126 if (is_object_type) {
1127 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001128 locations->AddTemp(Location::RequiresRegister());
1129 locations->AddTemp(Location::RequiresRegister());
1130 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001131}
1132
1133void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1134 LocationSummary* locations = instruction->GetLocations();
1135 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1136 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
1137 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001138 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001139
1140 switch (field_type) {
1141 case Primitive::kPrimBoolean:
1142 case Primitive::kPrimByte: {
1143 __ movb(Address(obj, offset), value);
1144 break;
1145 }
1146
1147 case Primitive::kPrimShort:
1148 case Primitive::kPrimChar: {
1149 __ movw(Address(obj, offset), value);
1150 break;
1151 }
1152
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001153 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001154 case Primitive::kPrimNot: {
1155 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001156 if (field_type == Primitive::kPrimNot) {
1157 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
1158 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
1159 codegen_->MarkGCCard(temp, card, obj, value);
1160 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001161 break;
1162 }
1163
1164 case Primitive::kPrimLong: {
1165 __ movq(Address(obj, offset), value);
1166 break;
1167 }
1168
1169 case Primitive::kPrimFloat:
1170 case Primitive::kPrimDouble:
1171 LOG(FATAL) << "Unimplemented register type " << field_type;
1172
1173 case Primitive::kPrimVoid:
1174 LOG(FATAL) << "Unreachable type " << field_type;
1175 }
1176}
1177
1178void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001179 LocationSummary* locations =
1180 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001181 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001182 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001183}
1184
1185void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1186 LocationSummary* locations = instruction->GetLocations();
1187 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1188 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1189 size_t offset = instruction->GetFieldOffset().SizeValue();
1190
1191 switch (instruction->GetType()) {
1192 case Primitive::kPrimBoolean: {
1193 __ movzxb(out, Address(obj, offset));
1194 break;
1195 }
1196
1197 case Primitive::kPrimByte: {
1198 __ movsxb(out, Address(obj, offset));
1199 break;
1200 }
1201
1202 case Primitive::kPrimShort: {
1203 __ movsxw(out, Address(obj, offset));
1204 break;
1205 }
1206
1207 case Primitive::kPrimChar: {
1208 __ movzxw(out, Address(obj, offset));
1209 break;
1210 }
1211
1212 case Primitive::kPrimInt:
1213 case Primitive::kPrimNot: {
1214 __ movl(out, Address(obj, offset));
1215 break;
1216 }
1217
1218 case Primitive::kPrimLong: {
1219 __ movq(out, Address(obj, offset));
1220 break;
1221 }
1222
1223 case Primitive::kPrimFloat:
1224 case Primitive::kPrimDouble:
1225 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1226
1227 case Primitive::kPrimVoid:
1228 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1229 }
1230}
1231
1232void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001233 LocationSummary* locations =
1234 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001235 locations->SetInAt(0, Location::Any());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001236 if (instruction->HasUses()) {
1237 locations->SetOut(Location::SameAsFirstInput());
1238 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001239}
1240
1241void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001242 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001243 codegen_->AddSlowPath(slow_path);
1244
1245 LocationSummary* locations = instruction->GetLocations();
1246 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001247
1248 if (obj.IsRegister()) {
1249 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001250 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001251 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001252 } else {
1253 DCHECK(obj.IsConstant()) << obj;
1254 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1255 __ jmp(slow_path->GetEntryLabel());
1256 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001257 }
1258 __ j(kEqual, slow_path->GetEntryLabel());
1259}
1260
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001261void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001262 LocationSummary* locations =
1263 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001264 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1265 locations->SetInAt(
1266 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001267 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001268}
1269
1270void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1271 LocationSummary* locations = instruction->GetLocations();
1272 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1273 Location index = locations->InAt(1);
1274
1275 switch (instruction->GetType()) {
1276 case Primitive::kPrimBoolean: {
1277 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1278 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1279 if (index.IsConstant()) {
1280 __ movzxb(out, Address(obj,
1281 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1282 } else {
1283 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1284 }
1285 break;
1286 }
1287
1288 case Primitive::kPrimByte: {
1289 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1290 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1291 if (index.IsConstant()) {
1292 __ movsxb(out, Address(obj,
1293 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1294 } else {
1295 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1296 }
1297 break;
1298 }
1299
1300 case Primitive::kPrimShort: {
1301 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1302 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1303 if (index.IsConstant()) {
1304 __ movsxw(out, Address(obj,
1305 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1306 } else {
1307 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1308 }
1309 break;
1310 }
1311
1312 case Primitive::kPrimChar: {
1313 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1314 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1315 if (index.IsConstant()) {
1316 __ movzxw(out, Address(obj,
1317 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1318 } else {
1319 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1320 }
1321 break;
1322 }
1323
1324 case Primitive::kPrimInt:
1325 case Primitive::kPrimNot: {
1326 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1327 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1328 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1329 if (index.IsConstant()) {
1330 __ movl(out, Address(obj,
1331 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1332 } else {
1333 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1334 }
1335 break;
1336 }
1337
1338 case Primitive::kPrimLong: {
1339 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1340 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1341 if (index.IsConstant()) {
1342 __ movq(out, Address(obj,
1343 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1344 } else {
1345 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1346 }
1347 break;
1348 }
1349
1350 case Primitive::kPrimFloat:
1351 case Primitive::kPrimDouble:
1352 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1353
1354 case Primitive::kPrimVoid:
1355 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1356 }
1357}
1358
1359void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001360 Primitive::Type value_type = instruction->GetComponentType();
1361 bool is_object = value_type == Primitive::kPrimNot;
1362 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1363 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1364 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001365 InvokeRuntimeCallingConvention calling_convention;
1366 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1367 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1368 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001369 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001370 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1371 locations->SetInAt(
1372 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1373 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001374 if (value_type == Primitive::kPrimLong) {
1375 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
1376 } else {
1377 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), Location::kDiesAtEntry);
1378 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001379 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001380}
1381
1382void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1383 LocationSummary* locations = instruction->GetLocations();
1384 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1385 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001386 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001387 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001388
1389 switch (value_type) {
1390 case Primitive::kPrimBoolean:
1391 case Primitive::kPrimByte: {
1392 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001393 if (index.IsConstant()) {
1394 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001395 if (value.IsRegister()) {
1396 __ movb(Address(obj, offset), value.AsX86_64().AsCpuRegister());
1397 } else {
1398 __ movb(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1399 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001400 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001401 if (value.IsRegister()) {
1402 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset),
1403 value.AsX86_64().AsCpuRegister());
1404 } else {
1405 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset),
1406 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1407 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001408 }
1409 break;
1410 }
1411
1412 case Primitive::kPrimShort:
1413 case Primitive::kPrimChar: {
1414 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001415 if (index.IsConstant()) {
1416 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001417 if (value.IsRegister()) {
1418 __ movw(Address(obj, offset), value.AsX86_64().AsCpuRegister());
1419 } else {
1420 __ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1421 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001422 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001423 if (value.IsRegister()) {
1424 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset),
1425 value.AsX86_64().AsCpuRegister());
1426 } else {
1427 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset),
1428 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1429 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001430 }
1431 break;
1432 }
1433
1434 case Primitive::kPrimInt: {
1435 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001436 if (index.IsConstant()) {
1437 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001438 if (value.IsRegister()) {
1439 __ movl(Address(obj, offset), value.AsX86_64().AsCpuRegister());
1440 } else {
1441 __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1442 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001443 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001444 if (value.IsRegister()) {
1445 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset),
1446 value.AsX86_64().AsCpuRegister());
1447 } else {
1448 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset),
1449 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1450 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001451 }
1452 break;
1453 }
1454
1455 case Primitive::kPrimNot: {
1456 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1457 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001458 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001459 break;
1460 }
1461
1462 case Primitive::kPrimLong: {
1463 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001464 if (index.IsConstant()) {
1465 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001466 DCHECK(value.IsRegister());
1467 __ movq(Address(obj, offset), value.AsX86_64().AsCpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001468 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001469 DCHECK(value.IsRegister());
1470 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset),
1471 value.AsX86_64().AsCpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001472 }
1473 break;
1474 }
1475
1476 case Primitive::kPrimFloat:
1477 case Primitive::kPrimDouble:
1478 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1479
1480 case Primitive::kPrimVoid:
1481 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1482 }
1483}
1484
1485void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001486 LocationSummary* locations =
1487 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001488 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001489 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001490}
1491
1492void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1493 LocationSummary* locations = instruction->GetLocations();
1494 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1495 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1496 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1497 __ movl(out, Address(obj, offset));
1498}
1499
1500void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001501 LocationSummary* locations =
1502 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001503 locations->SetInAt(0, Location::RequiresRegister());
1504 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001505 if (instruction->HasUses()) {
1506 locations->SetOut(Location::SameAsFirstInput());
1507 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001508}
1509
1510void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1511 LocationSummary* locations = instruction->GetLocations();
1512 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001513 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001514 codegen_->AddSlowPath(slow_path);
1515
1516 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1517 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1518
1519 __ cmpl(index, length);
1520 __ j(kAboveEqual, slow_path->GetEntryLabel());
1521}
1522
1523void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1524 CpuRegister card,
1525 CpuRegister object,
1526 CpuRegister value) {
1527 Label is_null;
1528 __ testl(value, value);
1529 __ j(kEqual, &is_null);
1530 __ gs()->movq(card, Address::Absolute(
1531 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1532 __ movq(temp, object);
1533 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1534 __ movb(Address(temp, card, TIMES_1, 0), card);
1535 __ Bind(&is_null);
1536}
1537
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001538void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1539 temp->SetLocations(nullptr);
1540}
1541
1542void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1543 // Nothing to do, this is driven by the code generator.
1544}
1545
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001546void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1547 LOG(FATAL) << "Unimplemented";
1548}
1549
1550void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001551 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1552}
1553
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001554void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1555 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1556}
1557
1558void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001559 HBasicBlock* block = instruction->GetBlock();
1560 if (block->GetLoopInformation() != nullptr) {
1561 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1562 // The back edge will generate the suspend check.
1563 return;
1564 }
1565 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1566 // The goto will generate the suspend check.
1567 return;
1568 }
1569 GenerateSuspendCheck(instruction, nullptr);
1570}
1571
1572void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
1573 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001574 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001575 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001576 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001577 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001578 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001579 if (successor == nullptr) {
1580 __ j(kNotEqual, slow_path->GetEntryLabel());
1581 __ Bind(slow_path->GetReturnLabel());
1582 } else {
1583 __ j(kEqual, codegen_->GetLabelOf(successor));
1584 __ jmp(slow_path->GetEntryLabel());
1585 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001586}
1587
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001588X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1589 return codegen_->GetAssembler();
1590}
1591
1592void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1593 MoveOperands* move = moves_.Get(index);
1594 Location source = move->GetSource();
1595 Location destination = move->GetDestination();
1596
1597 if (source.IsRegister()) {
1598 if (destination.IsRegister()) {
1599 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001600 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001601 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1602 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001603 } else {
1604 DCHECK(destination.IsDoubleStackSlot());
1605 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1606 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001607 }
1608 } else if (source.IsStackSlot()) {
1609 if (destination.IsRegister()) {
1610 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1611 Address(CpuRegister(RSP), source.GetStackIndex()));
1612 } else {
1613 DCHECK(destination.IsStackSlot());
1614 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1615 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1616 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001617 } else if (source.IsDoubleStackSlot()) {
1618 if (destination.IsRegister()) {
1619 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1620 Address(CpuRegister(RSP), source.GetStackIndex()));
1621 } else {
1622 DCHECK(destination.IsDoubleStackSlot());
1623 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1624 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1625 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001626 } else if (source.IsConstant()) {
1627 HConstant* constant = source.GetConstant();
1628 if (constant->IsIntConstant()) {
1629 Immediate imm(constant->AsIntConstant()->GetValue());
1630 if (destination.IsRegister()) {
1631 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1632 } else {
1633 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1634 }
1635 } else if (constant->IsLongConstant()) {
1636 int64_t value = constant->AsLongConstant()->GetValue();
1637 if (destination.IsRegister()) {
1638 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1639 } else {
1640 __ movq(CpuRegister(TMP), Immediate(value));
1641 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1642 }
1643 } else {
1644 LOG(FATAL) << "Unimplemented constant type";
1645 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001646 } else {
1647 LOG(FATAL) << "Unimplemented";
1648 }
1649}
1650
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001651void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001652 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001653 __ movl(Address(CpuRegister(RSP), mem), reg);
1654 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001655}
1656
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001657void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001658 ScratchRegisterScope ensure_scratch(
1659 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1660
1661 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1662 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1663 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1664 Address(CpuRegister(RSP), mem2 + stack_offset));
1665 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1666 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1667 CpuRegister(ensure_scratch.GetRegister()));
1668}
1669
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001670void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1671 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1672 __ movq(Address(CpuRegister(RSP), mem), reg);
1673 __ movq(reg, CpuRegister(TMP));
1674}
1675
1676void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1677 ScratchRegisterScope ensure_scratch(
1678 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1679
1680 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1681 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1682 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1683 Address(CpuRegister(RSP), mem2 + stack_offset));
1684 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1685 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1686 CpuRegister(ensure_scratch.GetRegister()));
1687}
1688
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001689void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1690 MoveOperands* move = moves_.Get(index);
1691 Location source = move->GetSource();
1692 Location destination = move->GetDestination();
1693
1694 if (source.IsRegister() && destination.IsRegister()) {
1695 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1696 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001697 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001698 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001699 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001700 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001701 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1702 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1703 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1704 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1705 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1706 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1707 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001708 } else {
1709 LOG(FATAL) << "Unimplemented";
1710 }
1711}
1712
1713
1714void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1715 __ pushq(CpuRegister(reg));
1716}
1717
1718
1719void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1720 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001721}
1722
1723} // namespace x86_64
1724} // namespace art