blob: 5aa1c4a6c8c752bc385ff6a63f48493bbe9068d7 [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
Calin Juravled0d48522014-11-04 16:40:20 +000093class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
94 public:
95 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
96
97 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
98 __ Bind(GetEntryLabel());
99 __ gs()->call(
100 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
101 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
102 }
103
104 private:
105 HDivZeroCheck* const instruction_;
106 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
107};
108
109class DivMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
110 public:
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000111 explicit DivMinusOneSlowPathX86_64(Register reg, Primitive::Type type)
112 : reg_(reg), type_(type) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000113
114 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
115 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000116 if (type_ == Primitive::kPrimInt) {
117 __ negl(CpuRegister(reg_));
118 } else {
119 DCHECK_EQ(Primitive::kPrimLong, type_);
120 __ negq(CpuRegister(reg_));
121 }
Calin Juravled0d48522014-11-04 16:40:20 +0000122 __ jmp(GetExitLabel());
123 }
124
125 private:
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 const Register reg_;
127 const Primitive::Type type_;
Calin Juravled0d48522014-11-04 16:40:20 +0000128 DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86_64);
129};
130
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100131class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100132 public:
133 StackOverflowCheckSlowPathX86_64() {}
134
135 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
136 __ Bind(GetEntryLabel());
137 __ addq(CpuRegister(RSP),
138 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
139 __ gs()->jmp(
140 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
141 }
142
143 private:
144 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
145};
146
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100147class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100149 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
150 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000151
152 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100153 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100155 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
157 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100158 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100159 if (successor_ == nullptr) {
160 __ jmp(GetReturnLabel());
161 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100162 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100163 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000164 }
165
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100166 Label* GetReturnLabel() {
167 DCHECK(successor_ == nullptr);
168 return &return_label_;
169 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000170
171 private:
172 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100173 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000174 Label return_label_;
175
176 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
177};
178
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100179class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100181 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
182 Location index_location,
183 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100184 : instruction_(instruction),
185 index_location_(index_location),
186 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187
188 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000190 // We're moving two locations to locations that could overlap, so we need a parallel
191 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100192 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000193 codegen->EmitParallelMoves(
194 index_location_,
195 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
196 length_location_,
197 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100198 __ gs()->call(Address::Absolute(
199 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100200 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100201 }
202
203 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100204 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100205 const Location index_location_;
206 const Location length_location_;
207
208 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
209};
210
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213 LoadClassSlowPathX86_64(HLoadClass* cls,
214 HInstruction* at,
215 uint32_t dex_pc,
216 bool do_clinit)
217 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
218 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
219 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100220
221 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000222 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100223 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
224 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100225
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226 codegen->SaveLiveRegisters(locations);
227
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000229 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000231 __ gs()->call(Address::Absolute((do_clinit_
232 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
233 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
234 codegen->RecordPcInfo(at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000236 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000238 if (out.IsValid()) {
239 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
240 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000241 }
242
243 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100244 __ jmp(GetExitLabel());
245 }
246
247 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000248 // The class this slow path will load.
249 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100250
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000251 // The instruction where this slow path is happening.
252 // (Might be the load class or an initialization check).
253 HInstruction* const at_;
254
255 // The dex PC of `at_`.
256 const uint32_t dex_pc_;
257
258 // Whether to initialize the class.
259 const bool do_clinit_;
260
261 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100262};
263
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000264class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
265 public:
266 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
267
268 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
269 LocationSummary* locations = instruction_->GetLocations();
270 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
271
272 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
273 __ Bind(GetEntryLabel());
274 codegen->SaveLiveRegisters(locations);
275
276 InvokeRuntimeCallingConvention calling_convention;
277 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(0)));
278 __ movl(CpuRegister(calling_convention.GetRegisterAt(1)),
279 Immediate(instruction_->GetStringIndex()));
280 __ gs()->call(Address::Absolute(
281 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
282 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
283 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
284 codegen->RestoreLiveRegisters(locations);
285 __ jmp(GetExitLabel());
286 }
287
288 private:
289 HLoadString* const instruction_;
290
291 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
292};
293
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
295 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000296 TypeCheckSlowPathX86_64(HInstruction* instruction,
297 Location class_to_check,
298 Location object_class,
299 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000300 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000301 class_to_check_(class_to_check),
302 object_class_(object_class),
303 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000304
305 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
306 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000307 DCHECK(instruction_->IsCheckCast()
308 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000309
310 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
311 __ Bind(GetEntryLabel());
312 codegen->SaveLiveRegisters(locations);
313
314 // We're moving two locations to locations that could overlap, so we need a parallel
315 // move resolver.
316 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000317 codegen->EmitParallelMoves(
318 class_to_check_,
319 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
320 object_class_,
321 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000322
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000323 if (instruction_->IsInstanceOf()) {
324 __ gs()->call(
325 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
326 } else {
327 DCHECK(instruction_->IsCheckCast());
328 __ gs()->call(
329 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
330 }
331 codegen->RecordPcInfo(instruction_, dex_pc_);
332
333 if (instruction_->IsInstanceOf()) {
334 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
335 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000336
337 codegen->RestoreLiveRegisters(locations);
338 __ jmp(GetExitLabel());
339 }
340
341 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000342 HInstruction* const instruction_;
343 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000344 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000345 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000346
347 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
348};
349
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100350#undef __
351#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
352
Dave Allison20dfc792014-06-16 20:44:29 -0700353inline Condition X86_64Condition(IfCondition cond) {
354 switch (cond) {
355 case kCondEQ: return kEqual;
356 case kCondNE: return kNotEqual;
357 case kCondLT: return kLess;
358 case kCondLE: return kLessEqual;
359 case kCondGT: return kGreater;
360 case kCondGE: return kGreaterEqual;
361 default:
362 LOG(FATAL) << "Unknown if condition";
363 }
364 return kEqual;
365}
366
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100367void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
368 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
369}
370
371void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
372 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
373}
374
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100375size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
376 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
377 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100378}
379
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100380size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
381 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
382 return kX86_64WordSize;
383}
384
385size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
386 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
387 return kX86_64WordSize;
388}
389
390size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
391 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
392 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100393}
394
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100395CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100396 : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100397 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000399 instruction_visitor_(graph, this),
400 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100401
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100402size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
403 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
404}
405
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100406InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
407 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100408 : HGraphVisitor(graph),
409 assembler_(codegen->GetAssembler()),
410 codegen_(codegen) {}
411
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100412Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100413 switch (type) {
414 case Primitive::kPrimLong:
415 case Primitive::kPrimByte:
416 case Primitive::kPrimBoolean:
417 case Primitive::kPrimChar:
418 case Primitive::kPrimShort:
419 case Primitive::kPrimInt:
420 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100421 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100422 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100423 }
424
425 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100426 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100427 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100428 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100429 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100430
431 case Primitive::kPrimVoid:
432 LOG(FATAL) << "Unreachable type " << type;
433 }
434
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100435 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100436}
437
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100438void CodeGeneratorX86_64::SetupBlockedRegisters() const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100439 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100440 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100441
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000442 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100443 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000444
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100445 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100446 blocked_core_registers_[RBX] = true;
447 blocked_core_registers_[RBP] = true;
448 blocked_core_registers_[R12] = true;
449 blocked_core_registers_[R13] = true;
450 blocked_core_registers_[R14] = true;
451 blocked_core_registers_[R15] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100452
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100453 blocked_fpu_registers_[XMM12] = true;
454 blocked_fpu_registers_[XMM13] = true;
455 blocked_fpu_registers_[XMM14] = true;
456 blocked_fpu_registers_[XMM15] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100457}
458
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100459void CodeGeneratorX86_64::GenerateFrameEntry() {
460 // Create a fake register to mimic Quick.
461 static const int kFakeReturnRegister = 16;
462 core_spill_mask_ |= (1 << kFakeReturnRegister);
463
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100464 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700465 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100466
467 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
468 __ testq(CpuRegister(RAX), Address(
469 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100470 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100471 }
472
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100473 // The return PC has already been pushed on the stack.
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100474 __ subq(CpuRegister(RSP),
475 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
476
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100477 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100478 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100479 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100480
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100481 __ gs()->cmpq(CpuRegister(RSP),
482 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
483 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100484 }
485
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100486 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
487}
488
489void CodeGeneratorX86_64::GenerateFrameExit() {
490 __ addq(CpuRegister(RSP),
491 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
492}
493
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100494void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
495 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100496}
497
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100498void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100499 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
500}
501
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100502Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
503 switch (load->GetType()) {
504 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100505 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100506 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
507 break;
508
509 case Primitive::kPrimInt:
510 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100511 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100512 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100513
514 case Primitive::kPrimBoolean:
515 case Primitive::kPrimByte:
516 case Primitive::kPrimChar:
517 case Primitive::kPrimShort:
518 case Primitive::kPrimVoid:
519 LOG(FATAL) << "Unexpected type " << load->GetType();
520 }
521
522 LOG(FATAL) << "Unreachable";
523 return Location();
524}
525
526void CodeGeneratorX86_64::Move(Location destination, Location source) {
527 if (source.Equals(destination)) {
528 return;
529 }
530 if (destination.IsRegister()) {
531 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100532 __ movq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100533 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100534 __ movd(destination.As<CpuRegister>(), source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100535 } else if (source.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100536 __ movl(destination.As<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100537 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100538 } else {
539 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100540 __ movq(destination.As<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100541 Address(CpuRegister(RSP), source.GetStackIndex()));
542 }
543 } else if (destination.IsFpuRegister()) {
544 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100545 __ movd(destination.As<XmmRegister>(), source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100546 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100547 __ movaps(destination.As<XmmRegister>(), source.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100548 } else if (source.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100549 __ movss(destination.As<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100550 Address(CpuRegister(RSP), source.GetStackIndex()));
551 } else {
552 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100553 __ movsd(destination.As<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100554 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100555 }
556 } else if (destination.IsStackSlot()) {
557 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100558 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100559 source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100560 } else if (source.IsFpuRegister()) {
561 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100562 source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100563 } else {
564 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000565 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
566 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100567 }
568 } else {
569 DCHECK(destination.IsDoubleStackSlot());
570 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100571 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100572 source.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100573 } else if (source.IsFpuRegister()) {
574 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100575 source.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100576 } else {
577 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000578 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
579 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100580 }
581 }
582}
583
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100584void CodeGeneratorX86_64::Move(HInstruction* instruction,
585 Location location,
586 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000587 LocationSummary* locations = instruction->GetLocations();
588 if (locations != nullptr && locations->Out().Equals(location)) {
589 return;
590 }
591
592 if (locations != nullptr && locations->Out().IsConstant()) {
593 HConstant* const_to_move = locations->Out().GetConstant();
594 if (const_to_move->IsIntConstant()) {
595 Immediate imm(const_to_move->AsIntConstant()->GetValue());
596 if (location.IsRegister()) {
597 __ movl(location.As<CpuRegister>(), imm);
598 } else if (location.IsStackSlot()) {
599 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
600 } else {
601 DCHECK(location.IsConstant());
602 DCHECK_EQ(location.GetConstant(), const_to_move);
603 }
604 } else if (const_to_move->IsLongConstant()) {
605 int64_t value = const_to_move->AsLongConstant()->GetValue();
606 if (location.IsRegister()) {
607 __ movq(location.As<CpuRegister>(), Immediate(value));
608 } else if (location.IsDoubleStackSlot()) {
609 __ movq(CpuRegister(TMP), Immediate(value));
610 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
611 } else {
612 DCHECK(location.IsConstant());
613 DCHECK_EQ(location.GetConstant(), const_to_move);
614 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615 }
Roland Levillain476df552014-10-09 17:51:36 +0100616 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100617 switch (instruction->GetType()) {
618 case Primitive::kPrimBoolean:
619 case Primitive::kPrimByte:
620 case Primitive::kPrimChar:
621 case Primitive::kPrimShort:
622 case Primitive::kPrimInt:
623 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100624 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100625 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
626 break;
627
628 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100629 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100630 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
631 break;
632
633 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100634 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100635 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000636 } else if (instruction->IsTemporary()) {
637 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
638 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100639 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100640 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100641 switch (instruction->GetType()) {
642 case Primitive::kPrimBoolean:
643 case Primitive::kPrimByte:
644 case Primitive::kPrimChar:
645 case Primitive::kPrimShort:
646 case Primitive::kPrimInt:
647 case Primitive::kPrimNot:
648 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100649 case Primitive::kPrimFloat:
650 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000651 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100652 break;
653
654 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100655 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100656 }
657 }
658}
659
660void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
661 got->SetLocations(nullptr);
662}
663
664void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
665 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100666 DCHECK(!successor->IsExitBlock());
667
668 HBasicBlock* block = got->GetBlock();
669 HInstruction* previous = got->GetPrevious();
670
671 HLoopInformation* info = block->GetLoopInformation();
672 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
673 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
674 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
675 return;
676 }
677
678 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
679 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
680 }
681 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100682 __ jmp(codegen_->GetLabelOf(successor));
683 }
684}
685
686void LocationsBuilderX86_64::VisitExit(HExit* exit) {
687 exit->SetLocations(nullptr);
688}
689
690void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700691 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100692 if (kIsDebugBuild) {
693 __ Comment("Unreachable");
694 __ int3();
695 }
696}
697
698void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100699 LocationSummary* locations =
700 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100701 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100702 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100703 locations->SetInAt(0, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100704 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100705}
706
707void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700708 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100709 if (cond->IsIntConstant()) {
710 // Constant condition, statically compared against 1.
711 int32_t cond_value = cond->AsIntConstant()->GetValue();
712 if (cond_value == 1) {
713 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
714 if_instr->IfTrueSuccessor())) {
715 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100716 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100717 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100718 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100719 DCHECK_EQ(cond_value, 0);
720 }
721 } else {
722 bool materialized =
723 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
724 // Moves do not affect the eflags register, so if the condition is
725 // evaluated just before the if, we don't need to evaluate it
726 // again.
727 bool eflags_set = cond->IsCondition()
728 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
729 if (materialized) {
730 if (!eflags_set) {
731 // Materialized condition, compare against 0.
732 Location lhs = if_instr->GetLocations()->InAt(0);
733 if (lhs.IsRegister()) {
734 __ cmpl(lhs.As<CpuRegister>(), Immediate(0));
735 } else {
736 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
737 Immediate(0));
738 }
739 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
740 } else {
741 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
742 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
743 }
744 } else {
745 Location lhs = cond->GetLocations()->InAt(0);
746 Location rhs = cond->GetLocations()->InAt(1);
747 if (rhs.IsRegister()) {
748 __ cmpl(lhs.As<CpuRegister>(), rhs.As<CpuRegister>());
749 } else if (rhs.IsConstant()) {
750 __ cmpl(lhs.As<CpuRegister>(),
751 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
752 } else {
753 __ cmpl(lhs.As<CpuRegister>(),
754 Address(CpuRegister(RSP), rhs.GetStackIndex()));
755 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100756 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
757 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700758 }
Dave Allison20dfc792014-06-16 20:44:29 -0700759 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100760 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
761 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700762 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100763 }
764}
765
766void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
767 local->SetLocations(nullptr);
768}
769
770void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
771 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
772}
773
774void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
775 local->SetLocations(nullptr);
776}
777
778void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
779 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700780 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100781}
782
783void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100784 LocationSummary* locations =
785 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100786 switch (store->InputAt(1)->GetType()) {
787 case Primitive::kPrimBoolean:
788 case Primitive::kPrimByte:
789 case Primitive::kPrimChar:
790 case Primitive::kPrimShort:
791 case Primitive::kPrimInt:
792 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100793 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100794 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
795 break;
796
797 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100798 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100799 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
800 break;
801
802 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100803 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100804 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100805}
806
807void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700808 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100809}
810
Dave Allison20dfc792014-06-16 20:44:29 -0700811void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100812 LocationSummary* locations =
813 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100814 locations->SetInAt(0, Location::RequiresRegister());
815 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100816 if (comp->NeedsMaterialization()) {
817 locations->SetOut(Location::RequiresRegister());
818 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100819}
820
Dave Allison20dfc792014-06-16 20:44:29 -0700821void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
822 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100823 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100824 CpuRegister reg = locations->Out().As<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100825 // Clear register: setcc only sets the low byte.
826 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100827 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100828 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100829 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100830 } else if (locations->InAt(1).IsConstant()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100831 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100832 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
833 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100834 __ cmpl(locations->InAt(0).As<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100835 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
836 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100837 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700838 }
839}
840
841void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
842 VisitCondition(comp);
843}
844
845void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
846 VisitCondition(comp);
847}
848
849void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
850 VisitCondition(comp);
851}
852
853void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
854 VisitCondition(comp);
855}
856
857void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
858 VisitCondition(comp);
859}
860
861void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
862 VisitCondition(comp);
863}
864
865void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
866 VisitCondition(comp);
867}
868
869void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
870 VisitCondition(comp);
871}
872
873void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
874 VisitCondition(comp);
875}
876
877void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
878 VisitCondition(comp);
879}
880
881void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
882 VisitCondition(comp);
883}
884
885void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
886 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887}
888
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100889void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100890 LocationSummary* locations =
891 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100892 locations->SetInAt(0, Location::RequiresRegister());
893 locations->SetInAt(1, Location::RequiresRegister());
894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100895}
896
897void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
898 Label greater, done;
899 LocationSummary* locations = compare->GetLocations();
900 switch (compare->InputAt(0)->GetType()) {
901 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100902 __ cmpq(locations->InAt(0).As<CpuRegister>(),
903 locations->InAt(1).As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100904 break;
905 default:
906 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
907 }
908
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100909 CpuRegister output = locations->Out().As<CpuRegister>();
910 __ movl(output, Immediate(0));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100911 __ j(kEqual, &done);
912 __ j(kGreater, &greater);
913
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100914 __ movl(output, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100915 __ jmp(&done);
916
917 __ Bind(&greater);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100918 __ movl(output, Immediate(1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100919
920 __ Bind(&done);
921}
922
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100923void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100924 LocationSummary* locations =
925 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100926 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100927}
928
929void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100930 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700931 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100932}
933
934void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100935 LocationSummary* locations =
936 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100937 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100938}
939
940void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100941 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700942 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943}
944
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100945void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
946 LocationSummary* locations =
947 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
948 locations->SetOut(Location::ConstantLocation(constant));
949}
950
951void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
952 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700953 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100954}
955
956void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
957 LocationSummary* locations =
958 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
959 locations->SetOut(Location::ConstantLocation(constant));
960}
961
962void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
963 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700964 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100965}
966
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100967void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
968 ret->SetLocations(nullptr);
969}
970
971void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700972 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100973 codegen_->GenerateFrameExit();
974 __ ret();
975}
976
977void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100978 LocationSummary* locations =
979 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100980 switch (ret->InputAt(0)->GetType()) {
981 case Primitive::kPrimBoolean:
982 case Primitive::kPrimByte:
983 case Primitive::kPrimChar:
984 case Primitive::kPrimShort:
985 case Primitive::kPrimInt:
986 case Primitive::kPrimNot:
987 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100988 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100989 break;
990
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100991 case Primitive::kPrimFloat:
992 case Primitive::kPrimDouble:
993 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100994 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100995 break;
996
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100997 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100998 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100999 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001000}
1001
1002void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1003 if (kIsDebugBuild) {
1004 switch (ret->InputAt(0)->GetType()) {
1005 case Primitive::kPrimBoolean:
1006 case Primitive::kPrimByte:
1007 case Primitive::kPrimChar:
1008 case Primitive::kPrimShort:
1009 case Primitive::kPrimInt:
1010 case Primitive::kPrimNot:
1011 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001012 DCHECK_EQ(ret->GetLocations()->InAt(0).As<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001013 break;
1014
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001015 case Primitive::kPrimFloat:
1016 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001017 DCHECK_EQ(ret->GetLocations()->InAt(0).As<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001018 XMM0);
1019 break;
1020
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001021 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001022 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001023 }
1024 }
1025 codegen_->GenerateFrameExit();
1026 __ ret();
1027}
1028
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001029Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1030 switch (type) {
1031 case Primitive::kPrimBoolean:
1032 case Primitive::kPrimByte:
1033 case Primitive::kPrimChar:
1034 case Primitive::kPrimShort:
1035 case Primitive::kPrimInt:
1036 case Primitive::kPrimNot: {
1037 uint32_t index = gp_index_++;
1038 stack_index_++;
1039 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001040 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001041 } else {
1042 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1043 }
1044 }
1045
1046 case Primitive::kPrimLong: {
1047 uint32_t index = gp_index_;
1048 stack_index_ += 2;
1049 if (index < calling_convention.GetNumberOfRegisters()) {
1050 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001051 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001052 } else {
1053 gp_index_ += 2;
1054 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1055 }
1056 }
1057
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001058 case Primitive::kPrimFloat: {
1059 uint32_t index = fp_index_++;
1060 stack_index_++;
1061 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001062 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001063 } else {
1064 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1065 }
1066 }
1067
1068 case Primitive::kPrimDouble: {
1069 uint32_t index = fp_index_++;
1070 stack_index_ += 2;
1071 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001072 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001073 } else {
1074 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1075 }
1076 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001077
1078 case Primitive::kPrimVoid:
1079 LOG(FATAL) << "Unexpected parameter type " << type;
1080 break;
1081 }
1082 return Location();
1083}
1084
1085void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001086 HandleInvoke(invoke);
1087}
1088
1089void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001090 CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001091 // TODO: Implement all kinds of calls:
1092 // 1) boot -> boot
1093 // 2) app -> boot
1094 // 3) app -> app
1095 //
1096 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1097
1098 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001099 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001100 // temp = temp->dex_cache_resolved_methods_;
1101 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
1102 // temp = temp[index_in_cache]
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001103 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache())));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001104 // (temp + offset_of_quick_compiled_code)()
1105 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
1106
1107 DCHECK(!codegen_->IsLeafMethod());
1108 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1109}
1110
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001111void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001112 LocationSummary* locations =
1113 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001114 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001115
1116 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001117 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001118 HInstruction* input = invoke->InputAt(i);
1119 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1120 }
1121
1122 switch (invoke->GetType()) {
1123 case Primitive::kPrimBoolean:
1124 case Primitive::kPrimByte:
1125 case Primitive::kPrimChar:
1126 case Primitive::kPrimShort:
1127 case Primitive::kPrimInt:
1128 case Primitive::kPrimNot:
1129 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001130 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001131 break;
1132
1133 case Primitive::kPrimVoid:
1134 break;
1135
1136 case Primitive::kPrimDouble:
1137 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001138 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001139 break;
1140 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001141}
1142
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001143void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1144 HandleInvoke(invoke);
1145}
1146
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001147void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001148 CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001149 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1150 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1151 LocationSummary* locations = invoke->GetLocations();
1152 Location receiver = locations->InAt(0);
1153 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1154 // temp = object->GetClass();
1155 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001156 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1157 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001158 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001159 __ movl(temp, Address(receiver.As<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001160 }
1161 // temp = temp->GetMethodAt(method_offset);
1162 __ movl(temp, Address(temp, method_offset));
1163 // call temp->GetEntryPoint();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001164 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
1165
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001166 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001167 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001168}
1169
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001170void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1171 HandleInvoke(invoke);
1172 // Add the hidden argument.
1173 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1174}
1175
1176void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1177 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1178 CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>();
1179 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1180 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1181 LocationSummary* locations = invoke->GetLocations();
1182 Location receiver = locations->InAt(0);
1183 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1184
1185 // Set the hidden argument.
1186 __ movq(invoke->GetLocations()->GetTemp(1).As<CpuRegister>(),
1187 Immediate(invoke->GetDexMethodIndex()));
1188
1189 // temp = object->GetClass();
1190 if (receiver.IsStackSlot()) {
1191 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1192 __ movl(temp, Address(temp, class_offset));
1193 } else {
1194 __ movl(temp, Address(receiver.As<CpuRegister>(), class_offset));
1195 }
1196 // temp = temp->GetImtEntryAt(method_offset);
1197 __ movl(temp, Address(temp, method_offset));
1198 // call temp->GetEntryPoint();
1199 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
1200
1201 DCHECK(!codegen_->IsLeafMethod());
1202 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1203}
1204
Roland Levillain88cb1752014-10-20 16:36:47 +01001205void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1206 LocationSummary* locations =
1207 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1208 switch (neg->GetResultType()) {
1209 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001210 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001211 locations->SetInAt(0, Location::RequiresRegister());
1212 locations->SetOut(Location::SameAsFirstInput());
1213 break;
1214
Roland Levillain88cb1752014-10-20 16:36:47 +01001215 case Primitive::kPrimFloat:
1216 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001217 locations->SetInAt(0, Location::RequiresFpuRegister());
1218 // Output overlaps as we need a fresh (zero-initialized)
1219 // register to perform subtraction from zero.
1220 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001221 break;
1222
1223 default:
1224 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1225 }
1226}
1227
1228void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1229 LocationSummary* locations = neg->GetLocations();
1230 Location out = locations->Out();
1231 Location in = locations->InAt(0);
1232 switch (neg->GetResultType()) {
1233 case Primitive::kPrimInt:
1234 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001235 DCHECK(in.Equals(out));
Roland Levillain88cb1752014-10-20 16:36:47 +01001236 __ negl(out.As<CpuRegister>());
1237 break;
1238
1239 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001240 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001241 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001242 __ negq(out.As<CpuRegister>());
1243 break;
1244
Roland Levillain88cb1752014-10-20 16:36:47 +01001245 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001246 DCHECK(in.IsFpuRegister());
1247 DCHECK(out.IsFpuRegister());
1248 DCHECK(!in.Equals(out));
1249 // TODO: Instead of computing negation as a subtraction from
1250 // zero, implement it with an exclusive or with value 0x80000000
1251 // (mask for bit 31, representing the sign of a single-precision
1252 // floating-point number), fetched from a constant pool:
1253 //
1254 // xorps out, [RIP:...] // value at RIP is 0x80 00 00 00
1255
1256 // out = 0
1257 __ xorps(out.As<XmmRegister>(), out.As<XmmRegister>());
1258 // out = out - in
1259 __ subss(out.As<XmmRegister>(), in.As<XmmRegister>());
1260 break;
1261
Roland Levillain88cb1752014-10-20 16:36:47 +01001262 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001263 DCHECK(in.IsFpuRegister());
1264 DCHECK(out.IsFpuRegister());
1265 DCHECK(!in.Equals(out));
1266 // TODO: Instead of computing negation as a subtraction from
1267 // zero, implement it with an exclusive or with value
1268 // 0x8000000000000000 (mask for bit 63, representing the sign of
1269 // a double-precision floating-point number), fetched from a
1270 // constant pool:
1271 //
1272 // xorpd out, [RIP:...] // value at RIP is 0x80 00 00 00 00 00 00 00
1273
1274 // out = 0
1275 __ xorpd(out.As<XmmRegister>(), out.As<XmmRegister>());
1276 // out = out - in
1277 __ subsd(out.As<XmmRegister>(), in.As<XmmRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001278 break;
1279
1280 default:
1281 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1282 }
1283}
1284
Roland Levillaindff1f282014-11-05 14:15:05 +00001285void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1286 LocationSummary* locations =
1287 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1288 Primitive::Type result_type = conversion->GetResultType();
1289 Primitive::Type input_type = conversion->GetInputType();
1290 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001291 case Primitive::kPrimByte:
1292 switch (input_type) {
1293 case Primitive::kPrimShort:
1294 case Primitive::kPrimInt:
1295 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001296 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001297 locations->SetInAt(0, Location::Any());
1298 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1299 break;
1300
1301 default:
1302 LOG(FATAL) << "Unexpected type conversion from " << input_type
1303 << " to " << result_type;
1304 }
1305 break;
1306
Roland Levillain946e1432014-11-11 17:35:19 +00001307 case Primitive::kPrimInt:
1308 switch (input_type) {
1309 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001310 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001311 locations->SetInAt(0, Location::Any());
1312 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1313 break;
1314
1315 case Primitive::kPrimFloat:
1316 case Primitive::kPrimDouble:
1317 LOG(FATAL) << "Type conversion from " << input_type
1318 << " to " << result_type << " not yet implemented";
1319 break;
1320
1321 default:
1322 LOG(FATAL) << "Unexpected type conversion from " << input_type
1323 << " to " << result_type;
1324 }
1325 break;
1326
Roland Levillaindff1f282014-11-05 14:15:05 +00001327 case Primitive::kPrimLong:
1328 switch (input_type) {
1329 case Primitive::kPrimByte:
1330 case Primitive::kPrimShort:
1331 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001332 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001333 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001334 // TODO: We would benefit from a (to-be-implemented)
1335 // Location::RegisterOrStackSlot requirement for this input.
1336 locations->SetInAt(0, Location::RequiresRegister());
1337 locations->SetOut(Location::RequiresRegister());
1338 break;
1339
1340 case Primitive::kPrimFloat:
1341 case Primitive::kPrimDouble:
1342 LOG(FATAL) << "Type conversion from " << input_type << " to "
1343 << result_type << " not yet implemented";
1344 break;
1345
1346 default:
1347 LOG(FATAL) << "Unexpected type conversion from " << input_type
1348 << " to " << result_type;
1349 }
1350 break;
1351
Roland Levillain981e4542014-11-14 11:47:14 +00001352 case Primitive::kPrimChar:
1353 switch (input_type) {
1354 case Primitive::kPrimByte:
1355 case Primitive::kPrimShort:
1356 case Primitive::kPrimInt:
1357 case Primitive::kPrimChar:
1358 // Processing a Dex `int-to-char' instruction.
1359 locations->SetInAt(0, Location::Any());
1360 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1361 break;
1362
1363 default:
1364 LOG(FATAL) << "Unexpected type conversion from " << input_type
1365 << " to " << result_type;
1366 }
1367 break;
1368
Roland Levillaindff1f282014-11-05 14:15:05 +00001369 case Primitive::kPrimFloat:
1370 case Primitive::kPrimDouble:
1371 LOG(FATAL) << "Type conversion from " << input_type
1372 << " to " << result_type << " not yet implemented";
1373 break;
1374
1375 default:
1376 LOG(FATAL) << "Unexpected type conversion from " << input_type
1377 << " to " << result_type;
1378 }
1379}
1380
1381void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1382 LocationSummary* locations = conversion->GetLocations();
1383 Location out = locations->Out();
1384 Location in = locations->InAt(0);
1385 Primitive::Type result_type = conversion->GetResultType();
1386 Primitive::Type input_type = conversion->GetInputType();
1387 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001388 case Primitive::kPrimByte:
1389 switch (input_type) {
1390 case Primitive::kPrimShort:
1391 case Primitive::kPrimInt:
1392 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001393 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001394 if (in.IsRegister()) {
1395 __ movsxb(out.As<CpuRegister>(), in.As<CpuRegister>());
1396 } else if (in.IsStackSlot()) {
1397 __ movsxb(out.As<CpuRegister>(),
1398 Address(CpuRegister(RSP), in.GetStackIndex()));
1399 } else {
1400 DCHECK(in.GetConstant()->IsIntConstant());
1401 __ movl(out.As<CpuRegister>(),
1402 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1403 }
1404 break;
1405
1406 default:
1407 LOG(FATAL) << "Unexpected type conversion from " << input_type
1408 << " to " << result_type;
1409 }
1410 break;
1411
Roland Levillain946e1432014-11-11 17:35:19 +00001412 case Primitive::kPrimInt:
1413 switch (input_type) {
1414 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001415 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001416 if (in.IsRegister()) {
1417 __ movl(out.As<CpuRegister>(), in.As<CpuRegister>());
1418 } else if (in.IsDoubleStackSlot()) {
1419 __ movl(out.As<CpuRegister>(),
1420 Address(CpuRegister(RSP), in.GetStackIndex()));
1421 } else {
1422 DCHECK(in.IsConstant());
1423 DCHECK(in.GetConstant()->IsLongConstant());
1424 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
1425 __ movl(out.As<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1426 }
1427 break;
1428
1429 case Primitive::kPrimFloat:
1430 case Primitive::kPrimDouble:
1431 LOG(FATAL) << "Type conversion from " << input_type
1432 << " to " << result_type << " not yet implemented";
1433 break;
1434
1435 default:
1436 LOG(FATAL) << "Unexpected type conversion from " << input_type
1437 << " to " << result_type;
1438 }
1439 break;
1440
Roland Levillaindff1f282014-11-05 14:15:05 +00001441 case Primitive::kPrimLong:
1442 switch (input_type) {
1443 DCHECK(out.IsRegister());
1444 case Primitive::kPrimByte:
1445 case Primitive::kPrimShort:
1446 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001447 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001448 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001449 DCHECK(in.IsRegister());
1450 __ movsxd(out.As<CpuRegister>(), in.As<CpuRegister>());
1451 break;
1452
1453 case Primitive::kPrimFloat:
1454 case Primitive::kPrimDouble:
1455 LOG(FATAL) << "Type conversion from " << input_type << " to "
1456 << result_type << " not yet implemented";
1457 break;
1458
1459 default:
1460 LOG(FATAL) << "Unexpected type conversion from " << input_type
1461 << " to " << result_type;
1462 }
1463 break;
1464
Roland Levillain981e4542014-11-14 11:47:14 +00001465 case Primitive::kPrimChar:
1466 switch (input_type) {
1467 case Primitive::kPrimByte:
1468 case Primitive::kPrimShort:
1469 case Primitive::kPrimInt:
1470 case Primitive::kPrimChar:
1471 // Processing a Dex `int-to-char' instruction.
1472 if (in.IsRegister()) {
1473 __ movzxw(out.As<CpuRegister>(), in.As<CpuRegister>());
1474 } else if (in.IsStackSlot()) {
1475 __ movzxw(out.As<CpuRegister>(),
1476 Address(CpuRegister(RSP), in.GetStackIndex()));
1477 } else {
1478 DCHECK(in.GetConstant()->IsIntConstant());
1479 __ movl(out.As<CpuRegister>(),
1480 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1481 }
1482 break;
1483
1484 default:
1485 LOG(FATAL) << "Unexpected type conversion from " << input_type
1486 << " to " << result_type;
1487 }
1488 break;
1489
Roland Levillaindff1f282014-11-05 14:15:05 +00001490 case Primitive::kPrimFloat:
1491 case Primitive::kPrimDouble:
1492 LOG(FATAL) << "Type conversion from " << input_type
1493 << " to " << result_type << " not yet implemented";
1494 break;
1495
1496 default:
1497 LOG(FATAL) << "Unexpected type conversion from " << input_type
1498 << " to " << result_type;
1499 }
1500}
1501
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001502void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001503 LocationSummary* locations =
1504 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001505 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001506 case Primitive::kPrimInt: {
1507 locations->SetInAt(0, Location::RequiresRegister());
1508 locations->SetInAt(1, Location::Any());
1509 locations->SetOut(Location::SameAsFirstInput());
1510 break;
1511 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001512
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001513 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001514 locations->SetInAt(0, Location::RequiresRegister());
1515 locations->SetInAt(1, Location::RequiresRegister());
1516 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001517 break;
1518 }
1519
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001520 case Primitive::kPrimDouble:
1521 case Primitive::kPrimFloat: {
1522 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001523 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001524 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001525 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001526 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001527
1528 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001529 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001530 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001531}
1532
1533void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1534 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001535 Location first = locations->InAt(0);
1536 Location second = locations->InAt(1);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001537 DCHECK(first.Equals(locations->Out()));
Calin Juravle11351682014-10-23 15:38:15 +01001538
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001539 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001540 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001541 if (second.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001542 __ addl(first.As<CpuRegister>(), second.As<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001543 } else if (second.IsConstant()) {
Calin Juravle11351682014-10-23 15:38:15 +01001544 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001545 __ addl(first.As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001546 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001547 __ addl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001548 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001549 break;
1550 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001551
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001552 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001553 __ addq(first.As<CpuRegister>(), second.As<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001554 break;
1555 }
1556
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001557 case Primitive::kPrimFloat: {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001558 __ addss(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001559 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001560 }
1561
1562 case Primitive::kPrimDouble: {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001563 __ addsd(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001564 break;
1565 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001566
1567 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001568 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001569 }
1570}
1571
1572void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001573 LocationSummary* locations =
1574 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001575 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001576 case Primitive::kPrimInt: {
1577 locations->SetInAt(0, Location::RequiresRegister());
1578 locations->SetInAt(1, Location::Any());
1579 locations->SetOut(Location::SameAsFirstInput());
1580 break;
1581 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001582 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001583 locations->SetInAt(0, Location::RequiresRegister());
1584 locations->SetInAt(1, Location::RequiresRegister());
1585 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001586 break;
1587 }
Calin Juravle11351682014-10-23 15:38:15 +01001588 case Primitive::kPrimFloat:
1589 case Primitive::kPrimDouble: {
1590 locations->SetInAt(0, Location::RequiresFpuRegister());
1591 locations->SetInAt(1, Location::RequiresFpuRegister());
1592 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001593 break;
Calin Juravle11351682014-10-23 15:38:15 +01001594 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001595 default:
Calin Juravle11351682014-10-23 15:38:15 +01001596 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001597 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001598}
1599
1600void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1601 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001602 Location first = locations->InAt(0);
1603 Location second = locations->InAt(1);
1604 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001605 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001606 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001607 if (second.IsRegister()) {
1608 __ subl(first.As<CpuRegister>(), second.As<CpuRegister>());
1609 } else if (second.IsConstant()) {
1610 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
1611 __ subl(first.As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001612 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001613 __ subl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001614 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001615 break;
1616 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001617 case Primitive::kPrimLong: {
Calin Juravle11351682014-10-23 15:38:15 +01001618 __ subq(first.As<CpuRegister>(), second.As<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001619 break;
1620 }
1621
Calin Juravle11351682014-10-23 15:38:15 +01001622 case Primitive::kPrimFloat: {
1623 __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001624 break;
Calin Juravle11351682014-10-23 15:38:15 +01001625 }
1626
1627 case Primitive::kPrimDouble: {
1628 __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1629 break;
1630 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001631
1632 default:
Calin Juravle11351682014-10-23 15:38:15 +01001633 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001634 }
1635}
1636
Calin Juravle34bacdf2014-10-07 20:23:36 +01001637void LocationsBuilderX86_64::VisitMul(HMul* mul) {
1638 LocationSummary* locations =
1639 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1640 switch (mul->GetResultType()) {
1641 case Primitive::kPrimInt: {
1642 locations->SetInAt(0, Location::RequiresRegister());
1643 locations->SetInAt(1, Location::Any());
1644 locations->SetOut(Location::SameAsFirstInput());
1645 break;
1646 }
1647 case Primitive::kPrimLong: {
1648 locations->SetInAt(0, Location::RequiresRegister());
1649 locations->SetInAt(1, Location::RequiresRegister());
1650 locations->SetOut(Location::SameAsFirstInput());
1651 break;
1652 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001653 case Primitive::kPrimFloat:
1654 case Primitive::kPrimDouble: {
1655 locations->SetInAt(0, Location::RequiresFpuRegister());
1656 locations->SetInAt(1, Location::RequiresFpuRegister());
1657 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001658 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001659 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001660
1661 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001662 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001663 }
1664}
1665
1666void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
1667 LocationSummary* locations = mul->GetLocations();
1668 Location first = locations->InAt(0);
1669 Location second = locations->InAt(1);
1670 DCHECK(first.Equals(locations->Out()));
1671 switch (mul->GetResultType()) {
1672 case Primitive::kPrimInt: {
1673 if (second.IsRegister()) {
1674 __ imull(first.As<CpuRegister>(), second.As<CpuRegister>());
1675 } else if (second.IsConstant()) {
1676 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
1677 __ imull(first.As<CpuRegister>(), imm);
1678 } else {
1679 DCHECK(second.IsStackSlot());
1680 __ imull(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
1681 }
1682 break;
1683 }
1684 case Primitive::kPrimLong: {
1685 __ imulq(first.As<CpuRegister>(), second.As<CpuRegister>());
1686 break;
1687 }
1688
Calin Juravleb5bfa962014-10-21 18:02:24 +01001689 case Primitive::kPrimFloat: {
1690 __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001691 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001692 }
1693
1694 case Primitive::kPrimDouble: {
1695 __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1696 break;
1697 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001698
1699 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001700 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001701 }
1702}
1703
Calin Juravle7c4954d2014-10-28 16:57:40 +00001704void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
1705 LocationSummary* locations =
1706 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1707 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001708 case Primitive::kPrimInt:
1709 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00001710 locations->SetInAt(0, Location::RegisterLocation(RAX));
1711 locations->SetInAt(1, Location::RequiresRegister());
1712 locations->SetOut(Location::SameAsFirstInput());
1713 // Intel uses edx:eax as the dividend.
1714 locations->AddTemp(Location::RegisterLocation(RDX));
1715 break;
1716 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001717
Calin Juravle7c4954d2014-10-28 16:57:40 +00001718 case Primitive::kPrimFloat:
1719 case Primitive::kPrimDouble: {
1720 locations->SetInAt(0, Location::RequiresFpuRegister());
1721 locations->SetInAt(1, Location::RequiresFpuRegister());
1722 locations->SetOut(Location::SameAsFirstInput());
1723 break;
1724 }
1725
1726 default:
1727 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1728 }
1729}
1730
1731void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
1732 LocationSummary* locations = div->GetLocations();
1733 Location first = locations->InAt(0);
1734 Location second = locations->InAt(1);
1735 DCHECK(first.Equals(locations->Out()));
1736
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001737 Primitive::Type type = div->GetResultType();
1738 switch (type) {
1739 case Primitive::kPrimInt:
1740 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00001741 CpuRegister first_reg = first.As<CpuRegister>();
1742 CpuRegister second_reg = second.As<CpuRegister>();
1743 DCHECK_EQ(RAX, first_reg.AsRegister());
1744 DCHECK_EQ(RDX, locations->GetTemp(0).As<CpuRegister>().AsRegister());
1745
1746 SlowPathCodeX86_64* slow_path =
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001747 new (GetGraph()->GetArena()) DivMinusOneSlowPathX86_64(first_reg.AsRegister(), type);
Calin Juravled0d48522014-11-04 16:40:20 +00001748 codegen_->AddSlowPath(slow_path);
1749
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001750 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
1751 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
1752 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravled0d48522014-11-04 16:40:20 +00001753
1754 __ cmpl(second_reg, Immediate(-1));
1755 __ j(kEqual, slow_path->GetEntryLabel());
1756
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001757 if (type == Primitive::kPrimInt) {
1758 // edx:eax <- sign-extended of eax
1759 __ cdq();
1760 // eax = quotient, edx = remainder
1761 __ idivl(second_reg);
1762 } else {
1763 // rdx:rax <- sign-extended of rax
1764 __ cqo();
1765 // rax = quotient, rdx = remainder
1766 __ idivq(second_reg);
1767 }
Calin Juravled0d48522014-11-04 16:40:20 +00001768
1769 __ Bind(slow_path->GetExitLabel());
1770 break;
1771 }
1772
Calin Juravle7c4954d2014-10-28 16:57:40 +00001773 case Primitive::kPrimFloat: {
1774 __ divss(first.As<XmmRegister>(), second.As<XmmRegister>());
1775 break;
1776 }
1777
1778 case Primitive::kPrimDouble: {
1779 __ divsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1780 break;
1781 }
1782
1783 default:
1784 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1785 }
1786}
1787
Calin Juravled0d48522014-11-04 16:40:20 +00001788void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1789 LocationSummary* locations =
1790 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1791 locations->SetInAt(0, Location::Any());
1792 if (instruction->HasUses()) {
1793 locations->SetOut(Location::SameAsFirstInput());
1794 }
1795}
1796
1797void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1798 SlowPathCodeX86_64* slow_path =
1799 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
1800 codegen_->AddSlowPath(slow_path);
1801
1802 LocationSummary* locations = instruction->GetLocations();
1803 Location value = locations->InAt(0);
1804
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001805 switch (instruction->GetType()) {
1806 case Primitive::kPrimInt: {
1807 if (value.IsRegister()) {
1808 __ testl(value.As<CpuRegister>(), value.As<CpuRegister>());
1809 __ j(kEqual, slow_path->GetEntryLabel());
1810 } else if (value.IsStackSlot()) {
1811 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
1812 __ j(kEqual, slow_path->GetEntryLabel());
1813 } else {
1814 DCHECK(value.IsConstant()) << value;
1815 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
1816 __ jmp(slow_path->GetEntryLabel());
1817 }
1818 }
1819 break;
Calin Juravled0d48522014-11-04 16:40:20 +00001820 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001821 case Primitive::kPrimLong: {
1822 if (value.IsRegister()) {
1823 __ testq(value.As<CpuRegister>(), value.As<CpuRegister>());
1824 __ j(kEqual, slow_path->GetEntryLabel());
1825 } else if (value.IsDoubleStackSlot()) {
1826 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
1827 __ j(kEqual, slow_path->GetEntryLabel());
1828 } else {
1829 DCHECK(value.IsConstant()) << value;
1830 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
1831 __ jmp(slow_path->GetEntryLabel());
1832 }
1833 }
1834 break;
1835 }
1836 default:
1837 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00001838 }
Calin Juravled0d48522014-11-04 16:40:20 +00001839}
1840
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001841void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001842 LocationSummary* locations =
1843 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001844 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001845 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1846 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1847 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001848}
1849
1850void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
1851 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001852 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001853 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
1854
1855 __ gs()->call(Address::Absolute(
1856 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
1857
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001858 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001859 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001860}
1861
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001862void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
1863 LocationSummary* locations =
1864 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1865 InvokeRuntimeCallingConvention calling_convention;
1866 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1867 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1868 locations->SetOut(Location::RegisterLocation(RAX));
1869 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1870}
1871
1872void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
1873 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001874 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001875 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
1876
1877 __ gs()->call(Address::Absolute(
1878 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true));
1879
1880 DCHECK(!codegen_->IsLeafMethod());
1881 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1882}
1883
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001884void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001885 LocationSummary* locations =
1886 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001887 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1888 if (location.IsStackSlot()) {
1889 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1890 } else if (location.IsDoubleStackSlot()) {
1891 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1892 }
1893 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001894}
1895
1896void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
1897 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001898 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001899}
1900
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001901void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001902 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001903 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001904 locations->SetInAt(0, Location::RequiresRegister());
1905 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001906}
1907
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001908void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
1909 LocationSummary* locations = not_->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001910 DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
1911 locations->Out().As<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001912 Location out = locations->Out();
1913 switch (not_->InputAt(0)->GetType()) {
1914 case Primitive::kPrimBoolean:
1915 __ xorq(out.As<CpuRegister>(), Immediate(1));
1916 break;
1917
1918 case Primitive::kPrimInt:
1919 __ notl(out.As<CpuRegister>());
1920 break;
1921
1922 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01001923 __ notq(out.As<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001924 break;
1925
1926 default:
1927 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
1928 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001929}
1930
1931void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001932 LocationSummary* locations =
1933 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001934 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1935 locations->SetInAt(i, Location::Any());
1936 }
1937 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001938}
1939
1940void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001941 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001942 LOG(FATAL) << "Unimplemented";
1943}
1944
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001945void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001946 LocationSummary* locations =
1947 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001948 Primitive::Type field_type = instruction->GetFieldType();
1949 bool is_object_type = field_type == Primitive::kPrimNot;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001950 locations->SetInAt(0, Location::RequiresRegister());
1951 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001952 if (is_object_type) {
1953 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001954 locations->AddTemp(Location::RequiresRegister());
1955 locations->AddTemp(Location::RequiresRegister());
1956 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001957}
1958
1959void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1960 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001961 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001962 size_t offset = instruction->GetFieldOffset().SizeValue();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001963 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001964
1965 switch (field_type) {
1966 case Primitive::kPrimBoolean:
1967 case Primitive::kPrimByte: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001968 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001969 __ movb(Address(obj, offset), value);
1970 break;
1971 }
1972
1973 case Primitive::kPrimShort:
1974 case Primitive::kPrimChar: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001975 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001976 __ movw(Address(obj, offset), value);
1977 break;
1978 }
1979
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001980 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001981 case Primitive::kPrimNot: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001982 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001983 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001984 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001985 CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
1986 CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001987 codegen_->MarkGCCard(temp, card, obj, value);
1988 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001989 break;
1990 }
1991
1992 case Primitive::kPrimLong: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001993 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001994 __ movq(Address(obj, offset), value);
1995 break;
1996 }
1997
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001998 case Primitive::kPrimFloat: {
1999 XmmRegister value = locations->InAt(1).As<XmmRegister>();
2000 __ movss(Address(obj, offset), value);
2001 break;
2002 }
2003
2004 case Primitive::kPrimDouble: {
2005 XmmRegister value = locations->InAt(1).As<XmmRegister>();
2006 __ movsd(Address(obj, offset), value);
2007 break;
2008 }
2009
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002010 case Primitive::kPrimVoid:
2011 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002012 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002013 }
2014}
2015
2016void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002017 LocationSummary* locations =
2018 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002019 locations->SetInAt(0, Location::RequiresRegister());
2020 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002021}
2022
2023void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
2024 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002025 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002026 size_t offset = instruction->GetFieldOffset().SizeValue();
2027
2028 switch (instruction->GetType()) {
2029 case Primitive::kPrimBoolean: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002030 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002031 __ movzxb(out, Address(obj, offset));
2032 break;
2033 }
2034
2035 case Primitive::kPrimByte: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002036 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002037 __ movsxb(out, Address(obj, offset));
2038 break;
2039 }
2040
2041 case Primitive::kPrimShort: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002042 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002043 __ movsxw(out, Address(obj, offset));
2044 break;
2045 }
2046
2047 case Primitive::kPrimChar: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002048 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002049 __ movzxw(out, Address(obj, offset));
2050 break;
2051 }
2052
2053 case Primitive::kPrimInt:
2054 case Primitive::kPrimNot: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002055 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002056 __ movl(out, Address(obj, offset));
2057 break;
2058 }
2059
2060 case Primitive::kPrimLong: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002061 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002062 __ movq(out, Address(obj, offset));
2063 break;
2064 }
2065
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002066 case Primitive::kPrimFloat: {
2067 XmmRegister out = locations->Out().As<XmmRegister>();
2068 __ movss(out, Address(obj, offset));
2069 break;
2070 }
2071
2072 case Primitive::kPrimDouble: {
2073 XmmRegister out = locations->Out().As<XmmRegister>();
2074 __ movsd(out, Address(obj, offset));
2075 break;
2076 }
2077
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002078 case Primitive::kPrimVoid:
2079 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002080 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002081 }
2082}
2083
2084void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002085 LocationSummary* locations =
2086 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002087 locations->SetInAt(0, Location::Any());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002088 if (instruction->HasUses()) {
2089 locations->SetOut(Location::SameAsFirstInput());
2090 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002091}
2092
2093void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002094 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002095 codegen_->AddSlowPath(slow_path);
2096
2097 LocationSummary* locations = instruction->GetLocations();
2098 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002099
2100 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002101 __ cmpl(obj.As<CpuRegister>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002102 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002103 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002104 } else {
2105 DCHECK(obj.IsConstant()) << obj;
2106 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2107 __ jmp(slow_path->GetEntryLabel());
2108 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002109 }
2110 __ j(kEqual, slow_path->GetEntryLabel());
2111}
2112
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002113void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002114 LocationSummary* locations =
2115 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002116 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002117 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002118 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2119 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002120}
2121
2122void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2123 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002124 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002125 Location index = locations->InAt(1);
2126
2127 switch (instruction->GetType()) {
2128 case Primitive::kPrimBoolean: {
2129 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002130 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002131 if (index.IsConstant()) {
2132 __ movzxb(out, Address(obj,
2133 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2134 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002135 __ movzxb(out, Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002136 }
2137 break;
2138 }
2139
2140 case Primitive::kPrimByte: {
2141 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002142 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002143 if (index.IsConstant()) {
2144 __ movsxb(out, Address(obj,
2145 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2146 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002147 __ movsxb(out, Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002148 }
2149 break;
2150 }
2151
2152 case Primitive::kPrimShort: {
2153 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002154 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002155 if (index.IsConstant()) {
2156 __ movsxw(out, Address(obj,
2157 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2158 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002159 __ movsxw(out, Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002160 }
2161 break;
2162 }
2163
2164 case Primitive::kPrimChar: {
2165 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002166 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002167 if (index.IsConstant()) {
2168 __ movzxw(out, Address(obj,
2169 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2170 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002171 __ movzxw(out, Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002172 }
2173 break;
2174 }
2175
2176 case Primitive::kPrimInt:
2177 case Primitive::kPrimNot: {
2178 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2179 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002180 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002181 if (index.IsConstant()) {
2182 __ movl(out, Address(obj,
2183 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2184 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002185 __ movl(out, Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002186 }
2187 break;
2188 }
2189
2190 case Primitive::kPrimLong: {
2191 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002192 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002193 if (index.IsConstant()) {
2194 __ movq(out, Address(obj,
2195 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2196 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002197 __ movq(out, Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002198 }
2199 break;
2200 }
2201
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002202 case Primitive::kPrimFloat: {
2203 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
2204 XmmRegister out = locations->Out().As<XmmRegister>();
2205 if (index.IsConstant()) {
2206 __ movss(out, Address(obj,
2207 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2208 } else {
2209 __ movss(out, Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset));
2210 }
2211 break;
2212 }
2213
2214 case Primitive::kPrimDouble: {
2215 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
2216 XmmRegister out = locations->Out().As<XmmRegister>();
2217 if (index.IsConstant()) {
2218 __ movsd(out, Address(obj,
2219 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2220 } else {
2221 __ movsd(out, Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset));
2222 }
2223 break;
2224 }
2225
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002226 case Primitive::kPrimVoid:
2227 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002228 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002229 }
2230}
2231
2232void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002233 Primitive::Type value_type = instruction->GetComponentType();
2234 bool is_object = value_type == Primitive::kPrimNot;
2235 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2236 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
2237 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002238 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002239 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2240 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2241 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002242 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002243 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002244 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002245 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2246 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002247 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002248 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002249 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
2250 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002251 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002252 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002253 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002254 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002255}
2256
2257void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
2258 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002259 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002260 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002261 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01002262 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002263
2264 switch (value_type) {
2265 case Primitive::kPrimBoolean:
2266 case Primitive::kPrimByte: {
2267 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002268 if (index.IsConstant()) {
2269 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002270 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002271 __ movb(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002272 } else {
2273 __ movb(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2274 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002275 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002276 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002277 __ movb(Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset),
2278 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002279 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002280 __ movb(Address(obj, index.As<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002281 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2282 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002283 }
2284 break;
2285 }
2286
2287 case Primitive::kPrimShort:
2288 case Primitive::kPrimChar: {
2289 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002290 if (index.IsConstant()) {
2291 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002292 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002293 __ movw(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002294 } else {
2295 __ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2296 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002297 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002298 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002299 __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
2300 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002301 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002302 __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002303 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2304 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002305 }
2306 break;
2307 }
2308
2309 case Primitive::kPrimInt: {
2310 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002311 if (index.IsConstant()) {
2312 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002313 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002314 __ movl(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002315 } else {
2316 __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2317 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002318 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002319 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002320 __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
2321 value.As<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002322 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002323 DCHECK(value.IsConstant()) << value;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002324 __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002325 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2326 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002327 }
2328 break;
2329 }
2330
2331 case Primitive::kPrimNot: {
2332 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
2333 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002334 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002335 break;
2336 }
2337
2338 case Primitive::kPrimLong: {
2339 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002340 if (index.IsConstant()) {
2341 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002342 DCHECK(value.IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002343 __ movq(Address(obj, offset), value.As<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002344 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002345 DCHECK(value.IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002346 __ movq(Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset),
2347 value.As<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002348 }
2349 break;
2350 }
2351
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002352 case Primitive::kPrimFloat: {
2353 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
2354 if (index.IsConstant()) {
2355 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2356 DCHECK(value.IsFpuRegister());
2357 __ movss(Address(obj, offset), value.As<XmmRegister>());
2358 } else {
2359 DCHECK(value.IsFpuRegister());
2360 __ movss(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
2361 value.As<XmmRegister>());
2362 }
2363 break;
2364 }
2365
2366 case Primitive::kPrimDouble: {
2367 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
2368 if (index.IsConstant()) {
2369 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
2370 DCHECK(value.IsFpuRegister());
2371 __ movsd(Address(obj, offset), value.As<XmmRegister>());
2372 } else {
2373 DCHECK(value.IsFpuRegister());
2374 __ movsd(Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset),
2375 value.As<XmmRegister>());
2376 }
2377 break;
2378 }
2379
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002380 case Primitive::kPrimVoid:
2381 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002382 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002383 }
2384}
2385
2386void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002387 LocationSummary* locations =
2388 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002389 locations->SetInAt(0, Location::RequiresRegister());
2390 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002391}
2392
2393void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
2394 LocationSummary* locations = instruction->GetLocations();
2395 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002396 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
2397 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002398 __ movl(out, Address(obj, offset));
2399}
2400
2401void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002402 LocationSummary* locations =
2403 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002404 locations->SetInAt(0, Location::RequiresRegister());
2405 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002406 if (instruction->HasUses()) {
2407 locations->SetOut(Location::SameAsFirstInput());
2408 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002409}
2410
2411void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
2412 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002413 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01002414 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002415 codegen_->AddSlowPath(slow_path);
2416
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002417 CpuRegister index = locations->InAt(0).As<CpuRegister>();
2418 CpuRegister length = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002419
2420 __ cmpl(index, length);
2421 __ j(kAboveEqual, slow_path->GetEntryLabel());
2422}
2423
2424void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
2425 CpuRegister card,
2426 CpuRegister object,
2427 CpuRegister value) {
2428 Label is_null;
2429 __ testl(value, value);
2430 __ j(kEqual, &is_null);
2431 __ gs()->movq(card, Address::Absolute(
2432 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
2433 __ movq(temp, object);
2434 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
2435 __ movb(Address(temp, card, TIMES_1, 0), card);
2436 __ Bind(&is_null);
2437}
2438
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002439void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
2440 temp->SetLocations(nullptr);
2441}
2442
2443void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
2444 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002445 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002446}
2447
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002448void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002449 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002450 LOG(FATAL) << "Unimplemented";
2451}
2452
2453void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002454 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2455}
2456
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002457void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
2458 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2459}
2460
2461void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002462 HBasicBlock* block = instruction->GetBlock();
2463 if (block->GetLoopInformation() != nullptr) {
2464 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2465 // The back edge will generate the suspend check.
2466 return;
2467 }
2468 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2469 // The goto will generate the suspend check.
2470 return;
2471 }
2472 GenerateSuspendCheck(instruction, nullptr);
2473}
2474
2475void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
2476 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002477 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002478 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002479 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002480 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002481 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002482 if (successor == nullptr) {
2483 __ j(kNotEqual, slow_path->GetEntryLabel());
2484 __ Bind(slow_path->GetReturnLabel());
2485 } else {
2486 __ j(kEqual, codegen_->GetLabelOf(successor));
2487 __ jmp(slow_path->GetEntryLabel());
2488 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002489}
2490
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002491X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
2492 return codegen_->GetAssembler();
2493}
2494
2495void ParallelMoveResolverX86_64::EmitMove(size_t index) {
2496 MoveOperands* move = moves_.Get(index);
2497 Location source = move->GetSource();
2498 Location destination = move->GetDestination();
2499
2500 if (source.IsRegister()) {
2501 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002502 __ movq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002503 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002504 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002505 source.As<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002506 } else {
2507 DCHECK(destination.IsDoubleStackSlot());
2508 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002509 source.As<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002510 }
2511 } else if (source.IsStackSlot()) {
2512 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002513 __ movl(destination.As<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002514 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002515 } else if (destination.IsFpuRegister()) {
2516 __ movss(destination.As<XmmRegister>(),
2517 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002518 } else {
2519 DCHECK(destination.IsStackSlot());
2520 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
2521 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
2522 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002523 } else if (source.IsDoubleStackSlot()) {
2524 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002525 __ movq(destination.As<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002526 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002527 } else if (destination.IsFpuRegister()) {
2528 __ movsd(destination.As<XmmRegister>(), Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002529 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01002530 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002531 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
2532 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
2533 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002534 } else if (source.IsConstant()) {
2535 HConstant* constant = source.GetConstant();
2536 if (constant->IsIntConstant()) {
2537 Immediate imm(constant->AsIntConstant()->GetValue());
2538 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002539 __ movl(destination.As<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002540 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002541 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002542 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
2543 }
2544 } else if (constant->IsLongConstant()) {
2545 int64_t value = constant->AsLongConstant()->GetValue();
2546 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002547 __ movq(destination.As<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002548 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002549 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002550 __ movq(CpuRegister(TMP), Immediate(value));
2551 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
2552 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002553 } else if (constant->IsFloatConstant()) {
2554 Immediate imm(bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()));
2555 if (destination.IsFpuRegister()) {
2556 __ movl(CpuRegister(TMP), imm);
2557 __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
2558 } else {
2559 DCHECK(destination.IsStackSlot()) << destination;
2560 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
2561 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002562 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002563 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
2564 Immediate imm(bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()));
2565 if (destination.IsFpuRegister()) {
2566 __ movq(CpuRegister(TMP), imm);
2567 __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
2568 } else {
2569 DCHECK(destination.IsDoubleStackSlot()) << destination;
2570 __ movq(CpuRegister(TMP), imm);
2571 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
2572 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002573 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002574 } else if (source.IsFpuRegister()) {
2575 if (destination.IsFpuRegister()) {
2576 __ movaps(destination.As<XmmRegister>(), source.As<XmmRegister>());
2577 } else if (destination.IsStackSlot()) {
2578 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
2579 source.As<XmmRegister>());
2580 } else {
2581 DCHECK(destination.IsDoubleStackSlot());
2582 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
2583 source.As<XmmRegister>());
2584 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002585 }
2586}
2587
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002588void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002589 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002590 __ movl(Address(CpuRegister(RSP), mem), reg);
2591 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002592}
2593
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002594void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002595 ScratchRegisterScope ensure_scratch(
2596 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
2597
2598 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
2599 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
2600 __ movl(CpuRegister(ensure_scratch.GetRegister()),
2601 Address(CpuRegister(RSP), mem2 + stack_offset));
2602 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
2603 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
2604 CpuRegister(ensure_scratch.GetRegister()));
2605}
2606
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002607void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
2608 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
2609 __ movq(Address(CpuRegister(RSP), mem), reg);
2610 __ movq(reg, CpuRegister(TMP));
2611}
2612
2613void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
2614 ScratchRegisterScope ensure_scratch(
2615 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
2616
2617 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
2618 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
2619 __ movq(CpuRegister(ensure_scratch.GetRegister()),
2620 Address(CpuRegister(RSP), mem2 + stack_offset));
2621 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
2622 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
2623 CpuRegister(ensure_scratch.GetRegister()));
2624}
2625
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002626void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
2627 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
2628 __ movss(Address(CpuRegister(RSP), mem), reg);
2629 __ movd(reg, CpuRegister(TMP));
2630}
2631
2632void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
2633 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
2634 __ movsd(Address(CpuRegister(RSP), mem), reg);
2635 __ movd(reg, CpuRegister(TMP));
2636}
2637
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002638void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
2639 MoveOperands* move = moves_.Get(index);
2640 Location source = move->GetSource();
2641 Location destination = move->GetDestination();
2642
2643 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002644 __ xchgq(destination.As<CpuRegister>(), source.As<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002645 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002646 Exchange32(source.As<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002647 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002648 Exchange32(destination.As<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002649 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002650 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
2651 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002652 Exchange64(source.As<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002653 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002654 Exchange64(destination.As<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002655 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
2656 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002657 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
2658 __ movd(CpuRegister(TMP), source.As<XmmRegister>());
2659 __ movaps(source.As<XmmRegister>(), destination.As<XmmRegister>());
2660 __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
2661 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
2662 Exchange32(source.As<XmmRegister>(), destination.GetStackIndex());
2663 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
2664 Exchange32(destination.As<XmmRegister>(), source.GetStackIndex());
2665 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
2666 Exchange64(source.As<XmmRegister>(), destination.GetStackIndex());
2667 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
2668 Exchange64(destination.As<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002669 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002670 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002671 }
2672}
2673
2674
2675void ParallelMoveResolverX86_64::SpillScratch(int reg) {
2676 __ pushq(CpuRegister(reg));
2677}
2678
2679
2680void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
2681 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002682}
2683
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002684void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
2685 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
2686 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
2687 Immediate(mirror::Class::kStatusInitialized));
2688 __ j(kLess, slow_path->GetEntryLabel());
2689 __ Bind(slow_path->GetExitLabel());
2690 // No need for memory fence, thanks to the X86_64 memory model.
2691}
2692
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002693void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002694 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
2695 ? LocationSummary::kCallOnSlowPath
2696 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002697 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002698 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002699 locations->SetOut(Location::RequiresRegister());
2700}
2701
2702void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
2703 CpuRegister out = cls->GetLocations()->Out().As<CpuRegister>();
2704 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002705 DCHECK(!cls->CanCallRuntime());
2706 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002707 codegen_->LoadCurrentMethod(out);
2708 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
2709 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002710 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002711 codegen_->LoadCurrentMethod(out);
2712 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
2713 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002714 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
2715 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
2716 codegen_->AddSlowPath(slow_path);
2717 __ testl(out, out);
2718 __ j(kEqual, slow_path->GetEntryLabel());
2719 if (cls->MustGenerateClinitCheck()) {
2720 GenerateClassInitializationCheck(slow_path, out);
2721 } else {
2722 __ Bind(slow_path->GetExitLabel());
2723 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002724 }
2725}
2726
2727void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
2728 LocationSummary* locations =
2729 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2730 locations->SetInAt(0, Location::RequiresRegister());
2731 if (check->HasUses()) {
2732 locations->SetOut(Location::SameAsFirstInput());
2733 }
2734}
2735
2736void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002737 // We assume the class to not be null.
2738 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
2739 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002740 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002741 GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002742}
2743
2744void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2745 LocationSummary* locations =
2746 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2747 locations->SetInAt(0, Location::RequiresRegister());
2748 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2749}
2750
2751void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2752 LocationSummary* locations = instruction->GetLocations();
2753 CpuRegister cls = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002754 size_t offset = instruction->GetFieldOffset().SizeValue();
2755
2756 switch (instruction->GetType()) {
2757 case Primitive::kPrimBoolean: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002758 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002759 __ movzxb(out, Address(cls, offset));
2760 break;
2761 }
2762
2763 case Primitive::kPrimByte: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002764 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002765 __ movsxb(out, Address(cls, offset));
2766 break;
2767 }
2768
2769 case Primitive::kPrimShort: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002770 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002771 __ movsxw(out, Address(cls, offset));
2772 break;
2773 }
2774
2775 case Primitive::kPrimChar: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002776 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002777 __ movzxw(out, Address(cls, offset));
2778 break;
2779 }
2780
2781 case Primitive::kPrimInt:
2782 case Primitive::kPrimNot: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002783 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002784 __ movl(out, Address(cls, offset));
2785 break;
2786 }
2787
2788 case Primitive::kPrimLong: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002789 CpuRegister out = locations->Out().As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002790 __ movq(out, Address(cls, offset));
2791 break;
2792 }
2793
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002794 case Primitive::kPrimFloat: {
2795 XmmRegister out = locations->Out().As<XmmRegister>();
2796 __ movss(out, Address(cls, offset));
2797 break;
2798 }
2799
2800 case Primitive::kPrimDouble: {
2801 XmmRegister out = locations->Out().As<XmmRegister>();
2802 __ movsd(out, Address(cls, offset));
2803 break;
2804 }
2805
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002806 case Primitive::kPrimVoid:
2807 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2808 UNREACHABLE();
2809 }
2810}
2811
2812void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2813 LocationSummary* locations =
2814 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2815 Primitive::Type field_type = instruction->GetFieldType();
2816 bool is_object_type = field_type == Primitive::kPrimNot;
2817 locations->SetInAt(0, Location::RequiresRegister());
2818 locations->SetInAt(1, Location::RequiresRegister());
2819 if (is_object_type) {
2820 // Temporary registers for the write barrier.
2821 locations->AddTemp(Location::RequiresRegister());
2822 locations->AddTemp(Location::RequiresRegister());
2823 }
2824}
2825
2826void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2827 LocationSummary* locations = instruction->GetLocations();
2828 CpuRegister cls = locations->InAt(0).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002829 size_t offset = instruction->GetFieldOffset().SizeValue();
2830 Primitive::Type field_type = instruction->GetFieldType();
2831
2832 switch (field_type) {
2833 case Primitive::kPrimBoolean:
2834 case Primitive::kPrimByte: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002835 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002836 __ movb(Address(cls, offset), value);
2837 break;
2838 }
2839
2840 case Primitive::kPrimShort:
2841 case Primitive::kPrimChar: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002842 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002843 __ movw(Address(cls, offset), value);
2844 break;
2845 }
2846
2847 case Primitive::kPrimInt:
2848 case Primitive::kPrimNot: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002849 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002850 __ movl(Address(cls, offset), value);
2851 if (field_type == Primitive::kPrimNot) {
2852 CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
2853 CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
2854 codegen_->MarkGCCard(temp, card, cls, value);
2855 }
2856 break;
2857 }
2858
2859 case Primitive::kPrimLong: {
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002860 CpuRegister value = locations->InAt(1).As<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002861 __ movq(Address(cls, offset), value);
2862 break;
2863 }
2864
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002865 case Primitive::kPrimFloat: {
2866 XmmRegister value = locations->InAt(1).As<XmmRegister>();
2867 __ movss(Address(cls, offset), value);
2868 break;
2869 }
2870
2871 case Primitive::kPrimDouble: {
2872 XmmRegister value = locations->InAt(1).As<XmmRegister>();
2873 __ movsd(Address(cls, offset), value);
2874 break;
2875 }
2876
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002877 case Primitive::kPrimVoid:
2878 LOG(FATAL) << "Unreachable type " << field_type;
2879 UNREACHABLE();
2880 }
2881}
2882
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00002883void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
2884 LocationSummary* locations =
2885 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
2886 locations->SetOut(Location::RequiresRegister());
2887}
2888
2889void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
2890 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
2891 codegen_->AddSlowPath(slow_path);
2892
2893 CpuRegister out = load->GetLocations()->Out().As<CpuRegister>();
2894 codegen_->LoadCurrentMethod(CpuRegister(out));
2895 __ movl(out, Address(out, mirror::ArtMethod::DexCacheStringsOffset().Int32Value()));
2896 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
2897 __ testl(out, out);
2898 __ j(kEqual, slow_path->GetEntryLabel());
2899 __ Bind(slow_path->GetExitLabel());
2900}
2901
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00002902void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
2903 LocationSummary* locations =
2904 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
2905 locations->SetOut(Location::RequiresRegister());
2906}
2907
2908void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
2909 Address address = Address::Absolute(
2910 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
2911 __ gs()->movl(load->GetLocations()->Out().As<CpuRegister>(), address);
2912 __ gs()->movl(address, Immediate(0));
2913}
2914
2915void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
2916 LocationSummary* locations =
2917 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2918 InvokeRuntimeCallingConvention calling_convention;
2919 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2920}
2921
2922void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
2923 __ gs()->call(
2924 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
2925 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2926}
2927
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00002928void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00002929 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
2930 ? LocationSummary::kNoCall
2931 : LocationSummary::kCallOnSlowPath;
2932 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
2933 locations->SetInAt(0, Location::RequiresRegister());
2934 locations->SetInAt(1, Location::Any());
2935 locations->SetOut(Location::RequiresRegister());
2936}
2937
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00002938void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00002939 LocationSummary* locations = instruction->GetLocations();
2940 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
2941 Location cls = locations->InAt(1);
2942 CpuRegister out = locations->Out().As<CpuRegister>();
2943 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2944 Label done, zero;
2945 SlowPathCodeX86_64* slow_path = nullptr;
2946
2947 // Return 0 if `obj` is null.
2948 // TODO: avoid this check if we know obj is not null.
2949 __ testl(obj, obj);
2950 __ j(kEqual, &zero);
2951 // Compare the class of `obj` with `cls`.
2952 __ movl(out, Address(obj, class_offset));
2953 if (cls.IsRegister()) {
2954 __ cmpl(out, cls.As<CpuRegister>());
2955 } else {
2956 DCHECK(cls.IsStackSlot()) << cls;
2957 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
2958 }
2959 if (instruction->IsClassFinal()) {
2960 // Classes must be equal for the instanceof to succeed.
2961 __ j(kNotEqual, &zero);
2962 __ movl(out, Immediate(1));
2963 __ jmp(&done);
2964 } else {
2965 // If the classes are not equal, we go into a slow path.
2966 DCHECK(locations->OnlyCallsOnSlowPath());
2967 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00002968 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00002969 codegen_->AddSlowPath(slow_path);
2970 __ j(kNotEqual, slow_path->GetEntryLabel());
2971 __ movl(out, Immediate(1));
2972 __ jmp(&done);
2973 }
2974 __ Bind(&zero);
2975 __ movl(out, Immediate(0));
2976 if (slow_path != nullptr) {
2977 __ Bind(slow_path->GetExitLabel());
2978 }
2979 __ Bind(&done);
2980}
2981
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00002982void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
2983 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2984 instruction, LocationSummary::kCallOnSlowPath);
2985 locations->SetInAt(0, Location::RequiresRegister());
2986 locations->SetInAt(1, Location::Any());
2987 locations->AddTemp(Location::RequiresRegister());
2988}
2989
2990void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
2991 LocationSummary* locations = instruction->GetLocations();
2992 CpuRegister obj = locations->InAt(0).As<CpuRegister>();
2993 Location cls = locations->InAt(1);
2994 CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
2995 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2996 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
2997 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
2998 codegen_->AddSlowPath(slow_path);
2999
3000 // TODO: avoid this check if we know obj is not null.
3001 __ testl(obj, obj);
3002 __ j(kEqual, slow_path->GetExitLabel());
3003 // Compare the class of `obj` with `cls`.
3004 __ movl(temp, Address(obj, class_offset));
3005 if (cls.IsRegister()) {
3006 __ cmpl(temp, cls.As<CpuRegister>());
3007 } else {
3008 DCHECK(cls.IsStackSlot()) << cls;
3009 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3010 }
3011 // Classes must be equal for the checkcast to succeed.
3012 __ j(kNotEqual, slow_path->GetEntryLabel());
3013 __ Bind(slow_path->GetExitLabel());
3014}
3015
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003016void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3017 LocationSummary* locations =
3018 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3019 InvokeRuntimeCallingConvention calling_convention;
3020 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3021}
3022
3023void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3024 __ gs()->call(Address::Absolute(instruction->IsEnter()
3025 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3026 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3027 true));
3028 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3029}
3030
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003031void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3032void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3033void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3034
3035void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3036 LocationSummary* locations =
3037 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3038 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3039 || instruction->GetResultType() == Primitive::kPrimLong);
3040 locations->SetInAt(0, Location::RequiresRegister());
3041 if (instruction->GetType() == Primitive::kPrimInt) {
3042 locations->SetInAt(1, Location::Any());
3043 } else {
3044 // Request a register to avoid loading a 64bits constant.
3045 locations->SetInAt(1, Location::RequiresRegister());
3046 }
3047 locations->SetOut(Location::SameAsFirstInput());
3048}
3049
3050void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3051 HandleBitwiseOperation(instruction);
3052}
3053
3054void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3055 HandleBitwiseOperation(instruction);
3056}
3057
3058void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3059 HandleBitwiseOperation(instruction);
3060}
3061
3062void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3063 LocationSummary* locations = instruction->GetLocations();
3064 Location first = locations->InAt(0);
3065 Location second = locations->InAt(1);
3066 DCHECK(first.Equals(locations->Out()));
3067
3068 if (instruction->GetResultType() == Primitive::kPrimInt) {
3069 if (second.IsRegister()) {
3070 if (instruction->IsAnd()) {
3071 __ andl(first.As<CpuRegister>(), second.As<CpuRegister>());
3072 } else if (instruction->IsOr()) {
3073 __ orl(first.As<CpuRegister>(), second.As<CpuRegister>());
3074 } else {
3075 DCHECK(instruction->IsXor());
3076 __ xorl(first.As<CpuRegister>(), second.As<CpuRegister>());
3077 }
3078 } else if (second.IsConstant()) {
3079 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3080 if (instruction->IsAnd()) {
3081 __ andl(first.As<CpuRegister>(), imm);
3082 } else if (instruction->IsOr()) {
3083 __ orl(first.As<CpuRegister>(), imm);
3084 } else {
3085 DCHECK(instruction->IsXor());
3086 __ xorl(first.As<CpuRegister>(), imm);
3087 }
3088 } else {
3089 Address address(CpuRegister(RSP), second.GetStackIndex());
3090 if (instruction->IsAnd()) {
3091 __ andl(first.As<CpuRegister>(), address);
3092 } else if (instruction->IsOr()) {
3093 __ orl(first.As<CpuRegister>(), address);
3094 } else {
3095 DCHECK(instruction->IsXor());
3096 __ xorl(first.As<CpuRegister>(), address);
3097 }
3098 }
3099 } else {
3100 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3101 if (instruction->IsAnd()) {
3102 __ andq(first.As<CpuRegister>(), second.As<CpuRegister>());
3103 } else if (instruction->IsOr()) {
3104 __ orq(first.As<CpuRegister>(), second.As<CpuRegister>());
3105 } else {
3106 DCHECK(instruction->IsXor());
3107 __ xorq(first.As<CpuRegister>(), second.As<CpuRegister>());
3108 }
3109 }
3110}
3111
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003112} // namespace x86_64
3113} // namespace art