blob: e60f8a56909b6ae78969c41b0e801a43403d29f2 [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"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080021#include "intrinsics.h"
22#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070023#include "mirror/array-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010025#include "mirror/class.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010026#include "mirror/object_reference.h"
27#include "thread.h"
28#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010029#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "utils/x86_64/assembler_x86_64.h"
31#include "utils/x86_64/managed_register_x86_64.h"
32
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010033namespace art {
34
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010035namespace x86_64 {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037// Some x86_64 instructions require a register to be available as temp.
38static constexpr Register TMP = R11;
39
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040static constexpr int kCurrentMethodStackOffset = 0;
41
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
43static constexpr size_t kRuntimeParameterCoreRegistersLength =
44 arraysize(kRuntimeParameterCoreRegisters);
Calin Juravled2ec87d2014-12-08 14:24:46 +000045static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
46static constexpr size_t kRuntimeParameterFpuRegistersLength =
47 arraysize(kRuntimeParameterFpuRegisters);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000048static constexpr Register kFakeReturnRegister = Register(16);
49static constexpr Register kCoreCalleeSaves[] =
50 { RBX, RBP, R12, R13, R14, R15, kFakeReturnRegister };
51static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010052
Mark Mendell24f2dfa2015-01-14 19:51:45 -050053static constexpr int kC2ConditionMask = 0x400;
54
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010055class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056 public:
57 InvokeRuntimeCallingConvention()
58 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010059 kRuntimeParameterCoreRegistersLength,
60 kRuntimeParameterFpuRegisters,
61 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010062
63 private:
64 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
65};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010066
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
68
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010069class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072
73 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
74 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010075 __ gs()->call(
76 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +010077 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010078 }
79
80 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010081 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010082 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
83};
84
Calin Juravled0d48522014-11-04 16:40:20 +000085class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
86 public:
87 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
88
89 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
90 __ Bind(GetEntryLabel());
91 __ gs()->call(
92 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
93 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
94 }
95
96 private:
97 HDivZeroCheck* const instruction_;
98 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
99};
100
Calin Juravlebacfec32014-11-14 15:54:36 +0000101class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +0000102 public:
Calin Juravlebacfec32014-11-14 15:54:36 +0000103 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
104 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000105
106 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
107 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000108 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000109 if (is_div_) {
110 __ negl(cpu_reg_);
111 } else {
112 __ movl(cpu_reg_, Immediate(0));
113 }
114
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000115 } else {
116 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000117 if (is_div_) {
118 __ negq(cpu_reg_);
119 } else {
120 __ movq(cpu_reg_, Immediate(0));
121 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000122 }
Calin Juravled0d48522014-11-04 16:40:20 +0000123 __ jmp(GetExitLabel());
124 }
125
126 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000127 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000128 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000129 const bool is_div_;
130 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000131};
132
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100133class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000134 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100135 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
136 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137
138 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100139 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100141 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000142 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
143 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100144 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 if (successor_ == nullptr) {
146 __ jmp(GetReturnLabel());
147 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100148 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100149 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000150 }
151
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100152 Label* GetReturnLabel() {
153 DCHECK(successor_ == nullptr);
154 return &return_label_;
155 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156
157 private:
158 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100159 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000160 Label return_label_;
161
162 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
163};
164
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100165class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100166 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100167 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
168 Location index_location,
169 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100170 : instruction_(instruction),
171 index_location_(index_location),
172 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173
174 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100175 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000176 // We're moving two locations to locations that could overlap, so we need a parallel
177 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100178 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000179 codegen->EmitParallelMoves(
180 index_location_,
181 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
182 length_location_,
183 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100184 __ gs()->call(Address::Absolute(
185 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100186 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187 }
188
189 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100190 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100191 const Location index_location_;
192 const Location length_location_;
193
194 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
195};
196
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100198 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000199 LoadClassSlowPathX86_64(HLoadClass* cls,
200 HInstruction* at,
201 uint32_t dex_pc,
202 bool do_clinit)
203 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
204 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
205 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100206
207 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
210 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100211
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000212 codegen->SaveLiveRegisters(locations);
213
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100214 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100216 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000217 __ gs()->call(Address::Absolute((do_clinit_
218 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
219 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
220 codegen->RecordPcInfo(at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100221
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000222 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000223 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000224 if (out.IsValid()) {
225 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
226 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000227 }
228
229 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230 __ jmp(GetExitLabel());
231 }
232
233 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000234 // The class this slow path will load.
235 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100236
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 // The instruction where this slow path is happening.
238 // (Might be the load class or an initialization check).
239 HInstruction* const at_;
240
241 // The dex PC of `at_`.
242 const uint32_t dex_pc_;
243
244 // Whether to initialize the class.
245 const bool do_clinit_;
246
247 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100248};
249
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000250class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
251 public:
252 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
253
254 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
255 LocationSummary* locations = instruction_->GetLocations();
256 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
257
258 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
259 __ Bind(GetEntryLabel());
260 codegen->SaveLiveRegisters(locations);
261
262 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800263 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
264 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000265 Immediate(instruction_->GetStringIndex()));
266 __ gs()->call(Address::Absolute(
267 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
268 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
269 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
270 codegen->RestoreLiveRegisters(locations);
271 __ jmp(GetExitLabel());
272 }
273
274 private:
275 HLoadString* const instruction_;
276
277 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
278};
279
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
281 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000282 TypeCheckSlowPathX86_64(HInstruction* instruction,
283 Location class_to_check,
284 Location object_class,
285 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000287 class_to_check_(class_to_check),
288 object_class_(object_class),
289 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000290
291 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
292 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000293 DCHECK(instruction_->IsCheckCast()
294 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000295
296 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
297 __ Bind(GetEntryLabel());
298 codegen->SaveLiveRegisters(locations);
299
300 // We're moving two locations to locations that could overlap, so we need a parallel
301 // move resolver.
302 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000303 codegen->EmitParallelMoves(
304 class_to_check_,
305 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
306 object_class_,
307 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000308
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000309 if (instruction_->IsInstanceOf()) {
310 __ gs()->call(
311 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
312 } else {
313 DCHECK(instruction_->IsCheckCast());
314 __ gs()->call(
315 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
316 }
317 codegen->RecordPcInfo(instruction_, dex_pc_);
318
319 if (instruction_->IsInstanceOf()) {
320 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
321 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000322
323 codegen->RestoreLiveRegisters(locations);
324 __ jmp(GetExitLabel());
325 }
326
327 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000328 HInstruction* const instruction_;
329 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000330 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000331 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000332
333 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
334};
335
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100336#undef __
337#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
338
Dave Allison20dfc792014-06-16 20:44:29 -0700339inline Condition X86_64Condition(IfCondition cond) {
340 switch (cond) {
341 case kCondEQ: return kEqual;
342 case kCondNE: return kNotEqual;
343 case kCondLT: return kLess;
344 case kCondLE: return kLessEqual;
345 case kCondGT: return kGreater;
346 case kCondGE: return kGreaterEqual;
347 default:
348 LOG(FATAL) << "Unknown if condition";
349 }
350 return kEqual;
351}
352
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800353void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
354 CpuRegister temp) {
355 // All registers are assumed to be correctly set up.
356
357 // TODO: Implement all kinds of calls:
358 // 1) boot -> boot
359 // 2) app -> boot
360 // 3) app -> app
361 //
362 // Currently we implement the app -> app logic, which looks up in the resolve cache.
363
364 // temp = method;
365 LoadCurrentMethod(temp);
366 // temp = temp->dex_cache_resolved_methods_;
367 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
368 // temp = temp[index_in_cache]
369 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
370 // (temp + offset_of_quick_compiled_code)()
371 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
372 kX86_64WordSize).SizeValue()));
373
374 DCHECK(!IsLeafMethod());
375 RecordPcInfo(invoke, invoke->GetDexPc());
376}
377
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100378void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
379 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
380}
381
382void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
383 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
384}
385
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100386size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
387 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
388 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100389}
390
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100391size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
392 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
393 return kX86_64WordSize;
394}
395
396size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
397 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
398 return kX86_64WordSize;
399}
400
401size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
402 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
403 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100404}
405
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000406static uint32_t ComputeCalleeSaveMask(const int* registers, size_t length) {
Nicolas Geoffray98893962015-01-21 12:32:32 +0000407 uint32_t mask = 0;
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000408 for (size_t i = 0, e = length; i < e; ++i) {
409 mask |= (1 << registers[i]);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000410 }
411 return mask;
412}
413
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000414static constexpr int kNumberOfCpuRegisterPairs = 0;
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000415CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000416 : CodeGenerator(graph,
417 kNumberOfCpuRegisters,
418 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000419 kNumberOfCpuRegisterPairs,
420 ComputeCalleeSaveMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
421 arraysize(kCoreCalleeSaves)),
422 ComputeCalleeSaveMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
423 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000424 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100425 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000427 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000428 move_resolver_(graph->GetArena(), this) {
429 // Use a fake return address register to mimic Quick.
430 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
431}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100432
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100433InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
434 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100435 : HGraphVisitor(graph),
436 assembler_(codegen->GetAssembler()),
437 codegen_(codegen) {}
438
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100439Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100440 switch (type) {
441 case Primitive::kPrimLong:
442 case Primitive::kPrimByte:
443 case Primitive::kPrimBoolean:
444 case Primitive::kPrimChar:
445 case Primitive::kPrimShort:
446 case Primitive::kPrimInt:
447 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100448 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100449 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100450 }
451
452 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100453 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100454 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100455 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100456 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100457
458 case Primitive::kPrimVoid:
459 LOG(FATAL) << "Unreachable type " << type;
460 }
461
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100462 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100463}
464
Nicolas Geoffray98893962015-01-21 12:32:32 +0000465void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100466 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100467 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100468
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000469 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100470 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000471
Nicolas Geoffray98893962015-01-21 12:32:32 +0000472 if (is_baseline) {
473 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
474 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
475 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000476 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
477 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
478 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000479 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100480}
481
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100482void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100483 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700484 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000485 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100486
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000487 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100488 __ testq(CpuRegister(RAX), Address(
489 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100490 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100491 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000492
Nicolas Geoffray98893962015-01-21 12:32:32 +0000493 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000494 Register reg = kCoreCalleeSaves[i];
495 if (allocated_registers_.ContainsCoreRegister(reg) && reg != kFakeReturnRegister) {
496 __ pushq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000497 }
498 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100499
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000500 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
501 uint32_t xmm_spill_location = GetFpuSpillStart();
502 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100503
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000504 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
505 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
506 __ movsd(Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)),
507 XmmRegister(kFpuCalleeSaves[i]));
508 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100509 }
510
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100511 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
512}
513
514void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000515 uint32_t xmm_spill_location = GetFpuSpillStart();
516 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
517 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
518 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
519 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
520 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
521 }
522 }
523
524 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000525
526 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000527 Register reg = kCoreCalleeSaves[i];
528 if (allocated_registers_.ContainsCoreRegister(reg) && reg != kFakeReturnRegister) {
529 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000530 }
531 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100532}
533
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100534void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
535 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536}
537
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100538void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100539 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
540}
541
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100542Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
543 switch (load->GetType()) {
544 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100545 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100546 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
547 break;
548
549 case Primitive::kPrimInt:
550 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100551 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100552 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100553
554 case Primitive::kPrimBoolean:
555 case Primitive::kPrimByte:
556 case Primitive::kPrimChar:
557 case Primitive::kPrimShort:
558 case Primitive::kPrimVoid:
559 LOG(FATAL) << "Unexpected type " << load->GetType();
560 }
561
562 LOG(FATAL) << "Unreachable";
563 return Location();
564}
565
566void CodeGeneratorX86_64::Move(Location destination, Location source) {
567 if (source.Equals(destination)) {
568 return;
569 }
570 if (destination.IsRegister()) {
571 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000572 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100573 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000574 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100575 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000576 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100577 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100578 } else {
579 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000580 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100581 Address(CpuRegister(RSP), source.GetStackIndex()));
582 }
583 } else if (destination.IsFpuRegister()) {
584 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000585 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100586 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000587 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000589 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100590 Address(CpuRegister(RSP), source.GetStackIndex()));
591 } else {
592 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000593 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100595 }
596 } else if (destination.IsStackSlot()) {
597 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100598 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000599 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100600 } else if (source.IsFpuRegister()) {
601 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000602 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500603 } else if (source.IsConstant()) {
604 HConstant* constant = source.GetConstant();
605 int32_t value;
606 if (constant->IsFloatConstant()) {
607 value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
608 } else {
609 DCHECK(constant->IsIntConstant());
610 value = constant->AsIntConstant()->GetValue();
611 }
612 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100613 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500614 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000615 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
616 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100617 }
618 } else {
619 DCHECK(destination.IsDoubleStackSlot());
620 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100621 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000622 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100623 } else if (source.IsFpuRegister()) {
624 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000625 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500626 } else if (source.IsConstant()) {
627 HConstant* constant = source.GetConstant();
628 int64_t value = constant->AsLongConstant()->GetValue();
629 if (constant->IsDoubleConstant()) {
630 value = bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue());
631 } else {
632 DCHECK(constant->IsLongConstant());
633 value = constant->AsLongConstant()->GetValue();
634 }
635 __ movq(CpuRegister(TMP), Immediate(value));
636 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100637 } else {
638 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000639 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
640 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100641 }
642 }
643}
644
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100645void CodeGeneratorX86_64::Move(HInstruction* instruction,
646 Location location,
647 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000648 LocationSummary* locations = instruction->GetLocations();
649 if (locations != nullptr && locations->Out().Equals(location)) {
650 return;
651 }
652
653 if (locations != nullptr && locations->Out().IsConstant()) {
654 HConstant* const_to_move = locations->Out().GetConstant();
655 if (const_to_move->IsIntConstant()) {
656 Immediate imm(const_to_move->AsIntConstant()->GetValue());
657 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000658 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000659 } else if (location.IsStackSlot()) {
660 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
661 } else {
662 DCHECK(location.IsConstant());
663 DCHECK_EQ(location.GetConstant(), const_to_move);
664 }
665 } else if (const_to_move->IsLongConstant()) {
666 int64_t value = const_to_move->AsLongConstant()->GetValue();
667 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000668 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000669 } else if (location.IsDoubleStackSlot()) {
670 __ movq(CpuRegister(TMP), Immediate(value));
671 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
672 } else {
673 DCHECK(location.IsConstant());
674 DCHECK_EQ(location.GetConstant(), const_to_move);
675 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100676 }
Roland Levillain476df552014-10-09 17:51:36 +0100677 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100678 switch (instruction->GetType()) {
679 case Primitive::kPrimBoolean:
680 case Primitive::kPrimByte:
681 case Primitive::kPrimChar:
682 case Primitive::kPrimShort:
683 case Primitive::kPrimInt:
684 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100685 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100686 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
687 break;
688
689 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100690 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000691 Move(location,
692 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100693 break;
694
695 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100696 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100697 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000698 } else if (instruction->IsTemporary()) {
699 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
700 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100701 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100702 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100703 switch (instruction->GetType()) {
704 case Primitive::kPrimBoolean:
705 case Primitive::kPrimByte:
706 case Primitive::kPrimChar:
707 case Primitive::kPrimShort:
708 case Primitive::kPrimInt:
709 case Primitive::kPrimNot:
710 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100711 case Primitive::kPrimFloat:
712 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000713 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100714 break;
715
716 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100717 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100718 }
719 }
720}
721
722void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
723 got->SetLocations(nullptr);
724}
725
726void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
727 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100728 DCHECK(!successor->IsExitBlock());
729
730 HBasicBlock* block = got->GetBlock();
731 HInstruction* previous = got->GetPrevious();
732
733 HLoopInformation* info = block->GetLoopInformation();
734 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
735 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
736 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
737 return;
738 }
739
740 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
741 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
742 }
743 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100744 __ jmp(codegen_->GetLabelOf(successor));
745 }
746}
747
748void LocationsBuilderX86_64::VisitExit(HExit* exit) {
749 exit->SetLocations(nullptr);
750}
751
752void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700753 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100754 if (kIsDebugBuild) {
755 __ Comment("Unreachable");
756 __ int3();
757 }
758}
759
760void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100761 LocationSummary* locations =
762 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100763 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100764 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100765 locations->SetInAt(0, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100766 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100767}
768
769void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700770 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100771 if (cond->IsIntConstant()) {
772 // Constant condition, statically compared against 1.
773 int32_t cond_value = cond->AsIntConstant()->GetValue();
774 if (cond_value == 1) {
775 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
776 if_instr->IfTrueSuccessor())) {
777 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100778 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100779 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100780 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100781 DCHECK_EQ(cond_value, 0);
782 }
783 } else {
784 bool materialized =
785 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
786 // Moves do not affect the eflags register, so if the condition is
787 // evaluated just before the if, we don't need to evaluate it
788 // again.
789 bool eflags_set = cond->IsCondition()
790 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
791 if (materialized) {
792 if (!eflags_set) {
793 // Materialized condition, compare against 0.
794 Location lhs = if_instr->GetLocations()->InAt(0);
795 if (lhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000796 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(0));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100797 } else {
798 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
799 Immediate(0));
800 }
801 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
802 } else {
803 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
804 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
805 }
806 } else {
807 Location lhs = cond->GetLocations()->InAt(0);
808 Location rhs = cond->GetLocations()->InAt(1);
809 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000810 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100811 } else if (rhs.IsConstant()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000812 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100813 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
814 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000815 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100816 Address(CpuRegister(RSP), rhs.GetStackIndex()));
817 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100818 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
819 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700820 }
Dave Allison20dfc792014-06-16 20:44:29 -0700821 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100822 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
823 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700824 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100825 }
826}
827
828void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
829 local->SetLocations(nullptr);
830}
831
832void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
833 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
834}
835
836void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
837 local->SetLocations(nullptr);
838}
839
840void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
841 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700842 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100843}
844
845void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100846 LocationSummary* locations =
847 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100848 switch (store->InputAt(1)->GetType()) {
849 case Primitive::kPrimBoolean:
850 case Primitive::kPrimByte:
851 case Primitive::kPrimChar:
852 case Primitive::kPrimShort:
853 case Primitive::kPrimInt:
854 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100855 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100856 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
857 break;
858
859 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100860 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100861 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
862 break;
863
864 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100865 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100866 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100867}
868
869void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700870 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100871}
872
Dave Allison20dfc792014-06-16 20:44:29 -0700873void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100874 LocationSummary* locations =
875 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100876 locations->SetInAt(0, Location::RequiresRegister());
877 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100878 if (comp->NeedsMaterialization()) {
879 locations->SetOut(Location::RequiresRegister());
880 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100881}
882
Dave Allison20dfc792014-06-16 20:44:29 -0700883void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
884 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100885 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000886 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100887 // Clear register: setcc only sets the low byte.
888 __ xorq(reg, reg);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100889 if (locations->InAt(1).IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000890 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
891 locations->InAt(1).AsRegister<CpuRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100892 } else if (locations->InAt(1).IsConstant()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000893 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100894 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
895 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000896 __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100897 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
898 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100899 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700900 }
901}
902
903void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
904 VisitCondition(comp);
905}
906
907void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
908 VisitCondition(comp);
909}
910
911void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
912 VisitCondition(comp);
913}
914
915void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
916 VisitCondition(comp);
917}
918
919void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
920 VisitCondition(comp);
921}
922
923void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
924 VisitCondition(comp);
925}
926
927void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
928 VisitCondition(comp);
929}
930
931void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
932 VisitCondition(comp);
933}
934
935void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
936 VisitCondition(comp);
937}
938
939void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
940 VisitCondition(comp);
941}
942
943void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
944 VisitCondition(comp);
945}
946
947void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
948 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100949}
950
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100951void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100952 LocationSummary* locations =
953 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000954 switch (compare->InputAt(0)->GetType()) {
955 case Primitive::kPrimLong: {
956 locations->SetInAt(0, Location::RequiresRegister());
957 locations->SetInAt(1, Location::RequiresRegister());
958 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
959 break;
960 }
961 case Primitive::kPrimFloat:
962 case Primitive::kPrimDouble: {
963 locations->SetInAt(0, Location::RequiresFpuRegister());
964 locations->SetInAt(1, Location::RequiresFpuRegister());
965 locations->SetOut(Location::RequiresRegister());
966 break;
967 }
968 default:
969 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
970 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100971}
972
973void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100974 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000975 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +0000976 Location left = locations->InAt(0);
977 Location right = locations->InAt(1);
978
979 Label less, greater, done;
980 Primitive::Type type = compare->InputAt(0)->GetType();
981 switch (type) {
982 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000983 __ cmpq(left.AsRegister<CpuRegister>(), right.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100984 break;
Calin Juravleddb7df22014-11-25 20:56:51 +0000985 }
986 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000987 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000988 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
989 break;
990 }
991 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000992 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000993 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
994 break;
995 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100996 default:
Calin Juravleddb7df22014-11-25 20:56:51 +0000997 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100998 }
Calin Juravleddb7df22014-11-25 20:56:51 +0000999 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001000 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001001 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001002
Calin Juravle91debbc2014-11-26 19:01:09 +00001003 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001004 __ movl(out, Immediate(1));
1005 __ jmp(&done);
1006
1007 __ Bind(&less);
1008 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001009
1010 __ Bind(&done);
1011}
1012
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001013void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001014 LocationSummary* locations =
1015 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001016 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001017}
1018
1019void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001020 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001021 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001022}
1023
1024void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001025 LocationSummary* locations =
1026 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001027 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001028}
1029
1030void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001031 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001032 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001033}
1034
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001035void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1036 LocationSummary* locations =
1037 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1038 locations->SetOut(Location::ConstantLocation(constant));
1039}
1040
1041void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1042 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001043 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001044}
1045
1046void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1047 LocationSummary* locations =
1048 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1049 locations->SetOut(Location::ConstantLocation(constant));
1050}
1051
1052void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1053 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001054 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001055}
1056
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001057void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1058 ret->SetLocations(nullptr);
1059}
1060
1061void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001062 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001063 codegen_->GenerateFrameExit();
1064 __ ret();
1065}
1066
1067void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001068 LocationSummary* locations =
1069 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001070 switch (ret->InputAt(0)->GetType()) {
1071 case Primitive::kPrimBoolean:
1072 case Primitive::kPrimByte:
1073 case Primitive::kPrimChar:
1074 case Primitive::kPrimShort:
1075 case Primitive::kPrimInt:
1076 case Primitive::kPrimNot:
1077 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001078 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001079 break;
1080
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001081 case Primitive::kPrimFloat:
1082 case Primitive::kPrimDouble:
1083 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001084 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001085 break;
1086
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001087 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001088 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001089 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001090}
1091
1092void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1093 if (kIsDebugBuild) {
1094 switch (ret->InputAt(0)->GetType()) {
1095 case Primitive::kPrimBoolean:
1096 case Primitive::kPrimByte:
1097 case Primitive::kPrimChar:
1098 case Primitive::kPrimShort:
1099 case Primitive::kPrimInt:
1100 case Primitive::kPrimNot:
1101 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001103 break;
1104
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001105 case Primitive::kPrimFloat:
1106 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001107 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001108 XMM0);
1109 break;
1110
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001111 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001112 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001113 }
1114 }
1115 codegen_->GenerateFrameExit();
1116 __ ret();
1117}
1118
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001119Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1120 switch (type) {
1121 case Primitive::kPrimBoolean:
1122 case Primitive::kPrimByte:
1123 case Primitive::kPrimChar:
1124 case Primitive::kPrimShort:
1125 case Primitive::kPrimInt:
1126 case Primitive::kPrimNot: {
1127 uint32_t index = gp_index_++;
1128 stack_index_++;
1129 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001130 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001131 } else {
1132 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1133 }
1134 }
1135
1136 case Primitive::kPrimLong: {
1137 uint32_t index = gp_index_;
1138 stack_index_ += 2;
1139 if (index < calling_convention.GetNumberOfRegisters()) {
1140 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001141 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001142 } else {
1143 gp_index_ += 2;
1144 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1145 }
1146 }
1147
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001148 case Primitive::kPrimFloat: {
1149 uint32_t index = fp_index_++;
1150 stack_index_++;
1151 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001152 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001153 } else {
1154 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1155 }
1156 }
1157
1158 case Primitive::kPrimDouble: {
1159 uint32_t index = fp_index_++;
1160 stack_index_ += 2;
1161 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001162 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001163 } else {
1164 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1165 }
1166 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001167
1168 case Primitive::kPrimVoid:
1169 LOG(FATAL) << "Unexpected parameter type " << type;
1170 break;
1171 }
1172 return Location();
1173}
1174
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001175void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001176 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1177 if (intrinsic.TryDispatch(invoke)) {
1178 return;
1179 }
1180
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001181 HandleInvoke(invoke);
1182}
1183
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001184static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1185 if (invoke->GetLocations()->Intrinsified()) {
1186 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1187 intrinsic.Dispatch(invoke);
1188 return true;
1189 }
1190 return false;
1191}
1192
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001193void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001194 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1195 return;
1196 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001197
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001198 codegen_->GenerateStaticOrDirectCall(
1199 invoke,
1200 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001201}
1202
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001203void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001204 LocationSummary* locations =
1205 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001206 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001207
1208 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001209 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001210 HInstruction* input = invoke->InputAt(i);
1211 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1212 }
1213
1214 switch (invoke->GetType()) {
1215 case Primitive::kPrimBoolean:
1216 case Primitive::kPrimByte:
1217 case Primitive::kPrimChar:
1218 case Primitive::kPrimShort:
1219 case Primitive::kPrimInt:
1220 case Primitive::kPrimNot:
1221 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001222 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001223 break;
1224
1225 case Primitive::kPrimVoid:
1226 break;
1227
1228 case Primitive::kPrimDouble:
1229 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001230 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231 break;
1232 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001233}
1234
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001235void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001236 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1237 if (intrinsic.TryDispatch(invoke)) {
1238 return;
1239 }
1240
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001241 HandleInvoke(invoke);
1242}
1243
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001244void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001245 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1246 return;
1247 }
1248
Roland Levillain271ab9c2014-11-27 15:23:57 +00001249 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001250 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1251 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1252 LocationSummary* locations = invoke->GetLocations();
1253 Location receiver = locations->InAt(0);
1254 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1255 // temp = object->GetClass();
1256 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001257 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1258 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001259 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001260 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001261 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001262 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001263 // temp = temp->GetMethodAt(method_offset);
1264 __ movl(temp, Address(temp, method_offset));
1265 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001266 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001267 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001268
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001269 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001270 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001271}
1272
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001273void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1274 HandleInvoke(invoke);
1275 // Add the hidden argument.
1276 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1277}
1278
1279void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1280 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001281 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001282 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1283 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1284 LocationSummary* locations = invoke->GetLocations();
1285 Location receiver = locations->InAt(0);
1286 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1287
1288 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001289 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001290 Immediate(invoke->GetDexMethodIndex()));
1291
1292 // temp = object->GetClass();
1293 if (receiver.IsStackSlot()) {
1294 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1295 __ movl(temp, Address(temp, class_offset));
1296 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001297 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001298 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001299 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001300 // temp = temp->GetImtEntryAt(method_offset);
1301 __ movl(temp, Address(temp, method_offset));
1302 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001303 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001304 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001305
1306 DCHECK(!codegen_->IsLeafMethod());
1307 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1308}
1309
Roland Levillain88cb1752014-10-20 16:36:47 +01001310void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1311 LocationSummary* locations =
1312 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1313 switch (neg->GetResultType()) {
1314 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001315 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001316 locations->SetInAt(0, Location::RequiresRegister());
1317 locations->SetOut(Location::SameAsFirstInput());
1318 break;
1319
Roland Levillain88cb1752014-10-20 16:36:47 +01001320 case Primitive::kPrimFloat:
1321 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001322 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001323 locations->SetOut(Location::SameAsFirstInput());
1324 locations->AddTemp(Location::RequiresRegister());
1325 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001326 break;
1327
1328 default:
1329 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1330 }
1331}
1332
1333void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1334 LocationSummary* locations = neg->GetLocations();
1335 Location out = locations->Out();
1336 Location in = locations->InAt(0);
1337 switch (neg->GetResultType()) {
1338 case Primitive::kPrimInt:
1339 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001340 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001341 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001342 break;
1343
1344 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001345 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001346 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001347 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001348 break;
1349
Roland Levillain5368c212014-11-27 15:03:41 +00001350 case Primitive::kPrimFloat: {
1351 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001352 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1353 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001354 // Implement float negation with an exclusive or with value
1355 // 0x80000000 (mask for bit 31, representing the sign of a
1356 // single-precision floating-point number).
1357 __ movq(constant, Immediate(INT64_C(0x80000000)));
1358 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001359 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001360 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001361 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001362
Roland Levillain5368c212014-11-27 15:03:41 +00001363 case Primitive::kPrimDouble: {
1364 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001365 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1366 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001367 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001368 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001369 // a double-precision floating-point number).
1370 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1371 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001372 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001373 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001374 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001375
1376 default:
1377 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1378 }
1379}
1380
Roland Levillaindff1f282014-11-05 14:15:05 +00001381void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1382 LocationSummary* locations =
1383 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1384 Primitive::Type result_type = conversion->GetResultType();
1385 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001386 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001387 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 locations->SetInAt(0, Location::Any());
1395 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1396 break;
1397
1398 default:
1399 LOG(FATAL) << "Unexpected type conversion from " << input_type
1400 << " to " << result_type;
1401 }
1402 break;
1403
Roland Levillain01a8d712014-11-14 16:27:39 +00001404 case Primitive::kPrimShort:
1405 switch (input_type) {
1406 case Primitive::kPrimByte:
1407 case Primitive::kPrimInt:
1408 case Primitive::kPrimChar:
1409 // Processing a Dex `int-to-short' instruction.
1410 locations->SetInAt(0, Location::Any());
1411 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1412 break;
1413
1414 default:
1415 LOG(FATAL) << "Unexpected type conversion from " << input_type
1416 << " to " << result_type;
1417 }
1418 break;
1419
Roland Levillain946e1432014-11-11 17:35:19 +00001420 case Primitive::kPrimInt:
1421 switch (input_type) {
1422 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001423 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001424 locations->SetInAt(0, Location::Any());
1425 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1426 break;
1427
1428 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001429 // Processing a Dex `float-to-int' instruction.
1430 locations->SetInAt(0, Location::RequiresFpuRegister());
1431 locations->SetOut(Location::RequiresRegister());
1432 locations->AddTemp(Location::RequiresFpuRegister());
1433 break;
1434
Roland Levillain946e1432014-11-11 17:35:19 +00001435 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001436 // Processing a Dex `double-to-int' instruction.
1437 locations->SetInAt(0, Location::RequiresFpuRegister());
1438 locations->SetOut(Location::RequiresRegister());
1439 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001440 break;
1441
1442 default:
1443 LOG(FATAL) << "Unexpected type conversion from " << input_type
1444 << " to " << result_type;
1445 }
1446 break;
1447
Roland Levillaindff1f282014-11-05 14:15:05 +00001448 case Primitive::kPrimLong:
1449 switch (input_type) {
1450 case Primitive::kPrimByte:
1451 case Primitive::kPrimShort:
1452 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001453 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001454 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001455 // TODO: We would benefit from a (to-be-implemented)
1456 // Location::RegisterOrStackSlot requirement for this input.
1457 locations->SetInAt(0, Location::RequiresRegister());
1458 locations->SetOut(Location::RequiresRegister());
1459 break;
1460
1461 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001462 // Processing a Dex `float-to-long' instruction.
1463 locations->SetInAt(0, Location::RequiresFpuRegister());
1464 locations->SetOut(Location::RequiresRegister());
1465 locations->AddTemp(Location::RequiresFpuRegister());
1466 break;
1467
Roland Levillaindff1f282014-11-05 14:15:05 +00001468 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001469 // Processing a Dex `double-to-long' instruction.
1470 locations->SetInAt(0, Location::RequiresFpuRegister());
1471 locations->SetOut(Location::RequiresRegister());
1472 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001473 break;
1474
1475 default:
1476 LOG(FATAL) << "Unexpected type conversion from " << input_type
1477 << " to " << result_type;
1478 }
1479 break;
1480
Roland Levillain981e4542014-11-14 11:47:14 +00001481 case Primitive::kPrimChar:
1482 switch (input_type) {
1483 case Primitive::kPrimByte:
1484 case Primitive::kPrimShort:
1485 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001486 // Processing a Dex `int-to-char' instruction.
1487 locations->SetInAt(0, Location::Any());
1488 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1489 break;
1490
1491 default:
1492 LOG(FATAL) << "Unexpected type conversion from " << input_type
1493 << " to " << result_type;
1494 }
1495 break;
1496
Roland Levillaindff1f282014-11-05 14:15:05 +00001497 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001498 switch (input_type) {
1499 case Primitive::kPrimByte:
1500 case Primitive::kPrimShort:
1501 case Primitive::kPrimInt:
1502 case Primitive::kPrimChar:
1503 // Processing a Dex `int-to-float' instruction.
1504 locations->SetInAt(0, Location::RequiresRegister());
1505 locations->SetOut(Location::RequiresFpuRegister());
1506 break;
1507
1508 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001509 // Processing a Dex `long-to-float' instruction.
1510 locations->SetInAt(0, Location::RequiresRegister());
1511 locations->SetOut(Location::RequiresFpuRegister());
1512 break;
1513
Roland Levillaincff13742014-11-17 14:32:17 +00001514 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001515 // Processing a Dex `double-to-float' instruction.
1516 locations->SetInAt(0, Location::RequiresFpuRegister());
1517 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001518 break;
1519
1520 default:
1521 LOG(FATAL) << "Unexpected type conversion from " << input_type
1522 << " to " << result_type;
1523 };
1524 break;
1525
Roland Levillaindff1f282014-11-05 14:15:05 +00001526 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001527 switch (input_type) {
1528 case Primitive::kPrimByte:
1529 case Primitive::kPrimShort:
1530 case Primitive::kPrimInt:
1531 case Primitive::kPrimChar:
1532 // Processing a Dex `int-to-double' instruction.
1533 locations->SetInAt(0, Location::RequiresRegister());
1534 locations->SetOut(Location::RequiresFpuRegister());
1535 break;
1536
1537 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001538 // Processing a Dex `long-to-double' instruction.
1539 locations->SetInAt(0, Location::RequiresRegister());
1540 locations->SetOut(Location::RequiresFpuRegister());
1541 break;
1542
Roland Levillaincff13742014-11-17 14:32:17 +00001543 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001544 // Processing a Dex `float-to-double' instruction.
1545 locations->SetInAt(0, Location::RequiresFpuRegister());
1546 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001547 break;
1548
1549 default:
1550 LOG(FATAL) << "Unexpected type conversion from " << input_type
1551 << " to " << result_type;
1552 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001553 break;
1554
1555 default:
1556 LOG(FATAL) << "Unexpected type conversion from " << input_type
1557 << " to " << result_type;
1558 }
1559}
1560
1561void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1562 LocationSummary* locations = conversion->GetLocations();
1563 Location out = locations->Out();
1564 Location in = locations->InAt(0);
1565 Primitive::Type result_type = conversion->GetResultType();
1566 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001567 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001568 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001569 case Primitive::kPrimByte:
1570 switch (input_type) {
1571 case Primitive::kPrimShort:
1572 case Primitive::kPrimInt:
1573 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001574 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001575 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001576 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001577 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001578 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001579 Address(CpuRegister(RSP), in.GetStackIndex()));
1580 } else {
1581 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001582 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001583 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1584 }
1585 break;
1586
1587 default:
1588 LOG(FATAL) << "Unexpected type conversion from " << input_type
1589 << " to " << result_type;
1590 }
1591 break;
1592
Roland Levillain01a8d712014-11-14 16:27:39 +00001593 case Primitive::kPrimShort:
1594 switch (input_type) {
1595 case Primitive::kPrimByte:
1596 case Primitive::kPrimInt:
1597 case Primitive::kPrimChar:
1598 // Processing a Dex `int-to-short' instruction.
1599 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001600 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001601 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001602 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001603 Address(CpuRegister(RSP), in.GetStackIndex()));
1604 } else {
1605 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001606 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001607 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1608 }
1609 break;
1610
1611 default:
1612 LOG(FATAL) << "Unexpected type conversion from " << input_type
1613 << " to " << result_type;
1614 }
1615 break;
1616
Roland Levillain946e1432014-11-11 17:35:19 +00001617 case Primitive::kPrimInt:
1618 switch (input_type) {
1619 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001620 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001621 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001622 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001623 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001624 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001625 Address(CpuRegister(RSP), in.GetStackIndex()));
1626 } else {
1627 DCHECK(in.IsConstant());
1628 DCHECK(in.GetConstant()->IsLongConstant());
1629 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001630 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001631 }
1632 break;
1633
Roland Levillain3f8f9362014-12-02 17:45:01 +00001634 case Primitive::kPrimFloat: {
1635 // Processing a Dex `float-to-int' instruction.
1636 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1637 CpuRegister output = out.AsRegister<CpuRegister>();
1638 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1639 Label done, nan;
1640
1641 __ movl(output, Immediate(kPrimIntMax));
1642 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001643 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001644 // if input >= temp goto done
1645 __ comiss(input, temp);
1646 __ j(kAboveEqual, &done);
1647 // if input == NaN goto nan
1648 __ j(kUnordered, &nan);
1649 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001650 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001651 __ jmp(&done);
1652 __ Bind(&nan);
1653 // output = 0
1654 __ xorl(output, output);
1655 __ Bind(&done);
1656 break;
1657 }
1658
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001659 case Primitive::kPrimDouble: {
1660 // Processing a Dex `double-to-int' instruction.
1661 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1662 CpuRegister output = out.AsRegister<CpuRegister>();
1663 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1664 Label done, nan;
1665
1666 __ movl(output, Immediate(kPrimIntMax));
1667 // temp = int-to-double(output)
1668 __ cvtsi2sd(temp, output);
1669 // if input >= temp goto done
1670 __ comisd(input, temp);
1671 __ j(kAboveEqual, &done);
1672 // if input == NaN goto nan
1673 __ j(kUnordered, &nan);
1674 // output = double-to-int-truncate(input)
1675 __ cvttsd2si(output, input);
1676 __ jmp(&done);
1677 __ Bind(&nan);
1678 // output = 0
1679 __ xorl(output, output);
1680 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001681 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001682 }
Roland Levillain946e1432014-11-11 17:35:19 +00001683
1684 default:
1685 LOG(FATAL) << "Unexpected type conversion from " << input_type
1686 << " to " << result_type;
1687 }
1688 break;
1689
Roland Levillaindff1f282014-11-05 14:15:05 +00001690 case Primitive::kPrimLong:
1691 switch (input_type) {
1692 DCHECK(out.IsRegister());
1693 case Primitive::kPrimByte:
1694 case Primitive::kPrimShort:
1695 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001696 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001697 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001698 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001699 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001700 break;
1701
Roland Levillain624279f2014-12-04 11:54:28 +00001702 case Primitive::kPrimFloat: {
1703 // Processing a Dex `float-to-long' instruction.
1704 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1705 CpuRegister output = out.AsRegister<CpuRegister>();
1706 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1707 Label done, nan;
1708
1709 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001710 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001711 __ cvtsi2ss(temp, output, true);
1712 // if input >= temp goto done
1713 __ comiss(input, temp);
1714 __ j(kAboveEqual, &done);
1715 // if input == NaN goto nan
1716 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001717 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001718 __ cvttss2si(output, input, true);
1719 __ jmp(&done);
1720 __ Bind(&nan);
1721 // output = 0
1722 __ xorq(output, output);
1723 __ Bind(&done);
1724 break;
1725 }
1726
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001727 case Primitive::kPrimDouble: {
1728 // Processing a Dex `double-to-long' instruction.
1729 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1730 CpuRegister output = out.AsRegister<CpuRegister>();
1731 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1732 Label done, nan;
1733
1734 __ movq(output, Immediate(kPrimLongMax));
1735 // temp = long-to-double(output)
1736 __ cvtsi2sd(temp, output, true);
1737 // if input >= temp goto done
1738 __ comisd(input, temp);
1739 __ j(kAboveEqual, &done);
1740 // if input == NaN goto nan
1741 __ j(kUnordered, &nan);
1742 // output = double-to-long-truncate(input)
1743 __ cvttsd2si(output, input, true);
1744 __ jmp(&done);
1745 __ Bind(&nan);
1746 // output = 0
1747 __ xorq(output, output);
1748 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001749 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001750 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001751
1752 default:
1753 LOG(FATAL) << "Unexpected type conversion from " << input_type
1754 << " to " << result_type;
1755 }
1756 break;
1757
Roland Levillain981e4542014-11-14 11:47:14 +00001758 case Primitive::kPrimChar:
1759 switch (input_type) {
1760 case Primitive::kPrimByte:
1761 case Primitive::kPrimShort:
1762 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001763 // Processing a Dex `int-to-char' instruction.
1764 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001765 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001766 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001767 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001768 Address(CpuRegister(RSP), in.GetStackIndex()));
1769 } else {
1770 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001771 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001772 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1773 }
1774 break;
1775
1776 default:
1777 LOG(FATAL) << "Unexpected type conversion from " << input_type
1778 << " to " << result_type;
1779 }
1780 break;
1781
Roland Levillaindff1f282014-11-05 14:15:05 +00001782 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001783 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001784 case Primitive::kPrimByte:
1785 case Primitive::kPrimShort:
1786 case Primitive::kPrimInt:
1787 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001788 // Processing a Dex `int-to-float' instruction.
1789 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001790 break;
1791
1792 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001793 // Processing a Dex `long-to-float' instruction.
1794 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1795 break;
1796
Roland Levillaincff13742014-11-17 14:32:17 +00001797 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001798 // Processing a Dex `double-to-float' instruction.
1799 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001800 break;
1801
1802 default:
1803 LOG(FATAL) << "Unexpected type conversion from " << input_type
1804 << " to " << result_type;
1805 };
1806 break;
1807
Roland Levillaindff1f282014-11-05 14:15:05 +00001808 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001809 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001810 case Primitive::kPrimByte:
1811 case Primitive::kPrimShort:
1812 case Primitive::kPrimInt:
1813 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001814 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001815 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001816 break;
1817
1818 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001819 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001820 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001821 break;
1822
Roland Levillaincff13742014-11-17 14:32:17 +00001823 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001824 // Processing a Dex `float-to-double' instruction.
1825 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001826 break;
1827
1828 default:
1829 LOG(FATAL) << "Unexpected type conversion from " << input_type
1830 << " to " << result_type;
1831 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001832 break;
1833
1834 default:
1835 LOG(FATAL) << "Unexpected type conversion from " << input_type
1836 << " to " << result_type;
1837 }
1838}
1839
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001840void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001841 LocationSummary* locations =
1842 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001843 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001844 case Primitive::kPrimInt: {
1845 locations->SetInAt(0, Location::RequiresRegister());
1846 locations->SetInAt(1, Location::Any());
1847 locations->SetOut(Location::SameAsFirstInput());
1848 break;
1849 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001850
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001851 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001852 locations->SetInAt(0, Location::RequiresRegister());
1853 locations->SetInAt(1, Location::RequiresRegister());
1854 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001855 break;
1856 }
1857
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001858 case Primitive::kPrimDouble:
1859 case Primitive::kPrimFloat: {
1860 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001861 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001862 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001863 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001864 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001865
1866 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001867 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001868 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001869}
1870
1871void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1872 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001873 Location first = locations->InAt(0);
1874 Location second = locations->InAt(1);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001875 DCHECK(first.Equals(locations->Out()));
Calin Juravle11351682014-10-23 15:38:15 +01001876
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001877 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001878 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001879 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001880 __ addl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001881 } else if (second.IsConstant()) {
Calin Juravle11351682014-10-23 15:38:15 +01001882 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001883 __ addl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001884 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001885 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001886 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001887 break;
1888 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001889
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001890 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001891 __ addq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001892 break;
1893 }
1894
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001895 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001896 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001897 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001898 }
1899
1900 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001901 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001902 break;
1903 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001904
1905 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001906 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001907 }
1908}
1909
1910void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001911 LocationSummary* locations =
1912 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001913 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001914 case Primitive::kPrimInt: {
1915 locations->SetInAt(0, Location::RequiresRegister());
1916 locations->SetInAt(1, Location::Any());
1917 locations->SetOut(Location::SameAsFirstInput());
1918 break;
1919 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001920 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001921 locations->SetInAt(0, Location::RequiresRegister());
1922 locations->SetInAt(1, Location::RequiresRegister());
1923 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001924 break;
1925 }
Calin Juravle11351682014-10-23 15:38:15 +01001926 case Primitive::kPrimFloat:
1927 case Primitive::kPrimDouble: {
1928 locations->SetInAt(0, Location::RequiresFpuRegister());
1929 locations->SetInAt(1, Location::RequiresFpuRegister());
1930 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001931 break;
Calin Juravle11351682014-10-23 15:38:15 +01001932 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001933 default:
Calin Juravle11351682014-10-23 15:38:15 +01001934 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001935 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001936}
1937
1938void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1939 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001940 Location first = locations->InAt(0);
1941 Location second = locations->InAt(1);
1942 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001943 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001944 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001945 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001946 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001947 } else if (second.IsConstant()) {
1948 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001949 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001950 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001951 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001952 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001953 break;
1954 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001955 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001956 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001957 break;
1958 }
1959
Calin Juravle11351682014-10-23 15:38:15 +01001960 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001961 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001962 break;
Calin Juravle11351682014-10-23 15:38:15 +01001963 }
1964
1965 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001966 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001967 break;
1968 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001969
1970 default:
Calin Juravle11351682014-10-23 15:38:15 +01001971 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001972 }
1973}
1974
Calin Juravle34bacdf2014-10-07 20:23:36 +01001975void LocationsBuilderX86_64::VisitMul(HMul* mul) {
1976 LocationSummary* locations =
1977 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1978 switch (mul->GetResultType()) {
1979 case Primitive::kPrimInt: {
1980 locations->SetInAt(0, Location::RequiresRegister());
1981 locations->SetInAt(1, Location::Any());
1982 locations->SetOut(Location::SameAsFirstInput());
1983 break;
1984 }
1985 case Primitive::kPrimLong: {
1986 locations->SetInAt(0, Location::RequiresRegister());
1987 locations->SetInAt(1, Location::RequiresRegister());
1988 locations->SetOut(Location::SameAsFirstInput());
1989 break;
1990 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001991 case Primitive::kPrimFloat:
1992 case Primitive::kPrimDouble: {
1993 locations->SetInAt(0, Location::RequiresFpuRegister());
1994 locations->SetInAt(1, Location::RequiresFpuRegister());
1995 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001996 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001997 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001998
1999 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002000 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002001 }
2002}
2003
2004void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2005 LocationSummary* locations = mul->GetLocations();
2006 Location first = locations->InAt(0);
2007 Location second = locations->InAt(1);
2008 DCHECK(first.Equals(locations->Out()));
2009 switch (mul->GetResultType()) {
2010 case Primitive::kPrimInt: {
2011 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002012 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002013 } else if (second.IsConstant()) {
2014 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002015 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002016 } else {
2017 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002018 __ imull(first.AsRegister<CpuRegister>(),
2019 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002020 }
2021 break;
2022 }
2023 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002024 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002025 break;
2026 }
2027
Calin Juravleb5bfa962014-10-21 18:02:24 +01002028 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002029 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002030 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002031 }
2032
2033 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002034 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002035 break;
2036 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002037
2038 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002039 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002040 }
2041}
2042
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002043void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2044 uint32_t stack_adjustment, bool is_float) {
2045 if (source.IsStackSlot()) {
2046 DCHECK(is_float);
2047 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2048 } else if (source.IsDoubleStackSlot()) {
2049 DCHECK(!is_float);
2050 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2051 } else {
2052 // Write the value to the temporary location on the stack and load to FP stack.
2053 if (is_float) {
2054 Location stack_temp = Location::StackSlot(temp_offset);
2055 codegen_->Move(stack_temp, source);
2056 __ flds(Address(CpuRegister(RSP), temp_offset));
2057 } else {
2058 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2059 codegen_->Move(stack_temp, source);
2060 __ fldl(Address(CpuRegister(RSP), temp_offset));
2061 }
2062 }
2063}
2064
2065void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2066 Primitive::Type type = rem->GetResultType();
2067 bool is_float = type == Primitive::kPrimFloat;
2068 size_t elem_size = Primitive::ComponentSize(type);
2069 LocationSummary* locations = rem->GetLocations();
2070 Location first = locations->InAt(0);
2071 Location second = locations->InAt(1);
2072 Location out = locations->Out();
2073
2074 // Create stack space for 2 elements.
2075 // TODO: enhance register allocator to ask for stack temporaries.
2076 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2077
2078 // Load the values to the FP stack in reverse order, using temporaries if needed.
2079 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2080 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2081
2082 // Loop doing FPREM until we stabilize.
2083 Label retry;
2084 __ Bind(&retry);
2085 __ fprem();
2086
2087 // Move FP status to AX.
2088 __ fstsw();
2089
2090 // And see if the argument reduction is complete. This is signaled by the
2091 // C2 FPU flag bit set to 0.
2092 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2093 __ j(kNotEqual, &retry);
2094
2095 // We have settled on the final value. Retrieve it into an XMM register.
2096 // Store FP top of stack to real stack.
2097 if (is_float) {
2098 __ fsts(Address(CpuRegister(RSP), 0));
2099 } else {
2100 __ fstl(Address(CpuRegister(RSP), 0));
2101 }
2102
2103 // Pop the 2 items from the FP stack.
2104 __ fucompp();
2105
2106 // Load the value from the stack into an XMM register.
2107 DCHECK(out.IsFpuRegister()) << out;
2108 if (is_float) {
2109 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2110 } else {
2111 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2112 }
2113
2114 // And remove the temporary stack space we allocated.
2115 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2116}
2117
Calin Juravlebacfec32014-11-14 15:54:36 +00002118void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2119 DCHECK(instruction->IsDiv() || instruction->IsRem());
2120 Primitive::Type type = instruction->GetResultType();
2121 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2122
2123 bool is_div = instruction->IsDiv();
2124 LocationSummary* locations = instruction->GetLocations();
2125
Roland Levillain271ab9c2014-11-27 15:23:57 +00002126 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2127 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002128
Roland Levillain271ab9c2014-11-27 15:23:57 +00002129 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002130 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2131
2132 SlowPathCodeX86_64* slow_path =
2133 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2134 out_reg.AsRegister(), type, is_div);
2135 codegen_->AddSlowPath(slow_path);
2136
2137 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2138 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2139 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002140 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002141 __ cmpl(second_reg, Immediate(-1));
2142 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002143 // edx:eax <- sign-extended of eax
2144 __ cdq();
2145 // eax = quotient, edx = remainder
2146 __ idivl(second_reg);
2147 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002148 __ cmpq(second_reg, Immediate(-1));
2149 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002150 // rdx:rax <- sign-extended of rax
2151 __ cqo();
2152 // rax = quotient, rdx = remainder
2153 __ idivq(second_reg);
2154 }
2155
2156 __ Bind(slow_path->GetExitLabel());
2157}
2158
Calin Juravle7c4954d2014-10-28 16:57:40 +00002159void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2160 LocationSummary* locations =
2161 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2162 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002163 case Primitive::kPrimInt:
2164 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002165 locations->SetInAt(0, Location::RegisterLocation(RAX));
2166 locations->SetInAt(1, Location::RequiresRegister());
2167 locations->SetOut(Location::SameAsFirstInput());
2168 // Intel uses edx:eax as the dividend.
2169 locations->AddTemp(Location::RegisterLocation(RDX));
2170 break;
2171 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002172
Calin Juravle7c4954d2014-10-28 16:57:40 +00002173 case Primitive::kPrimFloat:
2174 case Primitive::kPrimDouble: {
2175 locations->SetInAt(0, Location::RequiresFpuRegister());
2176 locations->SetInAt(1, Location::RequiresFpuRegister());
2177 locations->SetOut(Location::SameAsFirstInput());
2178 break;
2179 }
2180
2181 default:
2182 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2183 }
2184}
2185
2186void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2187 LocationSummary* locations = div->GetLocations();
2188 Location first = locations->InAt(0);
2189 Location second = locations->InAt(1);
2190 DCHECK(first.Equals(locations->Out()));
2191
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002192 Primitive::Type type = div->GetResultType();
2193 switch (type) {
2194 case Primitive::kPrimInt:
2195 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002196 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002197 break;
2198 }
2199
Calin Juravle7c4954d2014-10-28 16:57:40 +00002200 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002201 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002202 break;
2203 }
2204
2205 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002206 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002207 break;
2208 }
2209
2210 default:
2211 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2212 }
2213}
2214
Calin Juravlebacfec32014-11-14 15:54:36 +00002215void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002216 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002217 LocationSummary* locations =
2218 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002219
2220 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002221 case Primitive::kPrimInt:
2222 case Primitive::kPrimLong: {
2223 locations->SetInAt(0, Location::RegisterLocation(RAX));
2224 locations->SetInAt(1, Location::RequiresRegister());
2225 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2226 locations->SetOut(Location::RegisterLocation(RDX));
2227 break;
2228 }
2229
2230 case Primitive::kPrimFloat:
2231 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002232 locations->SetInAt(0, Location::Any());
2233 locations->SetInAt(1, Location::Any());
2234 locations->SetOut(Location::RequiresFpuRegister());
2235 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002236 break;
2237 }
2238
2239 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002240 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002241 }
2242}
2243
2244void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2245 Primitive::Type type = rem->GetResultType();
2246 switch (type) {
2247 case Primitive::kPrimInt:
2248 case Primitive::kPrimLong: {
2249 GenerateDivRemIntegral(rem);
2250 break;
2251 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002252 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002253 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002254 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002255 break;
2256 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002257 default:
2258 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2259 }
2260}
2261
Calin Juravled0d48522014-11-04 16:40:20 +00002262void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2263 LocationSummary* locations =
2264 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2265 locations->SetInAt(0, Location::Any());
2266 if (instruction->HasUses()) {
2267 locations->SetOut(Location::SameAsFirstInput());
2268 }
2269}
2270
2271void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2272 SlowPathCodeX86_64* slow_path =
2273 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2274 codegen_->AddSlowPath(slow_path);
2275
2276 LocationSummary* locations = instruction->GetLocations();
2277 Location value = locations->InAt(0);
2278
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002279 switch (instruction->GetType()) {
2280 case Primitive::kPrimInt: {
2281 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002282 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002283 __ j(kEqual, slow_path->GetEntryLabel());
2284 } else if (value.IsStackSlot()) {
2285 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2286 __ j(kEqual, slow_path->GetEntryLabel());
2287 } else {
2288 DCHECK(value.IsConstant()) << value;
2289 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2290 __ jmp(slow_path->GetEntryLabel());
2291 }
2292 }
2293 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002294 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002295 case Primitive::kPrimLong: {
2296 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002297 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002298 __ j(kEqual, slow_path->GetEntryLabel());
2299 } else if (value.IsDoubleStackSlot()) {
2300 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2301 __ j(kEqual, slow_path->GetEntryLabel());
2302 } else {
2303 DCHECK(value.IsConstant()) << value;
2304 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2305 __ jmp(slow_path->GetEntryLabel());
2306 }
2307 }
2308 break;
2309 }
2310 default:
2311 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002312 }
Calin Juravled0d48522014-11-04 16:40:20 +00002313}
2314
Calin Juravle9aec02f2014-11-18 23:06:35 +00002315void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2316 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2317
2318 LocationSummary* locations =
2319 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2320
2321 switch (op->GetResultType()) {
2322 case Primitive::kPrimInt:
2323 case Primitive::kPrimLong: {
2324 locations->SetInAt(0, Location::RequiresRegister());
2325 // The shift count needs to be in CL.
2326 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2327 locations->SetOut(Location::SameAsFirstInput());
2328 break;
2329 }
2330 default:
2331 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2332 }
2333}
2334
2335void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2336 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2337
2338 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002339 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002340 Location second = locations->InAt(1);
2341
2342 switch (op->GetResultType()) {
2343 case Primitive::kPrimInt: {
2344 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002345 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002346 if (op->IsShl()) {
2347 __ shll(first_reg, second_reg);
2348 } else if (op->IsShr()) {
2349 __ sarl(first_reg, second_reg);
2350 } else {
2351 __ shrl(first_reg, second_reg);
2352 }
2353 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002354 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002355 if (op->IsShl()) {
2356 __ shll(first_reg, imm);
2357 } else if (op->IsShr()) {
2358 __ sarl(first_reg, imm);
2359 } else {
2360 __ shrl(first_reg, imm);
2361 }
2362 }
2363 break;
2364 }
2365 case Primitive::kPrimLong: {
2366 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002367 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002368 if (op->IsShl()) {
2369 __ shlq(first_reg, second_reg);
2370 } else if (op->IsShr()) {
2371 __ sarq(first_reg, second_reg);
2372 } else {
2373 __ shrq(first_reg, second_reg);
2374 }
2375 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002376 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002377 if (op->IsShl()) {
2378 __ shlq(first_reg, imm);
2379 } else if (op->IsShr()) {
2380 __ sarq(first_reg, imm);
2381 } else {
2382 __ shrq(first_reg, imm);
2383 }
2384 }
2385 break;
2386 }
2387 default:
2388 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2389 }
2390}
2391
2392void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2393 HandleShift(shl);
2394}
2395
2396void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2397 HandleShift(shl);
2398}
2399
2400void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2401 HandleShift(shr);
2402}
2403
2404void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2405 HandleShift(shr);
2406}
2407
2408void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2409 HandleShift(ushr);
2410}
2411
2412void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2413 HandleShift(ushr);
2414}
2415
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002416void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002417 LocationSummary* locations =
2418 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002419 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002420 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2421 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2422 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002423}
2424
2425void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2426 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002427 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002428 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2429
2430 __ gs()->call(Address::Absolute(
2431 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
2432
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002433 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002434 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002435}
2436
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002437void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2438 LocationSummary* locations =
2439 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2440 InvokeRuntimeCallingConvention calling_convention;
2441 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002442 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002443 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002444 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002445}
2446
2447void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2448 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002449 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002450 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2451
2452 __ gs()->call(Address::Absolute(
2453 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true));
2454
2455 DCHECK(!codegen_->IsLeafMethod());
2456 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2457}
2458
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002459void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002460 LocationSummary* locations =
2461 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002462 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2463 if (location.IsStackSlot()) {
2464 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2465 } else if (location.IsDoubleStackSlot()) {
2466 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2467 }
2468 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002469}
2470
2471void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2472 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002473 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002474}
2475
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002476void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002477 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002478 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002479 locations->SetInAt(0, Location::RequiresRegister());
2480 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002481}
2482
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002483void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2484 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002485 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2486 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002487 Location out = locations->Out();
2488 switch (not_->InputAt(0)->GetType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002489 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002490 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002491 break;
2492
2493 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002494 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002495 break;
2496
2497 default:
2498 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2499 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002500}
2501
2502void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002503 LocationSummary* locations =
2504 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002505 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2506 locations->SetInAt(i, Location::Any());
2507 }
2508 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002509}
2510
2511void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002512 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002513 LOG(FATAL) << "Unimplemented";
2514}
2515
Calin Juravle52c48962014-12-16 17:02:57 +00002516void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2517 /*
2518 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2519 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2520 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2521 */
2522 switch (kind) {
2523 case MemBarrierKind::kAnyAny: {
2524 __ mfence();
2525 break;
2526 }
2527 case MemBarrierKind::kAnyStore:
2528 case MemBarrierKind::kLoadAny:
2529 case MemBarrierKind::kStoreStore: {
2530 // nop
2531 break;
2532 }
2533 default:
2534 LOG(FATAL) << "Unexpected memory barier " << kind;
2535 }
2536}
2537
2538void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2539 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2540
Nicolas Geoffray39468442014-09-02 15:17:15 +01002541 LocationSummary* locations =
2542 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002543 locations->SetInAt(0, Location::RequiresRegister());
2544 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2545}
2546
2547void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2548 const FieldInfo& field_info) {
2549 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2550
2551 LocationSummary* locations = instruction->GetLocations();
2552 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2553 Location out = locations->Out();
2554 bool is_volatile = field_info.IsVolatile();
2555 Primitive::Type field_type = field_info.GetFieldType();
2556 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2557
2558 switch (field_type) {
2559 case Primitive::kPrimBoolean: {
2560 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2561 break;
2562 }
2563
2564 case Primitive::kPrimByte: {
2565 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2566 break;
2567 }
2568
2569 case Primitive::kPrimShort: {
2570 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2571 break;
2572 }
2573
2574 case Primitive::kPrimChar: {
2575 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2576 break;
2577 }
2578
2579 case Primitive::kPrimInt:
2580 case Primitive::kPrimNot: {
2581 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2582 break;
2583 }
2584
2585 case Primitive::kPrimLong: {
2586 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2587 break;
2588 }
2589
2590 case Primitive::kPrimFloat: {
2591 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2592 break;
2593 }
2594
2595 case Primitive::kPrimDouble: {
2596 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2597 break;
2598 }
2599
2600 case Primitive::kPrimVoid:
2601 LOG(FATAL) << "Unreachable type " << field_type;
2602 UNREACHABLE();
2603 }
2604
Calin Juravle77520bc2015-01-12 18:45:46 +00002605 codegen_->MaybeRecordImplicitNullCheck(instruction);
2606
Calin Juravle52c48962014-12-16 17:02:57 +00002607 if (is_volatile) {
2608 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2609 }
2610}
2611
2612void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2613 const FieldInfo& field_info) {
2614 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2615
2616 LocationSummary* locations =
2617 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002618 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002619 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2620
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002621 locations->SetInAt(0, Location::RequiresRegister());
2622 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002623 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002624 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002625 locations->AddTemp(Location::RequiresRegister());
2626 locations->AddTemp(Location::RequiresRegister());
2627 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002628}
2629
Calin Juravle52c48962014-12-16 17:02:57 +00002630void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2631 const FieldInfo& field_info) {
2632 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2633
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002634 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002635 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2636 Location value = locations->InAt(1);
2637 bool is_volatile = field_info.IsVolatile();
2638 Primitive::Type field_type = field_info.GetFieldType();
2639 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2640
2641 if (is_volatile) {
2642 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2643 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002644
2645 switch (field_type) {
2646 case Primitive::kPrimBoolean:
2647 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002648 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002649 break;
2650 }
2651
2652 case Primitive::kPrimShort:
2653 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002654 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002655 break;
2656 }
2657
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002658 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002659 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002660 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002661 break;
2662 }
2663
2664 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002665 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002666 break;
2667 }
2668
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002669 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002670 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002671 break;
2672 }
2673
2674 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002675 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002676 break;
2677 }
2678
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002679 case Primitive::kPrimVoid:
2680 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002681 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002682 }
Calin Juravle52c48962014-12-16 17:02:57 +00002683
Calin Juravle77520bc2015-01-12 18:45:46 +00002684 codegen_->MaybeRecordImplicitNullCheck(instruction);
2685
2686 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2687 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2688 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2689 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2690 }
2691
Calin Juravle52c48962014-12-16 17:02:57 +00002692 if (is_volatile) {
2693 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2694 }
2695}
2696
2697void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2698 HandleFieldSet(instruction, instruction->GetFieldInfo());
2699}
2700
2701void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2702 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002703}
2704
2705void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002706 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002707}
2708
2709void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002710 HandleFieldGet(instruction, instruction->GetFieldInfo());
2711}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002712
Calin Juravle52c48962014-12-16 17:02:57 +00002713void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2714 HandleFieldGet(instruction);
2715}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002716
Calin Juravle52c48962014-12-16 17:02:57 +00002717void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2718 HandleFieldGet(instruction, instruction->GetFieldInfo());
2719}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002720
Calin Juravle52c48962014-12-16 17:02:57 +00002721void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2722 HandleFieldSet(instruction, instruction->GetFieldInfo());
2723}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002724
Calin Juravle52c48962014-12-16 17:02:57 +00002725void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2726 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002727}
2728
2729void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002730 LocationSummary* locations =
2731 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002732 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2733 ? Location::RequiresRegister()
2734 : Location::Any();
2735 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002736 if (instruction->HasUses()) {
2737 locations->SetOut(Location::SameAsFirstInput());
2738 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002739}
2740
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002741void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002742 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2743 return;
2744 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002745 LocationSummary* locations = instruction->GetLocations();
2746 Location obj = locations->InAt(0);
2747
2748 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2749 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2750}
2751
2752void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002753 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002754 codegen_->AddSlowPath(slow_path);
2755
2756 LocationSummary* locations = instruction->GetLocations();
2757 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002758
2759 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002760 __ cmpl(obj.AsRegister<CpuRegister>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002761 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002762 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002763 } else {
2764 DCHECK(obj.IsConstant()) << obj;
2765 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2766 __ jmp(slow_path->GetEntryLabel());
2767 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002768 }
2769 __ j(kEqual, slow_path->GetEntryLabel());
2770}
2771
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002772void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2773 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2774 GenerateImplicitNullCheck(instruction);
2775 } else {
2776 GenerateExplicitNullCheck(instruction);
2777 }
2778}
2779
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002780void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002781 LocationSummary* locations =
2782 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002783 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002784 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002785 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2786 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002787}
2788
2789void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2790 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002791 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002792 Location index = locations->InAt(1);
2793
2794 switch (instruction->GetType()) {
2795 case Primitive::kPrimBoolean: {
2796 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002797 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002798 if (index.IsConstant()) {
2799 __ movzxb(out, Address(obj,
2800 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2801 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002802 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002803 }
2804 break;
2805 }
2806
2807 case Primitive::kPrimByte: {
2808 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002809 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002810 if (index.IsConstant()) {
2811 __ movsxb(out, Address(obj,
2812 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2813 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002814 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002815 }
2816 break;
2817 }
2818
2819 case Primitive::kPrimShort: {
2820 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002821 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002822 if (index.IsConstant()) {
2823 __ movsxw(out, Address(obj,
2824 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2825 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002826 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002827 }
2828 break;
2829 }
2830
2831 case Primitive::kPrimChar: {
2832 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002833 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002834 if (index.IsConstant()) {
2835 __ movzxw(out, Address(obj,
2836 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2837 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002838 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002839 }
2840 break;
2841 }
2842
2843 case Primitive::kPrimInt:
2844 case Primitive::kPrimNot: {
2845 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2846 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002847 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002848 if (index.IsConstant()) {
2849 __ movl(out, Address(obj,
2850 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2851 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002852 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002853 }
2854 break;
2855 }
2856
2857 case Primitive::kPrimLong: {
2858 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002859 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002860 if (index.IsConstant()) {
2861 __ movq(out, Address(obj,
2862 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2863 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002864 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002865 }
2866 break;
2867 }
2868
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002869 case Primitive::kPrimFloat: {
2870 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002871 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002872 if (index.IsConstant()) {
2873 __ movss(out, Address(obj,
2874 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2875 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002876 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002877 }
2878 break;
2879 }
2880
2881 case Primitive::kPrimDouble: {
2882 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002883 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002884 if (index.IsConstant()) {
2885 __ movsd(out, Address(obj,
2886 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2887 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002888 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002889 }
2890 break;
2891 }
2892
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002893 case Primitive::kPrimVoid:
2894 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002895 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002896 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002897 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002898}
2899
2900void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002901 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002902
2903 bool needs_write_barrier =
2904 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2905 bool needs_runtime_call = instruction->NeedsTypeCheck();
2906
Nicolas Geoffray39468442014-09-02 15:17:15 +01002907 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002908 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
2909 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002910 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002911 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2912 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2913 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002914 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002915 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002916 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002917 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2918 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002919 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002920 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002921 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
2922 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002923 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002924 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002925 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002926
2927 if (needs_write_barrier) {
2928 // Temporary registers for the write barrier.
2929 locations->AddTemp(Location::RequiresRegister());
2930 locations->AddTemp(Location::RequiresRegister());
2931 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002932 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002933}
2934
2935void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
2936 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002937 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002938 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002939 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01002940 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002941 bool needs_runtime_call = locations->WillCall();
2942 bool needs_write_barrier =
2943 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002944
2945 switch (value_type) {
2946 case Primitive::kPrimBoolean:
2947 case Primitive::kPrimByte: {
2948 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002949 if (index.IsConstant()) {
2950 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002951 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002952 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002953 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00002954 __ movb(Address(obj, offset),
2955 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002956 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002957 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002958 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002959 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
2960 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002961 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002962 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002963 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2964 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002965 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002966 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002967 break;
2968 }
2969
2970 case Primitive::kPrimShort:
2971 case Primitive::kPrimChar: {
2972 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002973 if (index.IsConstant()) {
2974 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002975 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002976 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002977 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002978 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00002979 __ movw(Address(obj, offset),
2980 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002981 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002982 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002983 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002984 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002985 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
2986 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002987 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002988 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00002989 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002990 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
2991 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002992 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002993 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002994 break;
2995 }
2996
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002997 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002998 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002999 if (!needs_runtime_call) {
3000 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3001 if (index.IsConstant()) {
3002 size_t offset =
3003 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3004 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003005 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003006 } else {
3007 DCHECK(value.IsConstant()) << value;
3008 __ movl(Address(obj, offset),
3009 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3010 }
3011 } else {
3012 DCHECK(index.IsRegister()) << index;
3013 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003014 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3015 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003016 } else {
3017 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003018 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003019 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3020 }
3021 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003022 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003023 if (needs_write_barrier) {
3024 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003025 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3026 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3027 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003028 }
3029 } else {
3030 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003031 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3032 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003033 DCHECK(!codegen_->IsLeafMethod());
3034 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3035 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003036 break;
3037 }
3038
3039 case Primitive::kPrimLong: {
3040 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003041 if (index.IsConstant()) {
3042 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003043 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003044 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003045 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003046 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003047 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3048 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003049 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003050 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003051 break;
3052 }
3053
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003054 case Primitive::kPrimFloat: {
3055 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3056 if (index.IsConstant()) {
3057 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3058 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003059 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003060 } else {
3061 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003062 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3063 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003064 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003065 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003066 break;
3067 }
3068
3069 case Primitive::kPrimDouble: {
3070 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3071 if (index.IsConstant()) {
3072 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3073 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003074 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003075 } else {
3076 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003077 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3078 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003079 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003080 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003081 break;
3082 }
3083
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003084 case Primitive::kPrimVoid:
3085 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003086 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003087 }
3088}
3089
3090void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003091 LocationSummary* locations =
3092 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003093 locations->SetInAt(0, Location::RequiresRegister());
3094 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003095}
3096
3097void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3098 LocationSummary* locations = instruction->GetLocations();
3099 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003100 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3101 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003102 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003103 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003104}
3105
3106void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003107 LocationSummary* locations =
3108 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003109 locations->SetInAt(0, Location::RequiresRegister());
3110 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003111 if (instruction->HasUses()) {
3112 locations->SetOut(Location::SameAsFirstInput());
3113 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003114}
3115
3116void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3117 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003118 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003119 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003120 codegen_->AddSlowPath(slow_path);
3121
Roland Levillain271ab9c2014-11-27 15:23:57 +00003122 CpuRegister index = locations->InAt(0).AsRegister<CpuRegister>();
3123 CpuRegister length = locations->InAt(1).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003124
3125 __ cmpl(index, length);
3126 __ j(kAboveEqual, slow_path->GetEntryLabel());
3127}
3128
3129void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3130 CpuRegister card,
3131 CpuRegister object,
3132 CpuRegister value) {
3133 Label is_null;
3134 __ testl(value, value);
3135 __ j(kEqual, &is_null);
3136 __ gs()->movq(card, Address::Absolute(
3137 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3138 __ movq(temp, object);
3139 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3140 __ movb(Address(temp, card, TIMES_1, 0), card);
3141 __ Bind(&is_null);
3142}
3143
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003144void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3145 temp->SetLocations(nullptr);
3146}
3147
3148void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3149 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003150 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003151}
3152
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003153void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003154 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003155 LOG(FATAL) << "Unimplemented";
3156}
3157
3158void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003159 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3160}
3161
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003162void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3163 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3164}
3165
3166void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003167 HBasicBlock* block = instruction->GetBlock();
3168 if (block->GetLoopInformation() != nullptr) {
3169 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3170 // The back edge will generate the suspend check.
3171 return;
3172 }
3173 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3174 // The goto will generate the suspend check.
3175 return;
3176 }
3177 GenerateSuspendCheck(instruction, nullptr);
3178}
3179
3180void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3181 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003182 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003183 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003184 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003185 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003186 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003187 if (successor == nullptr) {
3188 __ j(kNotEqual, slow_path->GetEntryLabel());
3189 __ Bind(slow_path->GetReturnLabel());
3190 } else {
3191 __ j(kEqual, codegen_->GetLabelOf(successor));
3192 __ jmp(slow_path->GetEntryLabel());
3193 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003194}
3195
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003196X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3197 return codegen_->GetAssembler();
3198}
3199
3200void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3201 MoveOperands* move = moves_.Get(index);
3202 Location source = move->GetSource();
3203 Location destination = move->GetDestination();
3204
3205 if (source.IsRegister()) {
3206 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003207 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003208 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003209 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003210 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003211 } else {
3212 DCHECK(destination.IsDoubleStackSlot());
3213 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003214 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003215 }
3216 } else if (source.IsStackSlot()) {
3217 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003218 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003219 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003220 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003221 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003222 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003223 } else {
3224 DCHECK(destination.IsStackSlot());
3225 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3226 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3227 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003228 } else if (source.IsDoubleStackSlot()) {
3229 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003230 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003231 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003232 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003233 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3234 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003235 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003236 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003237 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3238 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3239 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003240 } else if (source.IsConstant()) {
3241 HConstant* constant = source.GetConstant();
3242 if (constant->IsIntConstant()) {
3243 Immediate imm(constant->AsIntConstant()->GetValue());
3244 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003245 __ movl(destination.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003246 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003247 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003248 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3249 }
3250 } else if (constant->IsLongConstant()) {
3251 int64_t value = constant->AsLongConstant()->GetValue();
3252 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003253 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003254 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003255 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003256 __ movq(CpuRegister(TMP), Immediate(value));
3257 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3258 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003259 } else if (constant->IsFloatConstant()) {
3260 Immediate imm(bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()));
3261 if (destination.IsFpuRegister()) {
3262 __ movl(CpuRegister(TMP), imm);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003263 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003264 } else {
3265 DCHECK(destination.IsStackSlot()) << destination;
3266 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3267 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003268 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003269 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
3270 Immediate imm(bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()));
3271 if (destination.IsFpuRegister()) {
3272 __ movq(CpuRegister(TMP), imm);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003273 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003274 } else {
3275 DCHECK(destination.IsDoubleStackSlot()) << destination;
3276 __ movq(CpuRegister(TMP), imm);
3277 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3278 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003279 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003280 } else if (source.IsFpuRegister()) {
3281 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003282 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003283 } else if (destination.IsStackSlot()) {
3284 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003285 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003286 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003287 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003288 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003289 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003290 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003291 }
3292}
3293
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003294void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003295 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003296 __ movl(Address(CpuRegister(RSP), mem), reg);
3297 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003298}
3299
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003300void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003301 ScratchRegisterScope ensure_scratch(
3302 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3303
3304 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3305 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3306 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3307 Address(CpuRegister(RSP), mem2 + stack_offset));
3308 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3309 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3310 CpuRegister(ensure_scratch.GetRegister()));
3311}
3312
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003313void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3314 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3315 __ movq(Address(CpuRegister(RSP), mem), reg);
3316 __ movq(reg, CpuRegister(TMP));
3317}
3318
3319void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3320 ScratchRegisterScope ensure_scratch(
3321 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3322
3323 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3324 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3325 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3326 Address(CpuRegister(RSP), mem2 + stack_offset));
3327 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3328 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3329 CpuRegister(ensure_scratch.GetRegister()));
3330}
3331
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003332void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3333 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3334 __ movss(Address(CpuRegister(RSP), mem), reg);
3335 __ movd(reg, CpuRegister(TMP));
3336}
3337
3338void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3339 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3340 __ movsd(Address(CpuRegister(RSP), mem), reg);
3341 __ movd(reg, CpuRegister(TMP));
3342}
3343
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003344void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3345 MoveOperands* move = moves_.Get(index);
3346 Location source = move->GetSource();
3347 Location destination = move->GetDestination();
3348
3349 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003350 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003351 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003352 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003353 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003354 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003355 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003356 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3357 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003358 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003359 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003360 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003361 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3362 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003363 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003364 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3365 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3366 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003367 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003368 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003369 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003370 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003371 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003372 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003373 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003374 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003375 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003376 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003377 }
3378}
3379
3380
3381void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3382 __ pushq(CpuRegister(reg));
3383}
3384
3385
3386void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3387 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003388}
3389
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003390void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3391 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3392 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3393 Immediate(mirror::Class::kStatusInitialized));
3394 __ j(kLess, slow_path->GetEntryLabel());
3395 __ Bind(slow_path->GetExitLabel());
3396 // No need for memory fence, thanks to the X86_64 memory model.
3397}
3398
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003399void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003400 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3401 ? LocationSummary::kCallOnSlowPath
3402 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003403 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003404 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003405 locations->SetOut(Location::RequiresRegister());
3406}
3407
3408void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003409 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003410 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003411 DCHECK(!cls->CanCallRuntime());
3412 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003413 codegen_->LoadCurrentMethod(out);
3414 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3415 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003416 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003417 codegen_->LoadCurrentMethod(out);
3418 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3419 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003420 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3421 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3422 codegen_->AddSlowPath(slow_path);
3423 __ testl(out, out);
3424 __ j(kEqual, slow_path->GetEntryLabel());
3425 if (cls->MustGenerateClinitCheck()) {
3426 GenerateClassInitializationCheck(slow_path, out);
3427 } else {
3428 __ Bind(slow_path->GetExitLabel());
3429 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003430 }
3431}
3432
3433void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3434 LocationSummary* locations =
3435 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3436 locations->SetInAt(0, Location::RequiresRegister());
3437 if (check->HasUses()) {
3438 locations->SetOut(Location::SameAsFirstInput());
3439 }
3440}
3441
3442void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003443 // We assume the class to not be null.
3444 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3445 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003446 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003447 GenerateClassInitializationCheck(slow_path,
3448 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003449}
3450
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003451void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3452 LocationSummary* locations =
3453 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3454 locations->SetOut(Location::RequiresRegister());
3455}
3456
3457void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3458 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3459 codegen_->AddSlowPath(slow_path);
3460
Roland Levillain271ab9c2014-11-27 15:23:57 +00003461 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003462 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003463 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3464 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003465 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3466 __ testl(out, out);
3467 __ j(kEqual, slow_path->GetEntryLabel());
3468 __ Bind(slow_path->GetExitLabel());
3469}
3470
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003471void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3472 LocationSummary* locations =
3473 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3474 locations->SetOut(Location::RequiresRegister());
3475}
3476
3477void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3478 Address address = Address::Absolute(
3479 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003480 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003481 __ gs()->movl(address, Immediate(0));
3482}
3483
3484void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
3485 LocationSummary* locations =
3486 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3487 InvokeRuntimeCallingConvention calling_convention;
3488 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3489}
3490
3491void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
3492 __ gs()->call(
3493 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3494 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3495}
3496
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003497void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003498 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3499 ? LocationSummary::kNoCall
3500 : LocationSummary::kCallOnSlowPath;
3501 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3502 locations->SetInAt(0, Location::RequiresRegister());
3503 locations->SetInAt(1, Location::Any());
3504 locations->SetOut(Location::RequiresRegister());
3505}
3506
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003507void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003508 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003509 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003510 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003511 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003512 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3513 Label done, zero;
3514 SlowPathCodeX86_64* slow_path = nullptr;
3515
3516 // Return 0 if `obj` is null.
3517 // TODO: avoid this check if we know obj is not null.
3518 __ testl(obj, obj);
3519 __ j(kEqual, &zero);
3520 // Compare the class of `obj` with `cls`.
3521 __ movl(out, Address(obj, class_offset));
3522 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003523 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003524 } else {
3525 DCHECK(cls.IsStackSlot()) << cls;
3526 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3527 }
3528 if (instruction->IsClassFinal()) {
3529 // Classes must be equal for the instanceof to succeed.
3530 __ j(kNotEqual, &zero);
3531 __ movl(out, Immediate(1));
3532 __ jmp(&done);
3533 } else {
3534 // If the classes are not equal, we go into a slow path.
3535 DCHECK(locations->OnlyCallsOnSlowPath());
3536 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003537 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003538 codegen_->AddSlowPath(slow_path);
3539 __ j(kNotEqual, slow_path->GetEntryLabel());
3540 __ movl(out, Immediate(1));
3541 __ jmp(&done);
3542 }
3543 __ Bind(&zero);
3544 __ movl(out, Immediate(0));
3545 if (slow_path != nullptr) {
3546 __ Bind(slow_path->GetExitLabel());
3547 }
3548 __ Bind(&done);
3549}
3550
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003551void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3552 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3553 instruction, LocationSummary::kCallOnSlowPath);
3554 locations->SetInAt(0, Location::RequiresRegister());
3555 locations->SetInAt(1, Location::Any());
3556 locations->AddTemp(Location::RequiresRegister());
3557}
3558
3559void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3560 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003561 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003562 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003563 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003564 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3565 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3566 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3567 codegen_->AddSlowPath(slow_path);
3568
3569 // TODO: avoid this check if we know obj is not null.
3570 __ testl(obj, obj);
3571 __ j(kEqual, slow_path->GetExitLabel());
3572 // Compare the class of `obj` with `cls`.
3573 __ movl(temp, Address(obj, class_offset));
3574 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003575 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003576 } else {
3577 DCHECK(cls.IsStackSlot()) << cls;
3578 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3579 }
3580 // Classes must be equal for the checkcast to succeed.
3581 __ j(kNotEqual, slow_path->GetEntryLabel());
3582 __ Bind(slow_path->GetExitLabel());
3583}
3584
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003585void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3586 LocationSummary* locations =
3587 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3588 InvokeRuntimeCallingConvention calling_convention;
3589 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3590}
3591
3592void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3593 __ gs()->call(Address::Absolute(instruction->IsEnter()
3594 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3595 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3596 true));
3597 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3598}
3599
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003600void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3601void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3602void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3603
3604void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3605 LocationSummary* locations =
3606 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3607 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3608 || instruction->GetResultType() == Primitive::kPrimLong);
3609 locations->SetInAt(0, Location::RequiresRegister());
3610 if (instruction->GetType() == Primitive::kPrimInt) {
3611 locations->SetInAt(1, Location::Any());
3612 } else {
3613 // Request a register to avoid loading a 64bits constant.
3614 locations->SetInAt(1, Location::RequiresRegister());
3615 }
3616 locations->SetOut(Location::SameAsFirstInput());
3617}
3618
3619void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3620 HandleBitwiseOperation(instruction);
3621}
3622
3623void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3624 HandleBitwiseOperation(instruction);
3625}
3626
3627void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3628 HandleBitwiseOperation(instruction);
3629}
3630
3631void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3632 LocationSummary* locations = instruction->GetLocations();
3633 Location first = locations->InAt(0);
3634 Location second = locations->InAt(1);
3635 DCHECK(first.Equals(locations->Out()));
3636
3637 if (instruction->GetResultType() == Primitive::kPrimInt) {
3638 if (second.IsRegister()) {
3639 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003640 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003641 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003643 } else {
3644 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003645 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003646 }
3647 } else if (second.IsConstant()) {
3648 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3649 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003650 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003651 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003652 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003653 } else {
3654 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003655 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003656 }
3657 } else {
3658 Address address(CpuRegister(RSP), second.GetStackIndex());
3659 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003660 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003661 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003662 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003663 } else {
3664 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003665 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003666 }
3667 }
3668 } else {
3669 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3670 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003671 __ andq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003672 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003673 __ orq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003674 } else {
3675 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003676 __ xorq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003677 }
3678 }
3679}
3680
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003681} // namespace x86_64
3682} // namespace art