blob: 2b175911f358704f7e8c5fd010328bec4bb3ea23 [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
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010033namespace x86_64 {
34
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010035static constexpr bool kExplicitStackOverflowCheck = false;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010036
37// Some x86_64 instructions require a register to be available as temp.
38static constexpr Register TMP = R11;
39
40static constexpr int kNumberOfPushedRegistersAtEntry = 1;
41static constexpr int kCurrentMethodStackOffset = 0;
42
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010043static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
44static constexpr size_t kRuntimeParameterCoreRegistersLength =
45 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010046static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { };
47static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010048
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050 public:
51 InvokeRuntimeCallingConvention()
52 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053 kRuntimeParameterCoreRegistersLength,
54 kRuntimeParameterFpuRegisters,
55 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056
57 private:
58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
59};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010060
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
62
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010063class SlowPathCodeX86_64 : public SlowPathCode {
64 public:
65 SlowPathCodeX86_64() : entry_label_(), exit_label_() {}
66
67 Label* GetEntryLabel() { return &entry_label_; }
68 Label* GetExitLabel() { return &exit_label_; }
69
70 private:
71 Label entry_label_;
72 Label exit_label_;
73
74 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86_64);
75};
76
77class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010078 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080
81 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
82 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010083 __ gs()->call(
84 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +010085 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010086 }
87
88 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010089 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010090 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
91};
92
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010093class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010094 public:
95 StackOverflowCheckSlowPathX86_64() {}
96
97 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
98 __ Bind(GetEntryLabel());
99 __ addq(CpuRegister(RSP),
100 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
101 __ gs()->jmp(
102 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
103 }
104
105 private:
106 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
107};
108
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100109class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000110 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100111 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
112 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000113
114 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100115 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100117 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
119 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100120 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 if (successor_ == nullptr) {
122 __ jmp(GetReturnLabel());
123 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100124 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100125 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000126 }
127
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100128 Label* GetReturnLabel() {
129 DCHECK(successor_ == nullptr);
130 return &return_label_;
131 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132
133 private:
134 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100135 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000136 Label return_label_;
137
138 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
139};
140
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100141class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100142 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100143 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
144 Location index_location,
145 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100146 : instruction_(instruction),
147 index_location_(index_location),
148 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100149
150 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100151 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 __ Bind(GetEntryLabel());
153 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100154 x64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
155 x64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 __ gs()->call(Address::Absolute(
157 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100158 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159 }
160
161 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100162 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100163 const Location index_location_;
164 const Location length_location_;
165
166 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
167};
168
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100169#undef __
170#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
171
Dave Allison20dfc792014-06-16 20:44:29 -0700172inline Condition X86_64Condition(IfCondition cond) {
173 switch (cond) {
174 case kCondEQ: return kEqual;
175 case kCondNE: return kNotEqual;
176 case kCondLT: return kLess;
177 case kCondLE: return kLessEqual;
178 case kCondGT: return kGreater;
179 case kCondGE: return kGreaterEqual;
180 default:
181 LOG(FATAL) << "Unknown if condition";
182 }
183 return kEqual;
184}
185
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100186void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
187 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
188}
189
190void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
191 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
192}
193
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100194void CodeGeneratorX86_64::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
195 __ movq(Address(CpuRegister(RSP), stack_location.GetStackIndex()), CpuRegister(reg_id));
196}
197
198void CodeGeneratorX86_64::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
199 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_location.GetStackIndex()));
200}
201
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100202CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100203 : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100204 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100205 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000206 instruction_visitor_(graph, this),
207 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100208
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100209size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
210 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
211}
212
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100213InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
214 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100215 : HGraphVisitor(graph),
216 assembler_(codegen->GetAssembler()),
217 codegen_(codegen) {}
218
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100219Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100220 switch (type) {
221 case Primitive::kPrimLong:
222 case Primitive::kPrimByte:
223 case Primitive::kPrimBoolean:
224 case Primitive::kPrimChar:
225 case Primitive::kPrimShort:
226 case Primitive::kPrimInt:
227 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100228 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100229 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100230 }
231
232 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100233 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100234 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100235 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100236 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100237
238 case Primitive::kPrimVoid:
239 LOG(FATAL) << "Unreachable type " << type;
240 }
241
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100242 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100243}
244
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100245void CodeGeneratorX86_64::SetupBlockedRegisters() const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100246 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100247 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100248
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000249 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100250 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000251
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100252 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100253 blocked_core_registers_[RBX] = true;
254 blocked_core_registers_[RBP] = true;
255 blocked_core_registers_[R12] = true;
256 blocked_core_registers_[R13] = true;
257 blocked_core_registers_[R14] = true;
258 blocked_core_registers_[R15] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100259
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100260 blocked_fpu_registers_[XMM12] = true;
261 blocked_fpu_registers_[XMM13] = true;
262 blocked_fpu_registers_[XMM14] = true;
263 blocked_fpu_registers_[XMM15] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100264}
265
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100266void CodeGeneratorX86_64::GenerateFrameEntry() {
267 // Create a fake register to mimic Quick.
268 static const int kFakeReturnRegister = 16;
269 core_spill_mask_ |= (1 << kFakeReturnRegister);
270
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100271 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700272 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100273
274 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
275 __ testq(CpuRegister(RAX), Address(
276 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100277 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100278 }
279
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100280 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100281 __ subq(CpuRegister(RSP),
282 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
283
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100284 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100285 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100286 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100287
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100288 __ gs()->cmpq(CpuRegister(RSP),
289 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
290 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100291 }
292
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100293 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
294}
295
296void CodeGeneratorX86_64::GenerateFrameExit() {
297 __ addq(CpuRegister(RSP),
298 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
299}
300
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100301void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
302 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100303}
304
305void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
306 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
307}
308
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100309Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
310 switch (load->GetType()) {
311 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100312 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100313 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
314 break;
315
316 case Primitive::kPrimInt:
317 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100318 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100319 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100320
321 case Primitive::kPrimBoolean:
322 case Primitive::kPrimByte:
323 case Primitive::kPrimChar:
324 case Primitive::kPrimShort:
325 case Primitive::kPrimVoid:
326 LOG(FATAL) << "Unexpected type " << load->GetType();
327 }
328
329 LOG(FATAL) << "Unreachable";
330 return Location();
331}
332
333void CodeGeneratorX86_64::Move(Location destination, Location source) {
334 if (source.Equals(destination)) {
335 return;
336 }
337 if (destination.IsRegister()) {
338 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100339 __ movq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100340 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100341 __ movd(destination.As<CpuRegister>(), source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100342 } else if (source.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100343 __ movl(destination.As<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100344 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100345 } else {
346 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100347 __ movq(destination.As<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100348 Address(CpuRegister(RSP), source.GetStackIndex()));
349 }
350 } else if (destination.IsFpuRegister()) {
351 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100352 __ movd(destination.As<XmmRegister>(), source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100353 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100354 __ movaps(destination.As<XmmRegister>(), source.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100355 } else if (source.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100356 __ movss(destination.As<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100357 Address(CpuRegister(RSP), source.GetStackIndex()));
358 } else {
359 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100360 __ movsd(destination.As<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100361 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100362 }
363 } else if (destination.IsStackSlot()) {
364 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100365 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100366 source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100367 } else if (source.IsFpuRegister()) {
368 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100369 source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100370 } else {
371 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000372 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
373 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100374 }
375 } else {
376 DCHECK(destination.IsDoubleStackSlot());
377 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100378 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100379 source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100380 } else if (source.IsFpuRegister()) {
381 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100382 source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100383 } else {
384 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000385 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
386 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100387 }
388 }
389}
390
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100391void CodeGeneratorX86_64::Move(HInstruction* instruction,
392 Location location,
393 HInstruction* move_for) {
Roland Levillain476df552014-10-09 17:51:36 +0100394 if (instruction->IsIntConstant()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100395 Immediate imm(instruction->AsIntConstant()->GetValue());
396 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100397 __ movl(location.As<CpuRegister>(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398 } else {
399 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
400 }
Roland Levillain476df552014-10-09 17:51:36 +0100401 } else if (instruction->IsLongConstant()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100402 int64_t value = instruction->AsLongConstant()->GetValue();
403 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100404 __ movq(location.As<CpuRegister>(), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100405 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000406 __ movq(CpuRegister(TMP), Immediate(value));
407 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100408 }
Roland Levillain476df552014-10-09 17:51:36 +0100409 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100410 switch (instruction->GetType()) {
411 case Primitive::kPrimBoolean:
412 case Primitive::kPrimByte:
413 case Primitive::kPrimChar:
414 case Primitive::kPrimShort:
415 case Primitive::kPrimInt:
416 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100417 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100418 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
419 break;
420
421 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100422 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100423 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
424 break;
425
426 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100427 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428 }
429 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100430 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100431 switch (instruction->GetType()) {
432 case Primitive::kPrimBoolean:
433 case Primitive::kPrimByte:
434 case Primitive::kPrimChar:
435 case Primitive::kPrimShort:
436 case Primitive::kPrimInt:
437 case Primitive::kPrimNot:
438 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100439 case Primitive::kPrimFloat:
440 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100441 Move(location, instruction->GetLocations()->Out());
442 break;
443
444 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100445 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100446 }
447 }
448}
449
450void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
451 got->SetLocations(nullptr);
452}
453
454void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
455 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100456 DCHECK(!successor->IsExitBlock());
457
458 HBasicBlock* block = got->GetBlock();
459 HInstruction* previous = got->GetPrevious();
460
461 HLoopInformation* info = block->GetLoopInformation();
462 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
463 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
464 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
465 return;
466 }
467
468 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
469 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
470 }
471 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100472 __ jmp(codegen_->GetLabelOf(successor));
473 }
474}
475
476void LocationsBuilderX86_64::VisitExit(HExit* exit) {
477 exit->SetLocations(nullptr);
478}
479
480void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
481 if (kIsDebugBuild) {
482 __ Comment("Unreachable");
483 __ int3();
484 }
485}
486
487void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100488 LocationSummary* locations =
489 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100490 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100491 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100492 locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100493 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100494}
495
496void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700497 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100498 bool materialized = !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
499 // Moves do not affect the eflags register, so if the condition is evaluated
500 // just before the if, we don't need to evaluate it again.
501 bool eflags_set = cond->IsCondition()
502 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
503 if (materialized) {
504 if (!eflags_set) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100505 // Materialized condition, compare against 0.
506 Location lhs = if_instr->GetLocations()->InAt(0);
507 if (lhs.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100508 __ cmpl(lhs.As<CpuRegister>(), Immediate(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100509 } else {
510 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
511 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100512 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
513 } else {
514 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
515 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700516 }
Dave Allison20dfc792014-06-16 20:44:29 -0700517 } else {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100518 Location lhs = cond->GetLocations()->InAt(0);
519 Location rhs = cond->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100520 if (rhs.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100521 __ cmpl(lhs.As<CpuRegister>(), rhs.As<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100522 } else if (rhs.IsConstant()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100523 __ cmpl(lhs.As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100524 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
525 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100526 __ cmpl(lhs.As<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100527 }
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100528 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
Dave Allison20dfc792014-06-16 20:44:29 -0700529 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
530 }
531 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
532 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100533 }
534}
535
536void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
537 local->SetLocations(nullptr);
538}
539
540void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
541 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
542}
543
544void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
545 local->SetLocations(nullptr);
546}
547
548void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
549 // Nothing to do, this is driven by the code generator.
550}
551
552void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100553 LocationSummary* locations =
554 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100555 switch (store->InputAt(1)->GetType()) {
556 case Primitive::kPrimBoolean:
557 case Primitive::kPrimByte:
558 case Primitive::kPrimChar:
559 case Primitive::kPrimShort:
560 case Primitive::kPrimInt:
561 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100562 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100563 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
564 break;
565
566 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100567 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100568 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
569 break;
570
571 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100572 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100573 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100574}
575
576void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
577}
578
Dave Allison20dfc792014-06-16 20:44:29 -0700579void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100580 LocationSummary* locations =
581 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100582 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
583 locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100584 if (comp->NeedsMaterialization()) {
585 locations->SetOut(Location::RequiresRegister());
586 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100587}
588
Dave Allison20dfc792014-06-16 20:44:29 -0700589void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
590 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100591 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100592 CpuRegister reg = locations->Out().As<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100593 // Clear register: setcc only sets the low byte.
594 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100595 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100596 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100597 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100598 } else if (locations->InAt(1).IsConstant()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100599 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100600 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
601 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100602 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100603 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
604 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100605 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700606 }
607}
608
609void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
610 VisitCondition(comp);
611}
612
613void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
614 VisitCondition(comp);
615}
616
617void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
618 VisitCondition(comp);
619}
620
621void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
622 VisitCondition(comp);
623}
624
625void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
626 VisitCondition(comp);
627}
628
629void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
630 VisitCondition(comp);
631}
632
633void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
634 VisitCondition(comp);
635}
636
637void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
638 VisitCondition(comp);
639}
640
641void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
642 VisitCondition(comp);
643}
644
645void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
646 VisitCondition(comp);
647}
648
649void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
650 VisitCondition(comp);
651}
652
653void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
654 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100655}
656
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100657void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100658 LocationSummary* locations =
659 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100660 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
661 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100662 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100663}
664
665void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
666 Label greater, done;
667 LocationSummary* locations = compare->GetLocations();
668 switch (compare->InputAt(0)->GetType()) {
669 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100670 __ cmpq(locations->InAt(0).As<CpuRegister>(),
671 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100672 break;
673 default:
674 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
675 }
676
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100677 CpuRegister output = locations->Out().As<CpuRegister>();
678 __ movl(output, Immediate(0));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100679 __ j(kEqual, &done);
680 __ j(kGreater, &greater);
681
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100682 __ movl(output, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100683 __ jmp(&done);
684
685 __ Bind(&greater);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100686 __ movl(output, Immediate(1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100687
688 __ Bind(&done);
689}
690
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100691void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100692 LocationSummary* locations =
693 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100694 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100695}
696
697void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100698}
699
700void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100701 LocationSummary* locations =
702 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100703 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100704}
705
706void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100707}
708
709void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
710 ret->SetLocations(nullptr);
711}
712
713void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
714 codegen_->GenerateFrameExit();
715 __ ret();
716}
717
718void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100719 LocationSummary* locations =
720 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100721 switch (ret->InputAt(0)->GetType()) {
722 case Primitive::kPrimBoolean:
723 case Primitive::kPrimByte:
724 case Primitive::kPrimChar:
725 case Primitive::kPrimShort:
726 case Primitive::kPrimInt:
727 case Primitive::kPrimNot:
728 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100729 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100730 break;
731
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100732 case Primitive::kPrimFloat:
733 case Primitive::kPrimDouble:
734 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100735 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100736 break;
737
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100738 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100739 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100740 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100741}
742
743void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
744 if (kIsDebugBuild) {
745 switch (ret->InputAt(0)->GetType()) {
746 case Primitive::kPrimBoolean:
747 case Primitive::kPrimByte:
748 case Primitive::kPrimChar:
749 case Primitive::kPrimShort:
750 case Primitive::kPrimInt:
751 case Primitive::kPrimNot:
752 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100753 DCHECK_EQ(ret->GetLocations()->InAt(0).As<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100754 break;
755
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100756 case Primitive::kPrimFloat:
757 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100758 DCHECK_EQ(ret->GetLocations()->InAt(0).As<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100759 XMM0);
760 break;
761
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100762 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100763 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100764 }
765 }
766 codegen_->GenerateFrameExit();
767 __ ret();
768}
769
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100770Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
771 switch (type) {
772 case Primitive::kPrimBoolean:
773 case Primitive::kPrimByte:
774 case Primitive::kPrimChar:
775 case Primitive::kPrimShort:
776 case Primitive::kPrimInt:
777 case Primitive::kPrimNot: {
778 uint32_t index = gp_index_++;
779 stack_index_++;
780 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100781 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100782 } else {
783 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
784 }
785 }
786
787 case Primitive::kPrimLong: {
788 uint32_t index = gp_index_;
789 stack_index_ += 2;
790 if (index < calling_convention.GetNumberOfRegisters()) {
791 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100792 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100793 } else {
794 gp_index_ += 2;
795 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
796 }
797 }
798
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100799 case Primitive::kPrimFloat: {
800 uint32_t index = fp_index_++;
801 stack_index_++;
802 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100803 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100804 } else {
805 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
806 }
807 }
808
809 case Primitive::kPrimDouble: {
810 uint32_t index = fp_index_++;
811 stack_index_ += 2;
812 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100813 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100814 } else {
815 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
816 }
817 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100818
819 case Primitive::kPrimVoid:
820 LOG(FATAL) << "Unexpected parameter type " << type;
821 break;
822 }
823 return Location();
824}
825
826void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100827 HandleInvoke(invoke);
828}
829
830void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100831 CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100832 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
833 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
834 invoke->GetIndexInDexCache() * heap_reference_size;
835
836 // TODO: Implement all kinds of calls:
837 // 1) boot -> boot
838 // 2) app -> boot
839 // 3) app -> app
840 //
841 // Currently we implement the app -> app logic, which looks up in the resolve cache.
842
843 // temp = method;
844 LoadCurrentMethod(temp);
845 // temp = temp->dex_cache_resolved_methods_;
846 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
847 // temp = temp[index_in_cache]
848 __ movl(temp, Address(temp, index_in_cache));
849 // (temp + offset_of_quick_compiled_code)()
850 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
851
852 DCHECK(!codegen_->IsLeafMethod());
853 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
854}
855
856void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
857 HandleInvoke(invoke);
858}
859
860void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100861 LocationSummary* locations =
862 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100863 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100864
865 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100866 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100867 HInstruction* input = invoke->InputAt(i);
868 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
869 }
870
871 switch (invoke->GetType()) {
872 case Primitive::kPrimBoolean:
873 case Primitive::kPrimByte:
874 case Primitive::kPrimChar:
875 case Primitive::kPrimShort:
876 case Primitive::kPrimInt:
877 case Primitive::kPrimNot:
878 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100879 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100880 break;
881
882 case Primitive::kPrimVoid:
883 break;
884
885 case Primitive::kPrimDouble:
886 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100887 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100888 break;
889 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100890}
891
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100892void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100893 CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100894 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
895 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
896 LocationSummary* locations = invoke->GetLocations();
897 Location receiver = locations->InAt(0);
898 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
899 // temp = object->GetClass();
900 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100901 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
902 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100903 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100904 __ movl(temp, Address(receiver.As<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100905 }
906 // temp = temp->GetMethodAt(method_offset);
907 __ movl(temp, Address(temp, method_offset));
908 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100909 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
910
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100911 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100912 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100913}
914
915void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100916 LocationSummary* locations =
917 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100918 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100919 case Primitive::kPrimInt: {
920 locations->SetInAt(0, Location::RequiresRegister());
921 locations->SetInAt(1, Location::Any());
922 locations->SetOut(Location::SameAsFirstInput());
923 break;
924 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100925
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100926 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000927 locations->SetInAt(0, Location::RequiresRegister());
928 locations->SetInAt(1, Location::RequiresRegister());
929 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100930 break;
931 }
932
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100933 case Primitive::kPrimDouble:
934 case Primitive::kPrimFloat: {
935 locations->SetInAt(0, Location::RequiresFpuRegister());
936 locations->SetInAt(1, Location::Any());
937 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100938 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100939 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940
941 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100942 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100944}
945
946void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
947 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100948 Location first = locations->InAt(0);
949 Location second = locations->InAt(1);
950
951 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100952 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000953 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100954 if (second.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100955 __ addl(first.As<CpuRegister>(), second.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100956 } else if (second.IsConstant()) {
957 HConstant* instruction = second.GetConstant();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100958 Immediate imm(instruction->AsIntConstant()->GetValue());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100959 __ addl(first.As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100960 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100961 __ addl(first.As<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100962 Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100963 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000964 break;
965 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100966
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100967 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100968 __ addq(first.As<CpuRegister>(), second.As<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100969 break;
970 }
971
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100972 case Primitive::kPrimFloat: {
973 if (second.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100974 __ addss(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100975 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100976 __ addss(first.As<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100977 Address(CpuRegister(RSP), second.GetStackIndex()));
978 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100979 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100980 }
981
982 case Primitive::kPrimDouble: {
983 if (second.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100984 __ addsd(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100985 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100986 __ addsd(first.As<XmmRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100987 }
988 break;
989 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100990
991 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100992 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100993 }
994}
995
996void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100997 LocationSummary* locations =
998 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100999 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001000 case Primitive::kPrimInt: {
1001 locations->SetInAt(0, Location::RequiresRegister());
1002 locations->SetInAt(1, Location::Any());
1003 locations->SetOut(Location::SameAsFirstInput());
1004 break;
1005 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001006 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001007 locations->SetInAt(0, Location::RequiresRegister());
1008 locations->SetInAt(1, Location::RequiresRegister());
1009 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001010 break;
1011 }
1012
1013 case Primitive::kPrimBoolean:
1014 case Primitive::kPrimByte:
1015 case Primitive::kPrimChar:
1016 case Primitive::kPrimShort:
1017 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1018 break;
1019
1020 default:
1021 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1022 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001023}
1024
1025void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1026 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001027 DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
1028 locations->Out().As<CpuRegister>().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001029 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001030 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001032 __ subl(locations->InAt(0).As<CpuRegister>(),
1033 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001034 } else if (locations->InAt(1).IsConstant()) {
1035 HConstant* instruction = locations->InAt(1).GetConstant();
1036 Immediate imm(instruction->AsIntConstant()->GetValue());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001037 __ subl(locations->InAt(0).As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001038 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001039 __ subl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001040 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
1041 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001042 break;
1043 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001044 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001045 __ subq(locations->InAt(0).As<CpuRegister>(),
1046 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001047 break;
1048 }
1049
1050 case Primitive::kPrimBoolean:
1051 case Primitive::kPrimByte:
1052 case Primitive::kPrimChar:
1053 case Primitive::kPrimShort:
1054 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1055 break;
1056
1057 default:
1058 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1059 }
1060}
1061
1062void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001063 LocationSummary* locations =
1064 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001065 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001066 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1067 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1068 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001069}
1070
1071void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
1072 InvokeRuntimeCallingConvention calling_convention;
1073 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
1074 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
1075
1076 __ gs()->call(Address::Absolute(
1077 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
1078
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001079 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001080 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001081}
1082
1083void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001084 LocationSummary* locations =
1085 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001086 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1087 if (location.IsStackSlot()) {
1088 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1089 } else if (location.IsDoubleStackSlot()) {
1090 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1091 }
1092 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001093}
1094
1095void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
1096 // Nothing to do, the parameter is already at its location.
1097}
1098
1099void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001100 LocationSummary* locations =
1101 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001102 locations->SetInAt(0, Location::RequiresRegister());
1103 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001104}
1105
1106void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
1107 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001108 DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
1109 locations->Out().As<CpuRegister>().AsRegister());
1110 __ xorq(locations->Out().As<CpuRegister>(), Immediate(1));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001111}
1112
1113void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001114 LocationSummary* locations =
1115 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001116 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1117 locations->SetInAt(i, Location::Any());
1118 }
1119 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001120}
1121
1122void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
1123 LOG(FATAL) << "Unimplemented";
1124}
1125
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001126void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001127 LocationSummary* locations =
1128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001129 Primitive::Type field_type = instruction->GetFieldType();
1130 bool is_object_type = field_type == Primitive::kPrimNot;
1131 bool dies_at_entry = !is_object_type;
1132 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1133 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
1134 if (is_object_type) {
1135 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001136 locations->AddTemp(Location::RequiresRegister());
1137 locations->AddTemp(Location::RequiresRegister());
1138 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001139}
1140
1141void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1142 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001143 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
1144 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001145 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001146 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001147
1148 switch (field_type) {
1149 case Primitive::kPrimBoolean:
1150 case Primitive::kPrimByte: {
1151 __ movb(Address(obj, offset), value);
1152 break;
1153 }
1154
1155 case Primitive::kPrimShort:
1156 case Primitive::kPrimChar: {
1157 __ movw(Address(obj, offset), value);
1158 break;
1159 }
1160
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001161 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001162 case Primitive::kPrimNot: {
1163 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001164 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001165 CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
1166 CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001167 codegen_->MarkGCCard(temp, card, obj, value);
1168 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001169 break;
1170 }
1171
1172 case Primitive::kPrimLong: {
1173 __ movq(Address(obj, offset), value);
1174 break;
1175 }
1176
1177 case Primitive::kPrimFloat:
1178 case Primitive::kPrimDouble:
1179 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001180 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001181 case Primitive::kPrimVoid:
1182 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001183 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001184 }
1185}
1186
1187void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001188 LocationSummary* locations =
1189 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001190 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001191 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001192}
1193
1194void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1195 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001196 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
1197 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001198 size_t offset = instruction->GetFieldOffset().SizeValue();
1199
1200 switch (instruction->GetType()) {
1201 case Primitive::kPrimBoolean: {
1202 __ movzxb(out, Address(obj, offset));
1203 break;
1204 }
1205
1206 case Primitive::kPrimByte: {
1207 __ movsxb(out, Address(obj, offset));
1208 break;
1209 }
1210
1211 case Primitive::kPrimShort: {
1212 __ movsxw(out, Address(obj, offset));
1213 break;
1214 }
1215
1216 case Primitive::kPrimChar: {
1217 __ movzxw(out, Address(obj, offset));
1218 break;
1219 }
1220
1221 case Primitive::kPrimInt:
1222 case Primitive::kPrimNot: {
1223 __ movl(out, Address(obj, offset));
1224 break;
1225 }
1226
1227 case Primitive::kPrimLong: {
1228 __ movq(out, Address(obj, offset));
1229 break;
1230 }
1231
1232 case Primitive::kPrimFloat:
1233 case Primitive::kPrimDouble:
1234 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001235 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001236 case Primitive::kPrimVoid:
1237 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001238 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001239 }
1240}
1241
1242void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001243 LocationSummary* locations =
1244 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001245 locations->SetInAt(0, Location::Any());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001246 if (instruction->HasUses()) {
1247 locations->SetOut(Location::SameAsFirstInput());
1248 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001249}
1250
1251void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001252 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001253 codegen_->AddSlowPath(slow_path);
1254
1255 LocationSummary* locations = instruction->GetLocations();
1256 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001257
1258 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001259 __ cmpl(obj.As<CpuRegister>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001260 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001261 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001262 } else {
1263 DCHECK(obj.IsConstant()) << obj;
1264 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1265 __ jmp(slow_path->GetEntryLabel());
1266 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001267 }
1268 __ j(kEqual, slow_path->GetEntryLabel());
1269}
1270
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001271void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001272 LocationSummary* locations =
1273 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001274 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1275 locations->SetInAt(
1276 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001277 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001278}
1279
1280void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1281 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001282 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001283 Location index = locations->InAt(1);
1284
1285 switch (instruction->GetType()) {
1286 case Primitive::kPrimBoolean: {
1287 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001288 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001289 if (index.IsConstant()) {
1290 __ movzxb(out, Address(obj,
1291 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1292 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001293 __ movzxb(out, Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001294 }
1295 break;
1296 }
1297
1298 case Primitive::kPrimByte: {
1299 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001300 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001301 if (index.IsConstant()) {
1302 __ movsxb(out, Address(obj,
1303 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1304 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001305 __ movsxb(out, Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001306 }
1307 break;
1308 }
1309
1310 case Primitive::kPrimShort: {
1311 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001312 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001313 if (index.IsConstant()) {
1314 __ movsxw(out, Address(obj,
1315 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1316 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001317 __ movsxw(out, Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001318 }
1319 break;
1320 }
1321
1322 case Primitive::kPrimChar: {
1323 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001324 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001325 if (index.IsConstant()) {
1326 __ movzxw(out, Address(obj,
1327 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1328 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001329 __ movzxw(out, Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001330 }
1331 break;
1332 }
1333
1334 case Primitive::kPrimInt:
1335 case Primitive::kPrimNot: {
1336 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1337 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001338 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001339 if (index.IsConstant()) {
1340 __ movl(out, Address(obj,
1341 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1342 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001343 __ movl(out, Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001344 }
1345 break;
1346 }
1347
1348 case Primitive::kPrimLong: {
1349 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001350 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001351 if (index.IsConstant()) {
1352 __ movq(out, Address(obj,
1353 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1354 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001355 __ movq(out, Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001356 }
1357 break;
1358 }
1359
1360 case Primitive::kPrimFloat:
1361 case Primitive::kPrimDouble:
1362 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001363 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001364 case Primitive::kPrimVoid:
1365 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001366 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001367 }
1368}
1369
1370void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001371 Primitive::Type value_type = instruction->GetComponentType();
1372 bool is_object = value_type == Primitive::kPrimNot;
1373 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1374 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1375 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001376 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001377 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1378 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1379 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001380 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001381 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1382 locations->SetInAt(
1383 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1384 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001385 if (value_type == Primitive::kPrimLong) {
1386 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
1387 } else {
1388 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), Location::kDiesAtEntry);
1389 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001390 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001391}
1392
1393void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1394 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001395 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001396 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001397 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001398 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001399
1400 switch (value_type) {
1401 case Primitive::kPrimBoolean:
1402 case Primitive::kPrimByte: {
1403 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001404 if (index.IsConstant()) {
1405 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001406 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001407 __ movb(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001408 } else {
1409 __ movb(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1410 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001411 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001412 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001413 __ movb(Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset),
1414 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001415 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001416 __ movb(Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001417 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1418 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001419 }
1420 break;
1421 }
1422
1423 case Primitive::kPrimShort:
1424 case Primitive::kPrimChar: {
1425 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001426 if (index.IsConstant()) {
1427 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001428 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001429 __ movw(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001430 } else {
1431 __ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1432 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001433 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001434 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001435 __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
1436 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001437 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001438 __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001439 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1440 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001441 }
1442 break;
1443 }
1444
1445 case Primitive::kPrimInt: {
1446 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001447 if (index.IsConstant()) {
1448 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001449 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001450 __ movl(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001451 } else {
1452 __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1453 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001454 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001455 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001456 __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
1457 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001458 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001459 __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001460 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1461 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001462 }
1463 break;
1464 }
1465
1466 case Primitive::kPrimNot: {
1467 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1468 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001469 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001470 break;
1471 }
1472
1473 case Primitive::kPrimLong: {
1474 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001475 if (index.IsConstant()) {
1476 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001477 DCHECK(value.IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001478 __ movq(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001479 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001480 DCHECK(value.IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001481 __ movq(Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset),
1482 value.As<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001483 }
1484 break;
1485 }
1486
1487 case Primitive::kPrimFloat:
1488 case Primitive::kPrimDouble:
1489 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001490 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001491 case Primitive::kPrimVoid:
1492 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001493 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001494 }
1495}
1496
1497void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001498 LocationSummary* locations =
1499 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001500 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001501 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001502}
1503
1504void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1505 LocationSummary* locations = instruction->GetLocations();
1506 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001507 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
1508 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001509 __ movl(out, Address(obj, offset));
1510}
1511
1512void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001513 LocationSummary* locations =
1514 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001515 locations->SetInAt(0, Location::RequiresRegister());
1516 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001517 if (instruction->HasUses()) {
1518 locations->SetOut(Location::SameAsFirstInput());
1519 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001520}
1521
1522void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1523 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001524 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001525 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001526 codegen_->AddSlowPath(slow_path);
1527
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001528 CpuRegister index = locations->InAt(0).As<CpuRegister>();
1529 CpuRegister length = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001530
1531 __ cmpl(index, length);
1532 __ j(kAboveEqual, slow_path->GetEntryLabel());
1533}
1534
1535void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1536 CpuRegister card,
1537 CpuRegister object,
1538 CpuRegister value) {
1539 Label is_null;
1540 __ testl(value, value);
1541 __ j(kEqual, &is_null);
1542 __ gs()->movq(card, Address::Absolute(
1543 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1544 __ movq(temp, object);
1545 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1546 __ movb(Address(temp, card, TIMES_1, 0), card);
1547 __ Bind(&is_null);
1548}
1549
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001550void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1551 temp->SetLocations(nullptr);
1552}
1553
1554void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1555 // Nothing to do, this is driven by the code generator.
1556}
1557
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001558void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1559 LOG(FATAL) << "Unimplemented";
1560}
1561
1562void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001563 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1564}
1565
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001566void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
1567 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1568}
1569
1570void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001571 HBasicBlock* block = instruction->GetBlock();
1572 if (block->GetLoopInformation() != nullptr) {
1573 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1574 // The back edge will generate the suspend check.
1575 return;
1576 }
1577 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1578 // The goto will generate the suspend check.
1579 return;
1580 }
1581 GenerateSuspendCheck(instruction, nullptr);
1582}
1583
1584void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
1585 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001586 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001587 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001588 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001589 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001590 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001591 if (successor == nullptr) {
1592 __ j(kNotEqual, slow_path->GetEntryLabel());
1593 __ Bind(slow_path->GetReturnLabel());
1594 } else {
1595 __ j(kEqual, codegen_->GetLabelOf(successor));
1596 __ jmp(slow_path->GetEntryLabel());
1597 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001598}
1599
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001600X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1601 return codegen_->GetAssembler();
1602}
1603
1604void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1605 MoveOperands* move = moves_.Get(index);
1606 Location source = move->GetSource();
1607 Location destination = move->GetDestination();
1608
1609 if (source.IsRegister()) {
1610 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001611 __ movq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001612 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001613 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001614 source.As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001615 } else {
1616 DCHECK(destination.IsDoubleStackSlot());
1617 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001618 source.As<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001619 }
1620 } else if (source.IsStackSlot()) {
1621 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001622 __ movl(destination.As<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001623 Address(CpuRegister(RSP), source.GetStackIndex()));
1624 } else {
1625 DCHECK(destination.IsStackSlot());
1626 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1627 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1628 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001629 } else if (source.IsDoubleStackSlot()) {
1630 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001631 __ movq(destination.As<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001632 Address(CpuRegister(RSP), source.GetStackIndex()));
1633 } else {
1634 DCHECK(destination.IsDoubleStackSlot());
1635 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1636 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1637 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001638 } else if (source.IsConstant()) {
1639 HConstant* constant = source.GetConstant();
1640 if (constant->IsIntConstant()) {
1641 Immediate imm(constant->AsIntConstant()->GetValue());
1642 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001643 __ movl(destination.As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001644 } else {
1645 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1646 }
1647 } else if (constant->IsLongConstant()) {
1648 int64_t value = constant->AsLongConstant()->GetValue();
1649 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001650 __ movq(destination.As<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001651 } else {
1652 __ movq(CpuRegister(TMP), Immediate(value));
1653 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1654 }
1655 } else {
1656 LOG(FATAL) << "Unimplemented constant type";
1657 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001658 } else {
1659 LOG(FATAL) << "Unimplemented";
1660 }
1661}
1662
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001663void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001664 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001665 __ movl(Address(CpuRegister(RSP), mem), reg);
1666 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001667}
1668
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001669void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001670 ScratchRegisterScope ensure_scratch(
1671 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1672
1673 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1674 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1675 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1676 Address(CpuRegister(RSP), mem2 + stack_offset));
1677 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1678 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1679 CpuRegister(ensure_scratch.GetRegister()));
1680}
1681
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001682void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1683 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1684 __ movq(Address(CpuRegister(RSP), mem), reg);
1685 __ movq(reg, CpuRegister(TMP));
1686}
1687
1688void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1689 ScratchRegisterScope ensure_scratch(
1690 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1691
1692 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1693 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1694 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1695 Address(CpuRegister(RSP), mem2 + stack_offset));
1696 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1697 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1698 CpuRegister(ensure_scratch.GetRegister()));
1699}
1700
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001701void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1702 MoveOperands* move = moves_.Get(index);
1703 Location source = move->GetSource();
1704 Location destination = move->GetDestination();
1705
1706 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001707 __ xchgq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001708 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001709 Exchange32(source.As<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001710 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001711 Exchange32(destination.As<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001712 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001713 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1714 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001715 Exchange64(source.As<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001716 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001717 Exchange64(destination.As<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001718 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1719 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001720 } else {
1721 LOG(FATAL) << "Unimplemented";
1722 }
1723}
1724
1725
1726void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1727 __ pushq(CpuRegister(reg));
1728}
1729
1730
1731void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1732 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001733}
1734
1735} // namespace x86_64
1736} // namespace art