blob: b12f57ed7637632266afb817586d7b69c889fbd1 [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 Geoffray4597b5b2015-01-23 21:51:55 +000048static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000049static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050
Mark Mendell24f2dfa2015-01-14 19:51:45 -050051static constexpr int kC2ConditionMask = 0x400;
52
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010054 public:
55 InvokeRuntimeCallingConvention()
56 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010057 kRuntimeParameterCoreRegistersLength,
58 kRuntimeParameterFpuRegisters,
59 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010060
61 private:
62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63};
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010064
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
66
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010067class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070
Alexandre Rames2ed20af2015-03-06 13:55:35 +000071 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010073 __ gs()->call(
74 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000075 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 }
77
78 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
81};
82
Calin Juravled0d48522014-11-04 16:40:20 +000083class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
84 public:
85 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
86
Alexandre Rames2ed20af2015-03-06 13:55:35 +000087 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000088 __ Bind(GetEntryLabel());
89 __ gs()->call(
90 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000091 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Calin Juravled0d48522014-11-04 16:40:20 +000092 }
93
94 private:
95 HDivZeroCheck* const instruction_;
96 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
97};
98
Calin Juravlebacfec32014-11-14 15:54:36 +000099class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +0000100 public:
Calin Juravlebacfec32014-11-14 15:54:36 +0000101 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
102 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000103
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000104 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000105 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000106 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000107 if (is_div_) {
108 __ negl(cpu_reg_);
109 } else {
110 __ movl(cpu_reg_, Immediate(0));
111 }
112
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000113 } else {
114 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000115 if (is_div_) {
116 __ negq(cpu_reg_);
117 } else {
118 __ movq(cpu_reg_, Immediate(0));
119 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000120 }
Calin Juravled0d48522014-11-04 16:40:20 +0000121 __ jmp(GetExitLabel());
122 }
123
124 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000127 const bool is_div_;
128 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000129};
130
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100131class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
134 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000136 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100137 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000139 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000141 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
142 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100143 if (successor_ == nullptr) {
144 __ jmp(GetReturnLabel());
145 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100146 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100147 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 }
149
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100150 Label* GetReturnLabel() {
151 DCHECK(successor_ == nullptr);
152 return &return_label_;
153 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154
155 private:
156 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100157 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000158 Label return_label_;
159
160 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
161};
162
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100163class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100164 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100165 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
166 Location index_location,
167 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100168 : instruction_(instruction),
169 index_location_(index_location),
170 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000172 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000174 // We're moving two locations to locations that could overlap, so we need a parallel
175 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100176 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000177 codegen->EmitParallelMoves(
178 index_location_,
179 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
180 length_location_,
181 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100182 __ gs()->call(Address::Absolute(
183 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000184 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 }
186
187 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100188 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 const Location index_location_;
190 const Location length_location_;
191
192 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
193};
194
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000195class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 LoadClassSlowPathX86_64(HLoadClass* cls,
198 HInstruction* at,
199 uint32_t dex_pc,
200 bool do_clinit)
201 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
202 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
203 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000205 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000206 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
208 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000210 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100214 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 __ gs()->call(Address::Absolute((do_clinit_
216 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
217 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000218 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100219
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000220 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000221 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000222 if (out.IsValid()) {
223 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
224 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225 }
226
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000227 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228 __ jmp(GetExitLabel());
229 }
230
231 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000232 // The class this slow path will load.
233 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100234
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000235 // The instruction where this slow path is happening.
236 // (Might be the load class or an initialization check).
237 HInstruction* const at_;
238
239 // The dex PC of `at_`.
240 const uint32_t dex_pc_;
241
242 // Whether to initialize the class.
243 const bool do_clinit_;
244
245 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100246};
247
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000248class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
249 public:
250 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
251
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000252 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000253 LocationSummary* locations = instruction_->GetLocations();
254 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
255
256 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
257 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000258 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000259
260 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800261 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
262 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000263 Immediate(instruction_->GetStringIndex()));
264 __ gs()->call(Address::Absolute(
265 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000266 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000268 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000269 __ jmp(GetExitLabel());
270 }
271
272 private:
273 HLoadString* const instruction_;
274
275 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
276};
277
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
279 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000280 TypeCheckSlowPathX86_64(HInstruction* instruction,
281 Location class_to_check,
282 Location object_class,
283 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000285 class_to_check_(class_to_check),
286 object_class_(object_class),
287 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000288
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000289 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000290 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000291 DCHECK(instruction_->IsCheckCast()
292 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000293
294 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
295 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000296 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000297
298 // We're moving two locations to locations that could overlap, so we need a parallel
299 // move resolver.
300 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000301 codegen->EmitParallelMoves(
302 class_to_check_,
303 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
304 object_class_,
305 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000306
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000307 if (instruction_->IsInstanceOf()) {
308 __ gs()->call(
309 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
310 } else {
311 DCHECK(instruction_->IsCheckCast());
312 __ gs()->call(
313 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
314 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000315 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000316
317 if (instruction_->IsInstanceOf()) {
318 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
319 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000320
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000321 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000322 __ jmp(GetExitLabel());
323 }
324
325 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000326 HInstruction* const instruction_;
327 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000328 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000329 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000330
331 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
332};
333
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100334#undef __
335#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
336
Dave Allison20dfc792014-06-16 20:44:29 -0700337inline Condition X86_64Condition(IfCondition cond) {
338 switch (cond) {
339 case kCondEQ: return kEqual;
340 case kCondNE: return kNotEqual;
341 case kCondLT: return kLess;
342 case kCondLE: return kLessEqual;
343 case kCondGT: return kGreater;
344 case kCondGE: return kGreaterEqual;
345 default:
346 LOG(FATAL) << "Unknown if condition";
347 }
348 return kEqual;
349}
350
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800351void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
352 CpuRegister temp) {
353 // All registers are assumed to be correctly set up.
354
355 // TODO: Implement all kinds of calls:
356 // 1) boot -> boot
357 // 2) app -> boot
358 // 3) app -> app
359 //
360 // Currently we implement the app -> app logic, which looks up in the resolve cache.
361
362 // temp = method;
363 LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000364 if (!invoke->IsRecursive()) {
365 // temp = temp->dex_cache_resolved_methods_;
366 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
367 // temp = temp[index_in_cache]
368 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
369 // (temp + offset_of_quick_compiled_code)()
370 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
371 kX86_64WordSize).SizeValue()));
372 } else {
373 __ call(&frame_entry_label_);
374 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800375
376 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800377}
378
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100379void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
380 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
381}
382
383void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
384 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
385}
386
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100387size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
388 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
389 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100390}
391
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100392size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
393 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
394 return kX86_64WordSize;
395}
396
397size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
398 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
399 return kX86_64WordSize;
400}
401
402size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
403 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
404 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100405}
406
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000407static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000408// Use a fake return address register to mimic Quick.
409static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000410CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000411 : CodeGenerator(graph,
412 kNumberOfCpuRegisters,
413 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000414 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000415 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
416 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000417 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000418 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
419 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000420 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100421 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100422 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000423 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000424 move_resolver_(graph->GetArena(), this) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000425 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
426}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100427
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100428InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
429 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100430 : HGraphVisitor(graph),
431 assembler_(codegen->GetAssembler()),
432 codegen_(codegen) {}
433
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100434Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100435 switch (type) {
436 case Primitive::kPrimLong:
437 case Primitive::kPrimByte:
438 case Primitive::kPrimBoolean:
439 case Primitive::kPrimChar:
440 case Primitive::kPrimShort:
441 case Primitive::kPrimInt:
442 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100443 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100444 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100445 }
446
447 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100448 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100449 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100450 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100451 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100452
453 case Primitive::kPrimVoid:
454 LOG(FATAL) << "Unreachable type " << type;
455 }
456
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100457 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100458}
459
Nicolas Geoffray98893962015-01-21 12:32:32 +0000460void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100461 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100462 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100463
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000464 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100465 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000466
Nicolas Geoffray98893962015-01-21 12:32:32 +0000467 if (is_baseline) {
468 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
469 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
470 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000471 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
472 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
473 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000474 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100475}
476
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100477void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000478 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100479 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700480 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000481 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100482
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000483 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100484 __ testq(CpuRegister(RAX), Address(
485 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100486 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100487 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000488
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000489 if (HasEmptyFrame()) {
490 return;
491 }
492
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];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000495 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000496 __ 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 Geoffrayc0572a42015-02-06 14:35:25 +0000515 if (HasEmptyFrame()) {
516 return;
517 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000518 uint32_t xmm_spill_location = GetFpuSpillStart();
519 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
520 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
521 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
522 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
523 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
524 }
525 }
526
527 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000528
529 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000530 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000531 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000532 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000533 }
534 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100535}
536
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100537void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
538 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100539}
540
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100541void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000542 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100543 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
544}
545
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100546Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
547 switch (load->GetType()) {
548 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100549 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100550 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
551 break;
552
553 case Primitive::kPrimInt:
554 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100555 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100556 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100557
558 case Primitive::kPrimBoolean:
559 case Primitive::kPrimByte:
560 case Primitive::kPrimChar:
561 case Primitive::kPrimShort:
562 case Primitive::kPrimVoid:
563 LOG(FATAL) << "Unexpected type " << load->GetType();
564 }
565
566 LOG(FATAL) << "Unreachable";
567 return Location();
568}
569
570void CodeGeneratorX86_64::Move(Location destination, Location source) {
571 if (source.Equals(destination)) {
572 return;
573 }
574 if (destination.IsRegister()) {
575 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000576 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100577 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000578 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100579 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000580 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100581 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100582 } else {
583 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000584 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100585 Address(CpuRegister(RSP), source.GetStackIndex()));
586 }
587 } else if (destination.IsFpuRegister()) {
588 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000589 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100590 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000591 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100592 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000593 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 Address(CpuRegister(RSP), source.GetStackIndex()));
595 } else {
596 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000597 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100598 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100599 }
600 } else if (destination.IsStackSlot()) {
601 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100602 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000603 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100604 } else if (source.IsFpuRegister()) {
605 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000606 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500607 } else if (source.IsConstant()) {
608 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000609 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500610 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100611 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500612 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000613 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
614 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615 }
616 } else {
617 DCHECK(destination.IsDoubleStackSlot());
618 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100619 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000620 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100621 } else if (source.IsFpuRegister()) {
622 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000623 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500624 } else if (source.IsConstant()) {
625 HConstant* constant = source.GetConstant();
626 int64_t value = constant->AsLongConstant()->GetValue();
627 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000628 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500629 } else {
630 DCHECK(constant->IsLongConstant());
631 value = constant->AsLongConstant()->GetValue();
632 }
633 __ movq(CpuRegister(TMP), Immediate(value));
634 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100635 } else {
636 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000637 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
638 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100639 }
640 }
641}
642
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100643void CodeGeneratorX86_64::Move(HInstruction* instruction,
644 Location location,
645 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000646 LocationSummary* locations = instruction->GetLocations();
647 if (locations != nullptr && locations->Out().Equals(location)) {
648 return;
649 }
650
651 if (locations != nullptr && locations->Out().IsConstant()) {
652 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000653 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
654 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000655 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000656 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000657 } else if (location.IsStackSlot()) {
658 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
659 } else {
660 DCHECK(location.IsConstant());
661 DCHECK_EQ(location.GetConstant(), const_to_move);
662 }
663 } else if (const_to_move->IsLongConstant()) {
664 int64_t value = const_to_move->AsLongConstant()->GetValue();
665 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000666 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000667 } else if (location.IsDoubleStackSlot()) {
668 __ movq(CpuRegister(TMP), Immediate(value));
669 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
670 } else {
671 DCHECK(location.IsConstant());
672 DCHECK_EQ(location.GetConstant(), const_to_move);
673 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100674 }
Roland Levillain476df552014-10-09 17:51:36 +0100675 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100676 switch (instruction->GetType()) {
677 case Primitive::kPrimBoolean:
678 case Primitive::kPrimByte:
679 case Primitive::kPrimChar:
680 case Primitive::kPrimShort:
681 case Primitive::kPrimInt:
682 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100683 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100684 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
685 break;
686
687 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100688 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000689 Move(location,
690 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100691 break;
692
693 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100694 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100695 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000696 } else if (instruction->IsTemporary()) {
697 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
698 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100699 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100700 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100701 switch (instruction->GetType()) {
702 case Primitive::kPrimBoolean:
703 case Primitive::kPrimByte:
704 case Primitive::kPrimChar:
705 case Primitive::kPrimShort:
706 case Primitive::kPrimInt:
707 case Primitive::kPrimNot:
708 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100709 case Primitive::kPrimFloat:
710 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000711 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100712 break;
713
714 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100715 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100716 }
717 }
718}
719
720void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
721 got->SetLocations(nullptr);
722}
723
724void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
725 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100726 DCHECK(!successor->IsExitBlock());
727
728 HBasicBlock* block = got->GetBlock();
729 HInstruction* previous = got->GetPrevious();
730
731 HLoopInformation* info = block->GetLoopInformation();
732 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
733 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
734 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
735 return;
736 }
737
738 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
739 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
740 }
741 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100742 __ jmp(codegen_->GetLabelOf(successor));
743 }
744}
745
746void LocationsBuilderX86_64::VisitExit(HExit* exit) {
747 exit->SetLocations(nullptr);
748}
749
750void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700751 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100752}
753
Andreas Gampe0ba62732015-03-24 02:39:46 +0000754void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
755 LocationSummary* locations =
756 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
757 HInstruction* cond = if_instr->InputAt(0);
758 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
759 locations->SetInAt(0, Location::Any());
760 }
761}
762
763void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
764 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100765 if (cond->IsIntConstant()) {
766 // Constant condition, statically compared against 1.
767 int32_t cond_value = cond->AsIntConstant()->GetValue();
768 if (cond_value == 1) {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000769 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
770 if_instr->IfTrueSuccessor())) {
771 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100772 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100773 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100774 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100775 DCHECK_EQ(cond_value, 0);
776 }
777 } else {
778 bool materialized =
779 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
780 // Moves do not affect the eflags register, so if the condition is
781 // evaluated just before the if, we don't need to evaluate it
782 // again.
783 bool eflags_set = cond->IsCondition()
Andreas Gampe0ba62732015-03-24 02:39:46 +0000784 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100785 if (materialized) {
786 if (!eflags_set) {
787 // Materialized condition, compare against 0.
Andreas Gampe0ba62732015-03-24 02:39:46 +0000788 Location lhs = if_instr->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100789 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000790 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100791 } else {
792 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
793 Immediate(0));
794 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000795 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100796 } else {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000797 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
798 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100799 }
800 } else {
801 Location lhs = cond->GetLocations()->InAt(0);
802 Location rhs = cond->GetLocations()->InAt(1);
803 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000804 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100805 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000806 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000807 if (constant == 0) {
808 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
809 } else {
810 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
811 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100812 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000813 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100814 Address(CpuRegister(RSP), rhs.GetStackIndex()));
815 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000816 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
817 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700818 }
Dave Allison20dfc792014-06-16 20:44:29 -0700819 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000820 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
821 if_instr->IfFalseSuccessor())) {
822 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100823 }
824}
825
826void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
827 local->SetLocations(nullptr);
828}
829
830void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
831 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
832}
833
834void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
835 local->SetLocations(nullptr);
836}
837
838void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
839 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700840 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100841}
842
843void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100844 LocationSummary* locations =
845 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100846 switch (store->InputAt(1)->GetType()) {
847 case Primitive::kPrimBoolean:
848 case Primitive::kPrimByte:
849 case Primitive::kPrimChar:
850 case Primitive::kPrimShort:
851 case Primitive::kPrimInt:
852 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100853 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100854 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
855 break;
856
857 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100858 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100859 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
860 break;
861
862 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100863 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100864 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865}
866
867void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700868 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100869}
870
Dave Allison20dfc792014-06-16 20:44:29 -0700871void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100872 LocationSummary* locations =
873 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100874 locations->SetInAt(0, Location::RequiresRegister());
875 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100876 if (comp->NeedsMaterialization()) {
877 locations->SetOut(Location::RequiresRegister());
878 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100879}
880
Dave Allison20dfc792014-06-16 20:44:29 -0700881void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
882 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100883 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000884 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100885 // Clear register: setcc only sets the low byte.
886 __ xorq(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000887 Location lhs = locations->InAt(0);
888 Location rhs = locations->InAt(1);
889 if (rhs.IsRegister()) {
890 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
891 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800892 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000893 if (constant == 0) {
894 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
895 } else {
896 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
897 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100898 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000899 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100900 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100901 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700902 }
903}
904
905void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
906 VisitCondition(comp);
907}
908
909void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
910 VisitCondition(comp);
911}
912
913void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
914 VisitCondition(comp);
915}
916
917void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
918 VisitCondition(comp);
919}
920
921void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
922 VisitCondition(comp);
923}
924
925void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
926 VisitCondition(comp);
927}
928
929void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
930 VisitCondition(comp);
931}
932
933void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
934 VisitCondition(comp);
935}
936
937void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
938 VisitCondition(comp);
939}
940
941void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
942 VisitCondition(comp);
943}
944
945void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
946 VisitCondition(comp);
947}
948
949void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
950 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100951}
952
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100953void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100954 LocationSummary* locations =
955 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000956 switch (compare->InputAt(0)->GetType()) {
957 case Primitive::kPrimLong: {
958 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400959 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +0000960 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
961 break;
962 }
963 case Primitive::kPrimFloat:
964 case Primitive::kPrimDouble: {
965 locations->SetInAt(0, Location::RequiresFpuRegister());
966 locations->SetInAt(1, Location::RequiresFpuRegister());
967 locations->SetOut(Location::RequiresRegister());
968 break;
969 }
970 default:
971 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
972 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100973}
974
975void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100976 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000977 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +0000978 Location left = locations->InAt(0);
979 Location right = locations->InAt(1);
980
981 Label less, greater, done;
982 Primitive::Type type = compare->InputAt(0)->GetType();
983 switch (type) {
984 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400985 CpuRegister left_reg = left.AsRegister<CpuRegister>();
986 if (right.IsConstant()) {
987 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
988 DCHECK(IsInt<32>(value));
989 if (value == 0) {
990 __ testq(left_reg, left_reg);
991 } else {
992 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
993 }
994 } else {
995 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
996 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100997 break;
Calin Juravleddb7df22014-11-25 20:56:51 +0000998 }
999 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001000 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001001 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1002 break;
1003 }
1004 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001005 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001006 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1007 break;
1008 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001009 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001010 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001011 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001012 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001013 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001014 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001015
Calin Juravle91debbc2014-11-26 19:01:09 +00001016 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001017 __ movl(out, Immediate(1));
1018 __ jmp(&done);
1019
1020 __ Bind(&less);
1021 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001022
1023 __ Bind(&done);
1024}
1025
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001026void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001027 LocationSummary* locations =
1028 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001029 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001030}
1031
1032void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001033 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001034 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001035}
1036
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001037void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1038 LocationSummary* locations =
1039 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1040 locations->SetOut(Location::ConstantLocation(constant));
1041}
1042
1043void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1044 // Will be generated at use site.
1045 UNUSED(constant);
1046}
1047
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001048void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001049 LocationSummary* locations =
1050 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001051 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001052}
1053
1054void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001055 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001056 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001057}
1058
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001059void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1060 LocationSummary* locations =
1061 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1062 locations->SetOut(Location::ConstantLocation(constant));
1063}
1064
1065void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1066 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001067 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001068}
1069
1070void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1071 LocationSummary* locations =
1072 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1073 locations->SetOut(Location::ConstantLocation(constant));
1074}
1075
1076void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1077 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001078 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001079}
1080
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001081void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1082 ret->SetLocations(nullptr);
1083}
1084
1085void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001086 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001087 codegen_->GenerateFrameExit();
1088 __ ret();
1089}
1090
1091void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001092 LocationSummary* locations =
1093 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001094 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:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001102 locations->SetInAt(0, Location::RegisterLocation(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:
1107 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001108 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001109 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 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001114}
1115
1116void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1117 if (kIsDebugBuild) {
1118 switch (ret->InputAt(0)->GetType()) {
1119 case Primitive::kPrimBoolean:
1120 case Primitive::kPrimByte:
1121 case Primitive::kPrimChar:
1122 case Primitive::kPrimShort:
1123 case Primitive::kPrimInt:
1124 case Primitive::kPrimNot:
1125 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001126 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001127 break;
1128
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001129 case Primitive::kPrimFloat:
1130 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001131 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001132 XMM0);
1133 break;
1134
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001135 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001136 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001137 }
1138 }
1139 codegen_->GenerateFrameExit();
1140 __ ret();
1141}
1142
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001143Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1144 switch (type) {
1145 case Primitive::kPrimBoolean:
1146 case Primitive::kPrimByte:
1147 case Primitive::kPrimChar:
1148 case Primitive::kPrimShort:
1149 case Primitive::kPrimInt:
1150 case Primitive::kPrimNot: {
1151 uint32_t index = gp_index_++;
1152 stack_index_++;
1153 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001154 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001155 } else {
1156 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1157 }
1158 }
1159
1160 case Primitive::kPrimLong: {
1161 uint32_t index = gp_index_;
1162 stack_index_ += 2;
1163 if (index < calling_convention.GetNumberOfRegisters()) {
1164 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001165 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001166 } else {
1167 gp_index_ += 2;
1168 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1169 }
1170 }
1171
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001172 case Primitive::kPrimFloat: {
1173 uint32_t index = fp_index_++;
1174 stack_index_++;
1175 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001176 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001177 } else {
1178 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1179 }
1180 }
1181
1182 case Primitive::kPrimDouble: {
1183 uint32_t index = fp_index_++;
1184 stack_index_ += 2;
1185 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001186 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001187 } else {
1188 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1189 }
1190 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001191
1192 case Primitive::kPrimVoid:
1193 LOG(FATAL) << "Unexpected parameter type " << type;
1194 break;
1195 }
1196 return Location();
1197}
1198
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001199void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001200 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1201 if (intrinsic.TryDispatch(invoke)) {
1202 return;
1203 }
1204
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001205 HandleInvoke(invoke);
1206}
1207
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001208static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1209 if (invoke->GetLocations()->Intrinsified()) {
1210 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1211 intrinsic.Dispatch(invoke);
1212 return true;
1213 }
1214 return false;
1215}
1216
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001217void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001218 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1219 return;
1220 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001221
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001222 codegen_->GenerateStaticOrDirectCall(
1223 invoke,
1224 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001225 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001226}
1227
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001228void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001229 LocationSummary* locations =
1230 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001231 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001232
1233 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001234 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001235 HInstruction* input = invoke->InputAt(i);
1236 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1237 }
1238
1239 switch (invoke->GetType()) {
1240 case Primitive::kPrimBoolean:
1241 case Primitive::kPrimByte:
1242 case Primitive::kPrimChar:
1243 case Primitive::kPrimShort:
1244 case Primitive::kPrimInt:
1245 case Primitive::kPrimNot:
1246 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001247 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001248 break;
1249
1250 case Primitive::kPrimVoid:
1251 break;
1252
1253 case Primitive::kPrimDouble:
1254 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001255 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001256 break;
1257 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001258}
1259
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001260void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001261 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1262 if (intrinsic.TryDispatch(invoke)) {
1263 return;
1264 }
1265
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001266 HandleInvoke(invoke);
1267}
1268
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001269void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001270 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1271 return;
1272 }
1273
Roland Levillain271ab9c2014-11-27 15:23:57 +00001274 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001275 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1276 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1277 LocationSummary* locations = invoke->GetLocations();
1278 Location receiver = locations->InAt(0);
1279 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1280 // temp = object->GetClass();
1281 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001282 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1283 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001284 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001285 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001286 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001287 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001288 // temp = temp->GetMethodAt(method_offset);
1289 __ movl(temp, Address(temp, method_offset));
1290 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001291 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001292 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001293
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001294 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001295 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001296}
1297
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001298void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1299 HandleInvoke(invoke);
1300 // Add the hidden argument.
1301 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1302}
1303
1304void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1305 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001306 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001307 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1308 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1309 LocationSummary* locations = invoke->GetLocations();
1310 Location receiver = locations->InAt(0);
1311 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1312
1313 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001314 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001315 Immediate(invoke->GetDexMethodIndex()));
1316
1317 // temp = object->GetClass();
1318 if (receiver.IsStackSlot()) {
1319 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1320 __ movl(temp, Address(temp, class_offset));
1321 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001322 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001323 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001324 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001325 // temp = temp->GetImtEntryAt(method_offset);
1326 __ movl(temp, Address(temp, method_offset));
1327 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001328 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001329 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001330
1331 DCHECK(!codegen_->IsLeafMethod());
1332 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1333}
1334
Roland Levillain88cb1752014-10-20 16:36:47 +01001335void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1336 LocationSummary* locations =
1337 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1338 switch (neg->GetResultType()) {
1339 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001340 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001341 locations->SetInAt(0, Location::RequiresRegister());
1342 locations->SetOut(Location::SameAsFirstInput());
1343 break;
1344
Roland Levillain88cb1752014-10-20 16:36:47 +01001345 case Primitive::kPrimFloat:
1346 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001347 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001348 locations->SetOut(Location::SameAsFirstInput());
1349 locations->AddTemp(Location::RequiresRegister());
1350 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001351 break;
1352
1353 default:
1354 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1355 }
1356}
1357
1358void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1359 LocationSummary* locations = neg->GetLocations();
1360 Location out = locations->Out();
1361 Location in = locations->InAt(0);
1362 switch (neg->GetResultType()) {
1363 case Primitive::kPrimInt:
1364 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001365 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001366 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001367 break;
1368
1369 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001370 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001371 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001372 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001373 break;
1374
Roland Levillain5368c212014-11-27 15:03:41 +00001375 case Primitive::kPrimFloat: {
1376 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001377 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1378 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001379 // Implement float negation with an exclusive or with value
1380 // 0x80000000 (mask for bit 31, representing the sign of a
1381 // single-precision floating-point number).
1382 __ movq(constant, Immediate(INT64_C(0x80000000)));
1383 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001384 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001385 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001386 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001387
Roland Levillain5368c212014-11-27 15:03:41 +00001388 case Primitive::kPrimDouble: {
1389 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001390 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1391 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001392 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001393 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001394 // a double-precision floating-point number).
1395 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1396 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001397 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001398 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001399 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001400
1401 default:
1402 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1403 }
1404}
1405
Roland Levillaindff1f282014-11-05 14:15:05 +00001406void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1407 LocationSummary* locations =
1408 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1409 Primitive::Type result_type = conversion->GetResultType();
1410 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001411 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001412 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001413 case Primitive::kPrimByte:
1414 switch (input_type) {
1415 case Primitive::kPrimShort:
1416 case Primitive::kPrimInt:
1417 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001418 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001419 locations->SetInAt(0, Location::Any());
1420 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1421 break;
1422
1423 default:
1424 LOG(FATAL) << "Unexpected type conversion from " << input_type
1425 << " to " << result_type;
1426 }
1427 break;
1428
Roland Levillain01a8d712014-11-14 16:27:39 +00001429 case Primitive::kPrimShort:
1430 switch (input_type) {
1431 case Primitive::kPrimByte:
1432 case Primitive::kPrimInt:
1433 case Primitive::kPrimChar:
1434 // Processing a Dex `int-to-short' instruction.
1435 locations->SetInAt(0, Location::Any());
1436 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1437 break;
1438
1439 default:
1440 LOG(FATAL) << "Unexpected type conversion from " << input_type
1441 << " to " << result_type;
1442 }
1443 break;
1444
Roland Levillain946e1432014-11-11 17:35:19 +00001445 case Primitive::kPrimInt:
1446 switch (input_type) {
1447 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001448 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001449 locations->SetInAt(0, Location::Any());
1450 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1451 break;
1452
1453 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001454 // Processing a Dex `float-to-int' instruction.
1455 locations->SetInAt(0, Location::RequiresFpuRegister());
1456 locations->SetOut(Location::RequiresRegister());
1457 locations->AddTemp(Location::RequiresFpuRegister());
1458 break;
1459
Roland Levillain946e1432014-11-11 17:35:19 +00001460 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001461 // Processing a Dex `double-to-int' instruction.
1462 locations->SetInAt(0, Location::RequiresFpuRegister());
1463 locations->SetOut(Location::RequiresRegister());
1464 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001465 break;
1466
1467 default:
1468 LOG(FATAL) << "Unexpected type conversion from " << input_type
1469 << " to " << result_type;
1470 }
1471 break;
1472
Roland Levillaindff1f282014-11-05 14:15:05 +00001473 case Primitive::kPrimLong:
1474 switch (input_type) {
1475 case Primitive::kPrimByte:
1476 case Primitive::kPrimShort:
1477 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001478 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001479 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001480 // TODO: We would benefit from a (to-be-implemented)
1481 // Location::RegisterOrStackSlot requirement for this input.
1482 locations->SetInAt(0, Location::RequiresRegister());
1483 locations->SetOut(Location::RequiresRegister());
1484 break;
1485
1486 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001487 // Processing a Dex `float-to-long' instruction.
1488 locations->SetInAt(0, Location::RequiresFpuRegister());
1489 locations->SetOut(Location::RequiresRegister());
1490 locations->AddTemp(Location::RequiresFpuRegister());
1491 break;
1492
Roland Levillaindff1f282014-11-05 14:15:05 +00001493 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001494 // Processing a Dex `double-to-long' instruction.
1495 locations->SetInAt(0, Location::RequiresFpuRegister());
1496 locations->SetOut(Location::RequiresRegister());
1497 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001498 break;
1499
1500 default:
1501 LOG(FATAL) << "Unexpected type conversion from " << input_type
1502 << " to " << result_type;
1503 }
1504 break;
1505
Roland Levillain981e4542014-11-14 11:47:14 +00001506 case Primitive::kPrimChar:
1507 switch (input_type) {
1508 case Primitive::kPrimByte:
1509 case Primitive::kPrimShort:
1510 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001511 // Processing a Dex `int-to-char' instruction.
1512 locations->SetInAt(0, Location::Any());
1513 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1514 break;
1515
1516 default:
1517 LOG(FATAL) << "Unexpected type conversion from " << input_type
1518 << " to " << result_type;
1519 }
1520 break;
1521
Roland Levillaindff1f282014-11-05 14:15:05 +00001522 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001523 switch (input_type) {
1524 case Primitive::kPrimByte:
1525 case Primitive::kPrimShort:
1526 case Primitive::kPrimInt:
1527 case Primitive::kPrimChar:
1528 // Processing a Dex `int-to-float' instruction.
1529 locations->SetInAt(0, Location::RequiresRegister());
1530 locations->SetOut(Location::RequiresFpuRegister());
1531 break;
1532
1533 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001534 // Processing a Dex `long-to-float' instruction.
1535 locations->SetInAt(0, Location::RequiresRegister());
1536 locations->SetOut(Location::RequiresFpuRegister());
1537 break;
1538
Roland Levillaincff13742014-11-17 14:32:17 +00001539 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001540 // Processing a Dex `double-to-float' instruction.
1541 locations->SetInAt(0, Location::RequiresFpuRegister());
1542 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001543 break;
1544
1545 default:
1546 LOG(FATAL) << "Unexpected type conversion from " << input_type
1547 << " to " << result_type;
1548 };
1549 break;
1550
Roland Levillaindff1f282014-11-05 14:15:05 +00001551 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001552 switch (input_type) {
1553 case Primitive::kPrimByte:
1554 case Primitive::kPrimShort:
1555 case Primitive::kPrimInt:
1556 case Primitive::kPrimChar:
1557 // Processing a Dex `int-to-double' instruction.
1558 locations->SetInAt(0, Location::RequiresRegister());
1559 locations->SetOut(Location::RequiresFpuRegister());
1560 break;
1561
1562 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001563 // Processing a Dex `long-to-double' instruction.
1564 locations->SetInAt(0, Location::RequiresRegister());
1565 locations->SetOut(Location::RequiresFpuRegister());
1566 break;
1567
Roland Levillaincff13742014-11-17 14:32:17 +00001568 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001569 // Processing a Dex `float-to-double' instruction.
1570 locations->SetInAt(0, Location::RequiresFpuRegister());
1571 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001572 break;
1573
1574 default:
1575 LOG(FATAL) << "Unexpected type conversion from " << input_type
1576 << " to " << result_type;
1577 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001578 break;
1579
1580 default:
1581 LOG(FATAL) << "Unexpected type conversion from " << input_type
1582 << " to " << result_type;
1583 }
1584}
1585
1586void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1587 LocationSummary* locations = conversion->GetLocations();
1588 Location out = locations->Out();
1589 Location in = locations->InAt(0);
1590 Primitive::Type result_type = conversion->GetResultType();
1591 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001592 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001593 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001594 case Primitive::kPrimByte:
1595 switch (input_type) {
1596 case Primitive::kPrimShort:
1597 case Primitive::kPrimInt:
1598 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001599 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001600 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001601 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001602 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001603 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001604 Address(CpuRegister(RSP), in.GetStackIndex()));
1605 } else {
1606 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001607 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001608 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1609 }
1610 break;
1611
1612 default:
1613 LOG(FATAL) << "Unexpected type conversion from " << input_type
1614 << " to " << result_type;
1615 }
1616 break;
1617
Roland Levillain01a8d712014-11-14 16:27:39 +00001618 case Primitive::kPrimShort:
1619 switch (input_type) {
1620 case Primitive::kPrimByte:
1621 case Primitive::kPrimInt:
1622 case Primitive::kPrimChar:
1623 // Processing a Dex `int-to-short' instruction.
1624 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001625 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001626 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001627 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001628 Address(CpuRegister(RSP), in.GetStackIndex()));
1629 } else {
1630 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001631 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001632 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1633 }
1634 break;
1635
1636 default:
1637 LOG(FATAL) << "Unexpected type conversion from " << input_type
1638 << " to " << result_type;
1639 }
1640 break;
1641
Roland Levillain946e1432014-11-11 17:35:19 +00001642 case Primitive::kPrimInt:
1643 switch (input_type) {
1644 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001645 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001646 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001647 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001648 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001649 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001650 Address(CpuRegister(RSP), in.GetStackIndex()));
1651 } else {
1652 DCHECK(in.IsConstant());
1653 DCHECK(in.GetConstant()->IsLongConstant());
1654 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001655 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001656 }
1657 break;
1658
Roland Levillain3f8f9362014-12-02 17:45:01 +00001659 case Primitive::kPrimFloat: {
1660 // Processing a Dex `float-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-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001668 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001669 // if input >= temp goto done
1670 __ comiss(input, temp);
1671 __ j(kAboveEqual, &done);
1672 // if input == NaN goto nan
1673 __ j(kUnordered, &nan);
1674 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001675 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001676 __ jmp(&done);
1677 __ Bind(&nan);
1678 // output = 0
1679 __ xorl(output, output);
1680 __ Bind(&done);
1681 break;
1682 }
1683
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001684 case Primitive::kPrimDouble: {
1685 // Processing a Dex `double-to-int' instruction.
1686 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1687 CpuRegister output = out.AsRegister<CpuRegister>();
1688 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1689 Label done, nan;
1690
1691 __ movl(output, Immediate(kPrimIntMax));
1692 // temp = int-to-double(output)
1693 __ cvtsi2sd(temp, output);
1694 // if input >= temp goto done
1695 __ comisd(input, temp);
1696 __ j(kAboveEqual, &done);
1697 // if input == NaN goto nan
1698 __ j(kUnordered, &nan);
1699 // output = double-to-int-truncate(input)
1700 __ cvttsd2si(output, input);
1701 __ jmp(&done);
1702 __ Bind(&nan);
1703 // output = 0
1704 __ xorl(output, output);
1705 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001706 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001707 }
Roland Levillain946e1432014-11-11 17:35:19 +00001708
1709 default:
1710 LOG(FATAL) << "Unexpected type conversion from " << input_type
1711 << " to " << result_type;
1712 }
1713 break;
1714
Roland Levillaindff1f282014-11-05 14:15:05 +00001715 case Primitive::kPrimLong:
1716 switch (input_type) {
1717 DCHECK(out.IsRegister());
1718 case Primitive::kPrimByte:
1719 case Primitive::kPrimShort:
1720 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001721 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001722 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001723 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001724 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001725 break;
1726
Roland Levillain624279f2014-12-04 11:54:28 +00001727 case Primitive::kPrimFloat: {
1728 // Processing a Dex `float-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));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001735 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001736 __ cvtsi2ss(temp, output, true);
1737 // if input >= temp goto done
1738 __ comiss(input, temp);
1739 __ j(kAboveEqual, &done);
1740 // if input == NaN goto nan
1741 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001742 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001743 __ cvttss2si(output, input, true);
1744 __ jmp(&done);
1745 __ Bind(&nan);
1746 // output = 0
1747 __ xorq(output, output);
1748 __ Bind(&done);
1749 break;
1750 }
1751
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001752 case Primitive::kPrimDouble: {
1753 // Processing a Dex `double-to-long' instruction.
1754 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1755 CpuRegister output = out.AsRegister<CpuRegister>();
1756 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1757 Label done, nan;
1758
1759 __ movq(output, Immediate(kPrimLongMax));
1760 // temp = long-to-double(output)
1761 __ cvtsi2sd(temp, output, true);
1762 // if input >= temp goto done
1763 __ comisd(input, temp);
1764 __ j(kAboveEqual, &done);
1765 // if input == NaN goto nan
1766 __ j(kUnordered, &nan);
1767 // output = double-to-long-truncate(input)
1768 __ cvttsd2si(output, input, true);
1769 __ jmp(&done);
1770 __ Bind(&nan);
1771 // output = 0
1772 __ xorq(output, output);
1773 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001774 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001775 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001776
1777 default:
1778 LOG(FATAL) << "Unexpected type conversion from " << input_type
1779 << " to " << result_type;
1780 }
1781 break;
1782
Roland Levillain981e4542014-11-14 11:47:14 +00001783 case Primitive::kPrimChar:
1784 switch (input_type) {
1785 case Primitive::kPrimByte:
1786 case Primitive::kPrimShort:
1787 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001788 // Processing a Dex `int-to-char' instruction.
1789 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001790 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001791 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001792 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001793 Address(CpuRegister(RSP), in.GetStackIndex()));
1794 } else {
1795 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001796 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001797 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1798 }
1799 break;
1800
1801 default:
1802 LOG(FATAL) << "Unexpected type conversion from " << input_type
1803 << " to " << result_type;
1804 }
1805 break;
1806
Roland Levillaindff1f282014-11-05 14:15:05 +00001807 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001808 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001809 case Primitive::kPrimByte:
1810 case Primitive::kPrimShort:
1811 case Primitive::kPrimInt:
1812 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001813 // Processing a Dex `int-to-float' instruction.
1814 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001815 break;
1816
1817 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001818 // Processing a Dex `long-to-float' instruction.
1819 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1820 break;
1821
Roland Levillaincff13742014-11-17 14:32:17 +00001822 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001823 // Processing a Dex `double-to-float' instruction.
1824 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001825 break;
1826
1827 default:
1828 LOG(FATAL) << "Unexpected type conversion from " << input_type
1829 << " to " << result_type;
1830 };
1831 break;
1832
Roland Levillaindff1f282014-11-05 14:15:05 +00001833 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001834 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001835 case Primitive::kPrimByte:
1836 case Primitive::kPrimShort:
1837 case Primitive::kPrimInt:
1838 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001839 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001840 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001841 break;
1842
1843 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001844 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001845 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001846 break;
1847
Roland Levillaincff13742014-11-17 14:32:17 +00001848 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001849 // Processing a Dex `float-to-double' instruction.
1850 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001851 break;
1852
1853 default:
1854 LOG(FATAL) << "Unexpected type conversion from " << input_type
1855 << " to " << result_type;
1856 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001857 break;
1858
1859 default:
1860 LOG(FATAL) << "Unexpected type conversion from " << input_type
1861 << " to " << result_type;
1862 }
1863}
1864
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001865void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001866 LocationSummary* locations =
1867 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001868 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001869 case Primitive::kPrimInt: {
1870 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001871 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1872 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001873 break;
1874 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001875
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001876 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001877 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05001878 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001879 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05001880 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001881 break;
1882 }
1883
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001884 case Primitive::kPrimDouble:
1885 case Primitive::kPrimFloat: {
1886 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001887 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001888 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001889 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001890 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001891
1892 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001893 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001894 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001895}
1896
1897void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1898 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001899 Location first = locations->InAt(0);
1900 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001901 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01001902
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001903 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001904 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001905 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001906 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1907 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1908 } else {
1909 __ leal(out.AsRegister<CpuRegister>(), Address(
1910 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1911 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001912 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001913 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1914 __ addl(out.AsRegister<CpuRegister>(),
1915 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
1916 } else {
1917 __ leal(out.AsRegister<CpuRegister>(), Address(
1918 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
1919 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001920 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001921 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001922 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001923 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001924 break;
1925 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001926
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001927 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05001928 if (second.IsRegister()) {
1929 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1930 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1931 } else {
1932 __ leaq(out.AsRegister<CpuRegister>(), Address(
1933 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1934 }
1935 } else {
1936 DCHECK(second.IsConstant());
1937 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1938 int32_t int32_value = Low32Bits(value);
1939 DCHECK_EQ(int32_value, value);
1940 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1941 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
1942 } else {
1943 __ leaq(out.AsRegister<CpuRegister>(), Address(
1944 first.AsRegister<CpuRegister>(), int32_value));
1945 }
1946 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001947 break;
1948 }
1949
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001950 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001951 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001952 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001953 }
1954
1955 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001956 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001957 break;
1958 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001959
1960 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001961 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001962 }
1963}
1964
1965void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001966 LocationSummary* locations =
1967 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001968 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001969 case Primitive::kPrimInt: {
1970 locations->SetInAt(0, Location::RequiresRegister());
1971 locations->SetInAt(1, Location::Any());
1972 locations->SetOut(Location::SameAsFirstInput());
1973 break;
1974 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001975 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001976 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001977 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001978 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001979 break;
1980 }
Calin Juravle11351682014-10-23 15:38:15 +01001981 case Primitive::kPrimFloat:
1982 case Primitive::kPrimDouble: {
1983 locations->SetInAt(0, Location::RequiresFpuRegister());
1984 locations->SetInAt(1, Location::RequiresFpuRegister());
1985 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001986 break;
Calin Juravle11351682014-10-23 15:38:15 +01001987 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001988 default:
Calin Juravle11351682014-10-23 15:38:15 +01001989 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001990 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001991}
1992
1993void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
1994 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001995 Location first = locations->InAt(0);
1996 Location second = locations->InAt(1);
1997 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001998 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001999 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002000 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002001 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002002 } else if (second.IsConstant()) {
2003 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002004 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002005 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002006 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002007 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002008 break;
2009 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002010 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002011 if (second.IsConstant()) {
2012 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2013 DCHECK(IsInt<32>(value));
2014 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2015 } else {
2016 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2017 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002018 break;
2019 }
2020
Calin Juravle11351682014-10-23 15:38:15 +01002021 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002022 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002023 break;
Calin Juravle11351682014-10-23 15:38:15 +01002024 }
2025
2026 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002027 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002028 break;
2029 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002030
2031 default:
Calin Juravle11351682014-10-23 15:38:15 +01002032 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002033 }
2034}
2035
Calin Juravle34bacdf2014-10-07 20:23:36 +01002036void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2037 LocationSummary* locations =
2038 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2039 switch (mul->GetResultType()) {
2040 case Primitive::kPrimInt: {
2041 locations->SetInAt(0, Location::RequiresRegister());
2042 locations->SetInAt(1, Location::Any());
2043 locations->SetOut(Location::SameAsFirstInput());
2044 break;
2045 }
2046 case Primitive::kPrimLong: {
2047 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002048 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2049 if (locations->InAt(1).IsConstant()) {
2050 // Can use 3 operand multiply.
2051 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2052 } else {
2053 locations->SetOut(Location::SameAsFirstInput());
2054 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002055 break;
2056 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002057 case Primitive::kPrimFloat:
2058 case Primitive::kPrimDouble: {
2059 locations->SetInAt(0, Location::RequiresFpuRegister());
2060 locations->SetInAt(1, Location::RequiresFpuRegister());
2061 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002062 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002063 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002064
2065 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002066 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002067 }
2068}
2069
2070void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2071 LocationSummary* locations = mul->GetLocations();
2072 Location first = locations->InAt(0);
2073 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002074 switch (mul->GetResultType()) {
2075 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002076 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002077 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002078 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002079 } else if (second.IsConstant()) {
2080 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002081 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002082 } else {
2083 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002084 __ imull(first.AsRegister<CpuRegister>(),
2085 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002086 }
2087 break;
2088 }
2089 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002090 if (second.IsConstant()) {
2091 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2092 DCHECK(IsInt<32>(value));
2093 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2094 first.AsRegister<CpuRegister>(),
2095 Immediate(static_cast<int32_t>(value)));
2096 } else {
2097 DCHECK(first.Equals(locations->Out()));
2098 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2099 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002100 break;
2101 }
2102
Calin Juravleb5bfa962014-10-21 18:02:24 +01002103 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002104 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002105 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002106 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002107 }
2108
2109 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002110 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002111 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002112 break;
2113 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002114
2115 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002116 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002117 }
2118}
2119
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002120void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2121 uint32_t stack_adjustment, bool is_float) {
2122 if (source.IsStackSlot()) {
2123 DCHECK(is_float);
2124 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2125 } else if (source.IsDoubleStackSlot()) {
2126 DCHECK(!is_float);
2127 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2128 } else {
2129 // Write the value to the temporary location on the stack and load to FP stack.
2130 if (is_float) {
2131 Location stack_temp = Location::StackSlot(temp_offset);
2132 codegen_->Move(stack_temp, source);
2133 __ flds(Address(CpuRegister(RSP), temp_offset));
2134 } else {
2135 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2136 codegen_->Move(stack_temp, source);
2137 __ fldl(Address(CpuRegister(RSP), temp_offset));
2138 }
2139 }
2140}
2141
2142void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2143 Primitive::Type type = rem->GetResultType();
2144 bool is_float = type == Primitive::kPrimFloat;
2145 size_t elem_size = Primitive::ComponentSize(type);
2146 LocationSummary* locations = rem->GetLocations();
2147 Location first = locations->InAt(0);
2148 Location second = locations->InAt(1);
2149 Location out = locations->Out();
2150
2151 // Create stack space for 2 elements.
2152 // TODO: enhance register allocator to ask for stack temporaries.
2153 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2154
2155 // Load the values to the FP stack in reverse order, using temporaries if needed.
2156 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2157 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2158
2159 // Loop doing FPREM until we stabilize.
2160 Label retry;
2161 __ Bind(&retry);
2162 __ fprem();
2163
2164 // Move FP status to AX.
2165 __ fstsw();
2166
2167 // And see if the argument reduction is complete. This is signaled by the
2168 // C2 FPU flag bit set to 0.
2169 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2170 __ j(kNotEqual, &retry);
2171
2172 // We have settled on the final value. Retrieve it into an XMM register.
2173 // Store FP top of stack to real stack.
2174 if (is_float) {
2175 __ fsts(Address(CpuRegister(RSP), 0));
2176 } else {
2177 __ fstl(Address(CpuRegister(RSP), 0));
2178 }
2179
2180 // Pop the 2 items from the FP stack.
2181 __ fucompp();
2182
2183 // Load the value from the stack into an XMM register.
2184 DCHECK(out.IsFpuRegister()) << out;
2185 if (is_float) {
2186 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2187 } else {
2188 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2189 }
2190
2191 // And remove the temporary stack space we allocated.
2192 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2193}
2194
Calin Juravlebacfec32014-11-14 15:54:36 +00002195void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2196 DCHECK(instruction->IsDiv() || instruction->IsRem());
2197 Primitive::Type type = instruction->GetResultType();
2198 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2199
2200 bool is_div = instruction->IsDiv();
2201 LocationSummary* locations = instruction->GetLocations();
2202
Roland Levillain271ab9c2014-11-27 15:23:57 +00002203 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2204 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002205
Roland Levillain271ab9c2014-11-27 15:23:57 +00002206 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002207 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2208
2209 SlowPathCodeX86_64* slow_path =
2210 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2211 out_reg.AsRegister(), type, is_div);
2212 codegen_->AddSlowPath(slow_path);
2213
2214 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2215 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2216 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002217 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002218 __ cmpl(second_reg, Immediate(-1));
2219 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002220 // edx:eax <- sign-extended of eax
2221 __ cdq();
2222 // eax = quotient, edx = remainder
2223 __ idivl(second_reg);
2224 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002225 __ cmpq(second_reg, Immediate(-1));
2226 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002227 // rdx:rax <- sign-extended of rax
2228 __ cqo();
2229 // rax = quotient, rdx = remainder
2230 __ idivq(second_reg);
2231 }
2232
2233 __ Bind(slow_path->GetExitLabel());
2234}
2235
Calin Juravle7c4954d2014-10-28 16:57:40 +00002236void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2237 LocationSummary* locations =
2238 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2239 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002240 case Primitive::kPrimInt:
2241 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002242 locations->SetInAt(0, Location::RegisterLocation(RAX));
2243 locations->SetInAt(1, Location::RequiresRegister());
2244 locations->SetOut(Location::SameAsFirstInput());
2245 // Intel uses edx:eax as the dividend.
2246 locations->AddTemp(Location::RegisterLocation(RDX));
2247 break;
2248 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002249
Calin Juravle7c4954d2014-10-28 16:57:40 +00002250 case Primitive::kPrimFloat:
2251 case Primitive::kPrimDouble: {
2252 locations->SetInAt(0, Location::RequiresFpuRegister());
2253 locations->SetInAt(1, Location::RequiresFpuRegister());
2254 locations->SetOut(Location::SameAsFirstInput());
2255 break;
2256 }
2257
2258 default:
2259 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2260 }
2261}
2262
2263void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2264 LocationSummary* locations = div->GetLocations();
2265 Location first = locations->InAt(0);
2266 Location second = locations->InAt(1);
2267 DCHECK(first.Equals(locations->Out()));
2268
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002269 Primitive::Type type = div->GetResultType();
2270 switch (type) {
2271 case Primitive::kPrimInt:
2272 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002273 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002274 break;
2275 }
2276
Calin Juravle7c4954d2014-10-28 16:57:40 +00002277 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002278 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002279 break;
2280 }
2281
2282 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002283 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002284 break;
2285 }
2286
2287 default:
2288 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2289 }
2290}
2291
Calin Juravlebacfec32014-11-14 15:54:36 +00002292void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002293 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002294 LocationSummary* locations =
2295 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002296
2297 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002298 case Primitive::kPrimInt:
2299 case Primitive::kPrimLong: {
2300 locations->SetInAt(0, Location::RegisterLocation(RAX));
2301 locations->SetInAt(1, Location::RequiresRegister());
2302 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2303 locations->SetOut(Location::RegisterLocation(RDX));
2304 break;
2305 }
2306
2307 case Primitive::kPrimFloat:
2308 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002309 locations->SetInAt(0, Location::Any());
2310 locations->SetInAt(1, Location::Any());
2311 locations->SetOut(Location::RequiresFpuRegister());
2312 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002313 break;
2314 }
2315
2316 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002317 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002318 }
2319}
2320
2321void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2322 Primitive::Type type = rem->GetResultType();
2323 switch (type) {
2324 case Primitive::kPrimInt:
2325 case Primitive::kPrimLong: {
2326 GenerateDivRemIntegral(rem);
2327 break;
2328 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002329 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002330 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002331 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002332 break;
2333 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002334 default:
2335 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2336 }
2337}
2338
Calin Juravled0d48522014-11-04 16:40:20 +00002339void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2340 LocationSummary* locations =
2341 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2342 locations->SetInAt(0, Location::Any());
2343 if (instruction->HasUses()) {
2344 locations->SetOut(Location::SameAsFirstInput());
2345 }
2346}
2347
2348void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2349 SlowPathCodeX86_64* slow_path =
2350 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2351 codegen_->AddSlowPath(slow_path);
2352
2353 LocationSummary* locations = instruction->GetLocations();
2354 Location value = locations->InAt(0);
2355
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002356 switch (instruction->GetType()) {
2357 case Primitive::kPrimInt: {
2358 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002359 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002360 __ j(kEqual, slow_path->GetEntryLabel());
2361 } else if (value.IsStackSlot()) {
2362 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2363 __ j(kEqual, slow_path->GetEntryLabel());
2364 } else {
2365 DCHECK(value.IsConstant()) << value;
2366 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2367 __ jmp(slow_path->GetEntryLabel());
2368 }
2369 }
2370 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002371 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002372 case Primitive::kPrimLong: {
2373 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002374 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002375 __ j(kEqual, slow_path->GetEntryLabel());
2376 } else if (value.IsDoubleStackSlot()) {
2377 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2378 __ j(kEqual, slow_path->GetEntryLabel());
2379 } else {
2380 DCHECK(value.IsConstant()) << value;
2381 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2382 __ jmp(slow_path->GetEntryLabel());
2383 }
2384 }
2385 break;
2386 }
2387 default:
2388 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002389 }
Calin Juravled0d48522014-11-04 16:40:20 +00002390}
2391
Calin Juravle9aec02f2014-11-18 23:06:35 +00002392void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2393 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2394
2395 LocationSummary* locations =
2396 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2397
2398 switch (op->GetResultType()) {
2399 case Primitive::kPrimInt:
2400 case Primitive::kPrimLong: {
2401 locations->SetInAt(0, Location::RequiresRegister());
2402 // The shift count needs to be in CL.
2403 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2404 locations->SetOut(Location::SameAsFirstInput());
2405 break;
2406 }
2407 default:
2408 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2409 }
2410}
2411
2412void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2413 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2414
2415 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002416 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002417 Location second = locations->InAt(1);
2418
2419 switch (op->GetResultType()) {
2420 case Primitive::kPrimInt: {
2421 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002422 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002423 if (op->IsShl()) {
2424 __ shll(first_reg, second_reg);
2425 } else if (op->IsShr()) {
2426 __ sarl(first_reg, second_reg);
2427 } else {
2428 __ shrl(first_reg, second_reg);
2429 }
2430 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002431 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002432 if (op->IsShl()) {
2433 __ shll(first_reg, imm);
2434 } else if (op->IsShr()) {
2435 __ sarl(first_reg, imm);
2436 } else {
2437 __ shrl(first_reg, imm);
2438 }
2439 }
2440 break;
2441 }
2442 case Primitive::kPrimLong: {
2443 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002444 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002445 if (op->IsShl()) {
2446 __ shlq(first_reg, second_reg);
2447 } else if (op->IsShr()) {
2448 __ sarq(first_reg, second_reg);
2449 } else {
2450 __ shrq(first_reg, second_reg);
2451 }
2452 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002453 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002454 if (op->IsShl()) {
2455 __ shlq(first_reg, imm);
2456 } else if (op->IsShr()) {
2457 __ sarq(first_reg, imm);
2458 } else {
2459 __ shrq(first_reg, imm);
2460 }
2461 }
2462 break;
2463 }
2464 default:
2465 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2466 }
2467}
2468
2469void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2470 HandleShift(shl);
2471}
2472
2473void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2474 HandleShift(shl);
2475}
2476
2477void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2478 HandleShift(shr);
2479}
2480
2481void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2482 HandleShift(shr);
2483}
2484
2485void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2486 HandleShift(ushr);
2487}
2488
2489void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2490 HandleShift(ushr);
2491}
2492
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002493void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002494 LocationSummary* locations =
2495 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002496 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002497 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2498 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2499 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002500}
2501
2502void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2503 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002504 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002505 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2506
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002507 __ gs()->call(
2508 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002509
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002510 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002511 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002512}
2513
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002514void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2515 LocationSummary* locations =
2516 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2517 InvokeRuntimeCallingConvention calling_convention;
2518 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002519 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002520 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002521 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002522}
2523
2524void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2525 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002526 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002527 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2528
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002529 __ gs()->call(
2530 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002531
2532 DCHECK(!codegen_->IsLeafMethod());
2533 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2534}
2535
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002536void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002537 LocationSummary* locations =
2538 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002539 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2540 if (location.IsStackSlot()) {
2541 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2542 } else if (location.IsDoubleStackSlot()) {
2543 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2544 }
2545 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002546}
2547
2548void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2549 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002550 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002551}
2552
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002553void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002554 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002555 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002556 locations->SetInAt(0, Location::RequiresRegister());
2557 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002558}
2559
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002560void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2561 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002562 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2563 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002564 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002565 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002566 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002567 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002568 break;
2569
2570 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002571 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002572 break;
2573
2574 default:
2575 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2576 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002577}
2578
2579void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002580 LocationSummary* locations =
2581 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002582 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2583 locations->SetInAt(i, Location::Any());
2584 }
2585 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002586}
2587
2588void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002589 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002590 LOG(FATAL) << "Unimplemented";
2591}
2592
Calin Juravle52c48962014-12-16 17:02:57 +00002593void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2594 /*
2595 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2596 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2597 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2598 */
2599 switch (kind) {
2600 case MemBarrierKind::kAnyAny: {
2601 __ mfence();
2602 break;
2603 }
2604 case MemBarrierKind::kAnyStore:
2605 case MemBarrierKind::kLoadAny:
2606 case MemBarrierKind::kStoreStore: {
2607 // nop
2608 break;
2609 }
2610 default:
2611 LOG(FATAL) << "Unexpected memory barier " << kind;
2612 }
2613}
2614
2615void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2616 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2617
Nicolas Geoffray39468442014-09-02 15:17:15 +01002618 LocationSummary* locations =
2619 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002620 locations->SetInAt(0, Location::RequiresRegister());
2621 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2622}
2623
2624void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2625 const FieldInfo& field_info) {
2626 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2627
2628 LocationSummary* locations = instruction->GetLocations();
2629 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2630 Location out = locations->Out();
2631 bool is_volatile = field_info.IsVolatile();
2632 Primitive::Type field_type = field_info.GetFieldType();
2633 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2634
2635 switch (field_type) {
2636 case Primitive::kPrimBoolean: {
2637 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2638 break;
2639 }
2640
2641 case Primitive::kPrimByte: {
2642 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2643 break;
2644 }
2645
2646 case Primitive::kPrimShort: {
2647 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2648 break;
2649 }
2650
2651 case Primitive::kPrimChar: {
2652 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2653 break;
2654 }
2655
2656 case Primitive::kPrimInt:
2657 case Primitive::kPrimNot: {
2658 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2659 break;
2660 }
2661
2662 case Primitive::kPrimLong: {
2663 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2664 break;
2665 }
2666
2667 case Primitive::kPrimFloat: {
2668 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2669 break;
2670 }
2671
2672 case Primitive::kPrimDouble: {
2673 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2674 break;
2675 }
2676
2677 case Primitive::kPrimVoid:
2678 LOG(FATAL) << "Unreachable type " << field_type;
2679 UNREACHABLE();
2680 }
2681
Calin Juravle77520bc2015-01-12 18:45:46 +00002682 codegen_->MaybeRecordImplicitNullCheck(instruction);
2683
Calin Juravle52c48962014-12-16 17:02:57 +00002684 if (is_volatile) {
2685 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2686 }
2687}
2688
2689void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2690 const FieldInfo& field_info) {
2691 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2692
2693 LocationSummary* locations =
2694 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002695 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002696 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2697
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002698 locations->SetInAt(0, Location::RequiresRegister());
2699 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002700 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002701 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002702 locations->AddTemp(Location::RequiresRegister());
2703 locations->AddTemp(Location::RequiresRegister());
2704 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002705}
2706
Calin Juravle52c48962014-12-16 17:02:57 +00002707void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2708 const FieldInfo& field_info) {
2709 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2710
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002711 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002712 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2713 Location value = locations->InAt(1);
2714 bool is_volatile = field_info.IsVolatile();
2715 Primitive::Type field_type = field_info.GetFieldType();
2716 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2717
2718 if (is_volatile) {
2719 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2720 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002721
2722 switch (field_type) {
2723 case Primitive::kPrimBoolean:
2724 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002725 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002726 break;
2727 }
2728
2729 case Primitive::kPrimShort:
2730 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002731 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002732 break;
2733 }
2734
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002735 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002736 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002737 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002738 break;
2739 }
2740
2741 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002742 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002743 break;
2744 }
2745
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002746 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002747 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002748 break;
2749 }
2750
2751 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002752 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002753 break;
2754 }
2755
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002756 case Primitive::kPrimVoid:
2757 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002758 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002759 }
Calin Juravle52c48962014-12-16 17:02:57 +00002760
Calin Juravle77520bc2015-01-12 18:45:46 +00002761 codegen_->MaybeRecordImplicitNullCheck(instruction);
2762
2763 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2764 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2765 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2766 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2767 }
2768
Calin Juravle52c48962014-12-16 17:02:57 +00002769 if (is_volatile) {
2770 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2771 }
2772}
2773
2774void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2775 HandleFieldSet(instruction, instruction->GetFieldInfo());
2776}
2777
2778void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2779 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002780}
2781
2782void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002783 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002784}
2785
2786void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002787 HandleFieldGet(instruction, instruction->GetFieldInfo());
2788}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002789
Calin Juravle52c48962014-12-16 17:02:57 +00002790void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2791 HandleFieldGet(instruction);
2792}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002793
Calin Juravle52c48962014-12-16 17:02:57 +00002794void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2795 HandleFieldGet(instruction, instruction->GetFieldInfo());
2796}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002797
Calin Juravle52c48962014-12-16 17:02:57 +00002798void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2799 HandleFieldSet(instruction, instruction->GetFieldInfo());
2800}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002801
Calin Juravle52c48962014-12-16 17:02:57 +00002802void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2803 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002804}
2805
2806void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002807 LocationSummary* locations =
2808 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002809 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2810 ? Location::RequiresRegister()
2811 : Location::Any();
2812 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002813 if (instruction->HasUses()) {
2814 locations->SetOut(Location::SameAsFirstInput());
2815 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002816}
2817
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002818void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002819 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2820 return;
2821 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002822 LocationSummary* locations = instruction->GetLocations();
2823 Location obj = locations->InAt(0);
2824
2825 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2826 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2827}
2828
2829void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002830 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002831 codegen_->AddSlowPath(slow_path);
2832
2833 LocationSummary* locations = instruction->GetLocations();
2834 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002835
2836 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002837 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002838 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002839 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002840 } else {
2841 DCHECK(obj.IsConstant()) << obj;
2842 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2843 __ jmp(slow_path->GetEntryLabel());
2844 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002845 }
2846 __ j(kEqual, slow_path->GetEntryLabel());
2847}
2848
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002849void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2850 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2851 GenerateImplicitNullCheck(instruction);
2852 } else {
2853 GenerateExplicitNullCheck(instruction);
2854 }
2855}
2856
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002857void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002858 LocationSummary* locations =
2859 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002860 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002861 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002862 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2863 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002864}
2865
2866void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2867 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002868 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002869 Location index = locations->InAt(1);
2870
2871 switch (instruction->GetType()) {
2872 case Primitive::kPrimBoolean: {
2873 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002874 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002875 if (index.IsConstant()) {
2876 __ movzxb(out, Address(obj,
2877 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2878 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002879 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002880 }
2881 break;
2882 }
2883
2884 case Primitive::kPrimByte: {
2885 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002886 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002887 if (index.IsConstant()) {
2888 __ movsxb(out, Address(obj,
2889 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2890 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002891 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002892 }
2893 break;
2894 }
2895
2896 case Primitive::kPrimShort: {
2897 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002898 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002899 if (index.IsConstant()) {
2900 __ movsxw(out, Address(obj,
2901 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2902 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002903 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002904 }
2905 break;
2906 }
2907
2908 case Primitive::kPrimChar: {
2909 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002910 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002911 if (index.IsConstant()) {
2912 __ movzxw(out, Address(obj,
2913 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2914 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002915 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002916 }
2917 break;
2918 }
2919
2920 case Primitive::kPrimInt:
2921 case Primitive::kPrimNot: {
2922 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2923 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002924 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002925 if (index.IsConstant()) {
2926 __ movl(out, Address(obj,
2927 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2928 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002929 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002930 }
2931 break;
2932 }
2933
2934 case Primitive::kPrimLong: {
2935 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002936 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002937 if (index.IsConstant()) {
2938 __ movq(out, Address(obj,
2939 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2940 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002941 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002942 }
2943 break;
2944 }
2945
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002946 case Primitive::kPrimFloat: {
2947 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002948 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002949 if (index.IsConstant()) {
2950 __ movss(out, Address(obj,
2951 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2952 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002953 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002954 }
2955 break;
2956 }
2957
2958 case Primitive::kPrimDouble: {
2959 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002960 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002961 if (index.IsConstant()) {
2962 __ movsd(out, Address(obj,
2963 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2964 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002965 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002966 }
2967 break;
2968 }
2969
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002970 case Primitive::kPrimVoid:
2971 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002972 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002973 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002974 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002975}
2976
2977void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002978 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002979
2980 bool needs_write_barrier =
2981 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2982 bool needs_runtime_call = instruction->NeedsTypeCheck();
2983
Nicolas Geoffray39468442014-09-02 15:17:15 +01002984 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002985 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
2986 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002987 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002988 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2989 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2990 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002991 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002992 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002993 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002994 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2995 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002996 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002997 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002998 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
2999 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003000 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003001 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003002 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003003
3004 if (needs_write_barrier) {
3005 // Temporary registers for the write barrier.
3006 locations->AddTemp(Location::RequiresRegister());
3007 locations->AddTemp(Location::RequiresRegister());
3008 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003009 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003010}
3011
3012void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3013 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003014 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003015 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003016 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003017 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003018 bool needs_runtime_call = locations->WillCall();
3019 bool needs_write_barrier =
3020 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003021
3022 switch (value_type) {
3023 case Primitive::kPrimBoolean:
3024 case Primitive::kPrimByte: {
3025 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003026 if (index.IsConstant()) {
3027 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003028 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003029 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003030 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003031 __ movb(Address(obj, offset),
3032 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003033 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003034 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003035 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003036 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3037 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003038 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003039 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003040 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3041 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003042 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003043 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003044 break;
3045 }
3046
3047 case Primitive::kPrimShort:
3048 case Primitive::kPrimChar: {
3049 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003050 if (index.IsConstant()) {
3051 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003052 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003053 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003054 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003055 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003056 __ movw(Address(obj, offset),
3057 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003058 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003059 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003060 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003061 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003062 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3063 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003064 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003065 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003066 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003067 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3068 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003069 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003070 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003071 break;
3072 }
3073
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003074 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003075 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003076 if (!needs_runtime_call) {
3077 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3078 if (index.IsConstant()) {
3079 size_t offset =
3080 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3081 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003082 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003083 } else {
3084 DCHECK(value.IsConstant()) << value;
3085 __ movl(Address(obj, offset),
3086 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3087 }
3088 } else {
3089 DCHECK(index.IsRegister()) << index;
3090 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003091 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3092 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003093 } else {
3094 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003095 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003096 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3097 }
3098 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003099 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003100 if (needs_write_barrier) {
3101 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003102 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3103 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3104 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003105 }
3106 } else {
3107 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003108 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3109 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003110 DCHECK(!codegen_->IsLeafMethod());
3111 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3112 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003113 break;
3114 }
3115
3116 case Primitive::kPrimLong: {
3117 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003118 if (index.IsConstant()) {
3119 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003120 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003121 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003122 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003123 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003124 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3125 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003126 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003127 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003128 break;
3129 }
3130
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003131 case Primitive::kPrimFloat: {
3132 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3133 if (index.IsConstant()) {
3134 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3135 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003136 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003137 } else {
3138 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003139 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3140 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003141 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003142 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003143 break;
3144 }
3145
3146 case Primitive::kPrimDouble: {
3147 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3148 if (index.IsConstant()) {
3149 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3150 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003151 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003152 } else {
3153 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003154 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3155 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003156 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003157 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003158 break;
3159 }
3160
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003161 case Primitive::kPrimVoid:
3162 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003163 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003164 }
3165}
3166
3167void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003168 LocationSummary* locations =
3169 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003170 locations->SetInAt(0, Location::RequiresRegister());
3171 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003172}
3173
3174void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3175 LocationSummary* locations = instruction->GetLocations();
3176 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003177 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3178 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003179 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003180 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003181}
3182
3183void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003184 LocationSummary* locations =
3185 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003186 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003187 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003188 if (instruction->HasUses()) {
3189 locations->SetOut(Location::SameAsFirstInput());
3190 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003191}
3192
3193void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3194 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003195 Location index_loc = locations->InAt(0);
3196 Location length_loc = locations->InAt(1);
3197 SlowPathCodeX86_64* slow_path =
3198 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003199 codegen_->AddSlowPath(slow_path);
3200
Mark Mendellf60c90b2015-03-04 15:12:59 -05003201 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3202 if (index_loc.IsConstant()) {
3203 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3204 __ cmpl(length, Immediate(value));
3205 } else {
3206 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3207 }
3208 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003209}
3210
3211void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3212 CpuRegister card,
3213 CpuRegister object,
3214 CpuRegister value) {
3215 Label is_null;
3216 __ testl(value, value);
3217 __ j(kEqual, &is_null);
3218 __ gs()->movq(card, Address::Absolute(
3219 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3220 __ movq(temp, object);
3221 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3222 __ movb(Address(temp, card, TIMES_1, 0), card);
3223 __ Bind(&is_null);
3224}
3225
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003226void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3227 temp->SetLocations(nullptr);
3228}
3229
3230void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3231 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003232 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003233}
3234
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003235void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003236 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003237 LOG(FATAL) << "Unimplemented";
3238}
3239
3240void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003241 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3242}
3243
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003244void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3245 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3246}
3247
3248void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003249 HBasicBlock* block = instruction->GetBlock();
3250 if (block->GetLoopInformation() != nullptr) {
3251 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3252 // The back edge will generate the suspend check.
3253 return;
3254 }
3255 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3256 // The goto will generate the suspend check.
3257 return;
3258 }
3259 GenerateSuspendCheck(instruction, nullptr);
3260}
3261
3262void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3263 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003264 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003265 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003266 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003267 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003268 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003269 if (successor == nullptr) {
3270 __ j(kNotEqual, slow_path->GetEntryLabel());
3271 __ Bind(slow_path->GetReturnLabel());
3272 } else {
3273 __ j(kEqual, codegen_->GetLabelOf(successor));
3274 __ jmp(slow_path->GetEntryLabel());
3275 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003276}
3277
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003278X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3279 return codegen_->GetAssembler();
3280}
3281
3282void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3283 MoveOperands* move = moves_.Get(index);
3284 Location source = move->GetSource();
3285 Location destination = move->GetDestination();
3286
3287 if (source.IsRegister()) {
3288 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003289 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003290 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003291 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003292 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003293 } else {
3294 DCHECK(destination.IsDoubleStackSlot());
3295 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003296 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003297 }
3298 } else if (source.IsStackSlot()) {
3299 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003300 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003301 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003302 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003303 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003304 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003305 } else {
3306 DCHECK(destination.IsStackSlot());
3307 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3308 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3309 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003310 } else if (source.IsDoubleStackSlot()) {
3311 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003312 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003313 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003314 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003315 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3316 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003317 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003318 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003319 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3320 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3321 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003322 } else if (source.IsConstant()) {
3323 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003324 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3325 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003326 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003327 if (value == 0) {
3328 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3329 } else {
3330 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3331 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003332 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003333 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003334 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003335 }
3336 } else if (constant->IsLongConstant()) {
3337 int64_t value = constant->AsLongConstant()->GetValue();
3338 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003339 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003340 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003341 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003342 __ movq(CpuRegister(TMP), Immediate(value));
3343 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3344 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003345 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003346 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003347 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003348 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003349 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003350 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3351 if (value == 0) {
3352 // easy FP 0.0.
3353 __ xorps(dest, dest);
3354 } else {
3355 __ movl(CpuRegister(TMP), imm);
3356 __ movd(dest, CpuRegister(TMP));
3357 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003358 } else {
3359 DCHECK(destination.IsStackSlot()) << destination;
3360 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3361 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003362 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003363 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003364 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003365 int64_t value = bit_cast<int64_t, double>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003366 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003367 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003368 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3369 if (value == 0) {
3370 __ xorpd(dest, dest);
3371 } else {
3372 __ movq(CpuRegister(TMP), imm);
3373 __ movd(dest, CpuRegister(TMP));
3374 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003375 } else {
3376 DCHECK(destination.IsDoubleStackSlot()) << destination;
3377 __ movq(CpuRegister(TMP), imm);
3378 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3379 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003380 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003381 } else if (source.IsFpuRegister()) {
3382 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003383 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003384 } else if (destination.IsStackSlot()) {
3385 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003386 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003387 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003388 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003389 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003390 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003391 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003392 }
3393}
3394
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003395void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003396 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003397 __ movl(Address(CpuRegister(RSP), mem), reg);
3398 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003399}
3400
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003401void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003402 ScratchRegisterScope ensure_scratch(
3403 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3404
3405 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3406 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3407 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3408 Address(CpuRegister(RSP), mem2 + stack_offset));
3409 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3410 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3411 CpuRegister(ensure_scratch.GetRegister()));
3412}
3413
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003414void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3415 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3416 __ movq(Address(CpuRegister(RSP), mem), reg);
3417 __ movq(reg, CpuRegister(TMP));
3418}
3419
3420void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3421 ScratchRegisterScope ensure_scratch(
3422 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3423
3424 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3425 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3426 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3427 Address(CpuRegister(RSP), mem2 + stack_offset));
3428 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3429 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3430 CpuRegister(ensure_scratch.GetRegister()));
3431}
3432
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003433void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3434 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3435 __ movss(Address(CpuRegister(RSP), mem), reg);
3436 __ movd(reg, CpuRegister(TMP));
3437}
3438
3439void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3440 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3441 __ movsd(Address(CpuRegister(RSP), mem), reg);
3442 __ movd(reg, CpuRegister(TMP));
3443}
3444
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003445void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3446 MoveOperands* move = moves_.Get(index);
3447 Location source = move->GetSource();
3448 Location destination = move->GetDestination();
3449
3450 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003451 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003452 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003453 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003454 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003455 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003456 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003457 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3458 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003459 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003460 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003461 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003462 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3463 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003464 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003465 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3466 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3467 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003468 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003469 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003470 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003471 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003472 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003473 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003474 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003475 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003476 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003477 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003478 }
3479}
3480
3481
3482void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3483 __ pushq(CpuRegister(reg));
3484}
3485
3486
3487void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3488 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003489}
3490
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003491void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3492 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3493 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3494 Immediate(mirror::Class::kStatusInitialized));
3495 __ j(kLess, slow_path->GetEntryLabel());
3496 __ Bind(slow_path->GetExitLabel());
3497 // No need for memory fence, thanks to the X86_64 memory model.
3498}
3499
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003500void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003501 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3502 ? LocationSummary::kCallOnSlowPath
3503 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003504 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003505 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003506 locations->SetOut(Location::RequiresRegister());
3507}
3508
3509void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003510 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003511 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003512 DCHECK(!cls->CanCallRuntime());
3513 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003514 codegen_->LoadCurrentMethod(out);
3515 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3516 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003517 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003518 codegen_->LoadCurrentMethod(out);
3519 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3520 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003521 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3522 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3523 codegen_->AddSlowPath(slow_path);
3524 __ testl(out, out);
3525 __ j(kEqual, slow_path->GetEntryLabel());
3526 if (cls->MustGenerateClinitCheck()) {
3527 GenerateClassInitializationCheck(slow_path, out);
3528 } else {
3529 __ Bind(slow_path->GetExitLabel());
3530 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003531 }
3532}
3533
3534void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3535 LocationSummary* locations =
3536 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3537 locations->SetInAt(0, Location::RequiresRegister());
3538 if (check->HasUses()) {
3539 locations->SetOut(Location::SameAsFirstInput());
3540 }
3541}
3542
3543void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003544 // We assume the class to not be null.
3545 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3546 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003547 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003548 GenerateClassInitializationCheck(slow_path,
3549 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003550}
3551
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003552void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3553 LocationSummary* locations =
3554 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3555 locations->SetOut(Location::RequiresRegister());
3556}
3557
3558void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3559 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3560 codegen_->AddSlowPath(slow_path);
3561
Roland Levillain271ab9c2014-11-27 15:23:57 +00003562 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003563 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003564 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3565 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003566 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3567 __ testl(out, out);
3568 __ j(kEqual, slow_path->GetEntryLabel());
3569 __ Bind(slow_path->GetExitLabel());
3570}
3571
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003572void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3573 LocationSummary* locations =
3574 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3575 locations->SetOut(Location::RequiresRegister());
3576}
3577
3578void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3579 Address address = Address::Absolute(
3580 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003581 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003582 __ gs()->movl(address, Immediate(0));
3583}
3584
3585void LocationsBuilderX86_64::VisitThrow(HThrow* 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::VisitThrow(HThrow* instruction) {
3593 __ gs()->call(
3594 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3595 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3596}
3597
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003598void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003599 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3600 ? LocationSummary::kNoCall
3601 : LocationSummary::kCallOnSlowPath;
3602 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3603 locations->SetInAt(0, Location::RequiresRegister());
3604 locations->SetInAt(1, Location::Any());
3605 locations->SetOut(Location::RequiresRegister());
3606}
3607
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003608void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003609 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003610 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003611 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003612 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003613 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3614 Label done, zero;
3615 SlowPathCodeX86_64* slow_path = nullptr;
3616
3617 // Return 0 if `obj` is null.
3618 // TODO: avoid this check if we know obj is not null.
3619 __ testl(obj, obj);
3620 __ j(kEqual, &zero);
3621 // Compare the class of `obj` with `cls`.
3622 __ movl(out, Address(obj, class_offset));
3623 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003624 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003625 } else {
3626 DCHECK(cls.IsStackSlot()) << cls;
3627 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3628 }
3629 if (instruction->IsClassFinal()) {
3630 // Classes must be equal for the instanceof to succeed.
3631 __ j(kNotEqual, &zero);
3632 __ movl(out, Immediate(1));
3633 __ jmp(&done);
3634 } else {
3635 // If the classes are not equal, we go into a slow path.
3636 DCHECK(locations->OnlyCallsOnSlowPath());
3637 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003638 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003639 codegen_->AddSlowPath(slow_path);
3640 __ j(kNotEqual, slow_path->GetEntryLabel());
3641 __ movl(out, Immediate(1));
3642 __ jmp(&done);
3643 }
3644 __ Bind(&zero);
3645 __ movl(out, Immediate(0));
3646 if (slow_path != nullptr) {
3647 __ Bind(slow_path->GetExitLabel());
3648 }
3649 __ Bind(&done);
3650}
3651
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003652void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3653 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3654 instruction, LocationSummary::kCallOnSlowPath);
3655 locations->SetInAt(0, Location::RequiresRegister());
3656 locations->SetInAt(1, Location::Any());
3657 locations->AddTemp(Location::RequiresRegister());
3658}
3659
3660void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3661 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003662 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003663 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003664 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003665 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3666 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3667 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3668 codegen_->AddSlowPath(slow_path);
3669
3670 // TODO: avoid this check if we know obj is not null.
3671 __ testl(obj, obj);
3672 __ j(kEqual, slow_path->GetExitLabel());
3673 // Compare the class of `obj` with `cls`.
3674 __ movl(temp, Address(obj, class_offset));
3675 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003676 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003677 } else {
3678 DCHECK(cls.IsStackSlot()) << cls;
3679 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3680 }
3681 // Classes must be equal for the checkcast to succeed.
3682 __ j(kNotEqual, slow_path->GetEntryLabel());
3683 __ Bind(slow_path->GetExitLabel());
3684}
3685
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003686void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3687 LocationSummary* locations =
3688 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3689 InvokeRuntimeCallingConvention calling_convention;
3690 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3691}
3692
3693void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3694 __ gs()->call(Address::Absolute(instruction->IsEnter()
3695 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3696 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3697 true));
3698 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3699}
3700
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003701void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3702void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3703void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3704
3705void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3706 LocationSummary* locations =
3707 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3708 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3709 || instruction->GetResultType() == Primitive::kPrimLong);
3710 locations->SetInAt(0, Location::RequiresRegister());
3711 if (instruction->GetType() == Primitive::kPrimInt) {
3712 locations->SetInAt(1, Location::Any());
3713 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003714 // We can handle 32 bit constants.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003715 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003716 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003717 }
3718 locations->SetOut(Location::SameAsFirstInput());
3719}
3720
3721void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3722 HandleBitwiseOperation(instruction);
3723}
3724
3725void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3726 HandleBitwiseOperation(instruction);
3727}
3728
3729void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3730 HandleBitwiseOperation(instruction);
3731}
3732
3733void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3734 LocationSummary* locations = instruction->GetLocations();
3735 Location first = locations->InAt(0);
3736 Location second = locations->InAt(1);
3737 DCHECK(first.Equals(locations->Out()));
3738
3739 if (instruction->GetResultType() == Primitive::kPrimInt) {
3740 if (second.IsRegister()) {
3741 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003742 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003743 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003744 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003745 } else {
3746 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003747 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003748 }
3749 } else if (second.IsConstant()) {
3750 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3751 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003752 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003753 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003754 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003755 } else {
3756 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003757 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003758 }
3759 } else {
3760 Address address(CpuRegister(RSP), second.GetStackIndex());
3761 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003762 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003763 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003764 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003765 } else {
3766 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003767 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003768 }
3769 }
3770 } else {
3771 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003772 CpuRegister first_reg = first.AsRegister<CpuRegister>();
3773 bool second_is_constant = false;
3774 int64_t value = 0;
3775 if (second.IsConstant()) {
3776 second_is_constant = true;
3777 value = second.GetConstant()->AsLongConstant()->GetValue();
3778 DCHECK(IsInt<32>(value));
3779 }
3780
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003781 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003782 if (second_is_constant) {
3783 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
3784 } else {
3785 __ andq(first_reg, second.AsRegister<CpuRegister>());
3786 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003787 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003788 if (second_is_constant) {
3789 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
3790 } else {
3791 __ orq(first_reg, second.AsRegister<CpuRegister>());
3792 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003793 } else {
3794 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003795 if (second_is_constant) {
3796 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
3797 } else {
3798 __ xorq(first_reg, second.AsRegister<CpuRegister>());
3799 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003800 }
3801 }
3802}
3803
Calin Juravleb1498f62015-02-16 13:13:29 +00003804void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
3805 // Nothing to do, this should be removed during prepare for register allocator.
3806 UNUSED(instruction);
3807 LOG(FATAL) << "Unreachable";
3808}
3809
3810void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
3811 // Nothing to do, this should be removed during prepare for register allocator.
3812 UNUSED(instruction);
3813 LOG(FATAL) << "Unreachable";
3814}
3815
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003816} // namespace x86_64
3817} // namespace art