blob: 0c4c0b3e5d443e203b65b01fcd81f3d2d9425d04 [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 Geoffray4597b5b2015-01-23 21:51:55 +000042static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000043static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010044
Mark Mendell24f2dfa2015-01-14 19:51:45 -050045static constexpr int kC2ConditionMask = 0x400;
46
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010047
Nicolas Geoffraye5038322014-07-04 09:41:32 +010048#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
49
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010050class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010051 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010052 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010053
Alexandre Rames2ed20af2015-03-06 13:55:35 +000054 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010055 __ Bind(GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010056 __ gs()->call(
57 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000058 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059 }
60
61 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010062 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
64};
65
Calin Juravled0d48522014-11-04 16:40:20 +000066class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
67 public:
68 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
69
Alexandre Rames2ed20af2015-03-06 13:55:35 +000070 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000071 __ Bind(GetEntryLabel());
72 __ gs()->call(
73 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000074 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Calin Juravled0d48522014-11-04 16:40:20 +000075 }
76
77 private:
78 HDivZeroCheck* const instruction_;
79 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
80};
81
Calin Juravlebacfec32014-11-14 15:54:36 +000082class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +000083 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000084 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
85 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000086
Alexandre Rames2ed20af2015-03-06 13:55:35 +000087 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000088 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +000089 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +000090 if (is_div_) {
91 __ negl(cpu_reg_);
92 } else {
93 __ movl(cpu_reg_, Immediate(0));
94 }
95
Calin Juravled6fb6cf2014-11-11 19:07:44 +000096 } else {
97 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +000098 if (is_div_) {
99 __ negq(cpu_reg_);
100 } else {
101 __ movq(cpu_reg_, Immediate(0));
102 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000103 }
Calin Juravled0d48522014-11-04 16:40:20 +0000104 __ jmp(GetExitLabel());
105 }
106
107 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000108 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000109 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000110 const bool is_div_;
111 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000112};
113
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100114class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000115 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100116 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
117 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000119 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100120 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000122 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000123 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000124 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
125 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100126 if (successor_ == nullptr) {
127 __ jmp(GetReturnLabel());
128 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100129 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100130 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000131 }
132
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 Label* GetReturnLabel() {
134 DCHECK(successor_ == nullptr);
135 return &return_label_;
136 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137
138 private:
139 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100140 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000141 Label return_label_;
142
143 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
144};
145
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100146class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100147 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100148 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
149 Location index_location,
150 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 : instruction_(instruction),
152 index_location_(index_location),
153 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100154
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000155 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000157 // We're moving two locations to locations that could overlap, so we need a parallel
158 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000160 codegen->EmitParallelMoves(
161 index_location_,
162 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
163 length_location_,
164 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100165 __ gs()->call(Address::Absolute(
166 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000167 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100168 }
169
170 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100171 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100172 const Location index_location_;
173 const Location length_location_;
174
175 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
176};
177
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000178class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100179 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000180 LoadClassSlowPathX86_64(HLoadClass* cls,
181 HInstruction* at,
182 uint32_t dex_pc,
183 bool do_clinit)
184 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
185 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
186 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100187
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000188 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000189 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
191 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100192
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000193 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000194
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100195 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000196 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100197 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000198 __ gs()->call(Address::Absolute((do_clinit_
199 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
200 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000201 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100202
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000203 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000205 if (out.IsValid()) {
206 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
207 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 }
209
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000210 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100211 __ jmp(GetExitLabel());
212 }
213
214 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 // The class this slow path will load.
216 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100217
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000218 // The instruction where this slow path is happening.
219 // (Might be the load class or an initialization check).
220 HInstruction* const at_;
221
222 // The dex PC of `at_`.
223 const uint32_t dex_pc_;
224
225 // Whether to initialize the class.
226 const bool do_clinit_;
227
228 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100229};
230
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000231class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
232 public:
233 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
234
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000235 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000236 LocationSummary* locations = instruction_->GetLocations();
237 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
238
239 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
240 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000241 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000242
243 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800244 x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
245 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000246 Immediate(instruction_->GetStringIndex()));
247 __ gs()->call(Address::Absolute(
248 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000249 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000250 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000251 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000252 __ jmp(GetExitLabel());
253 }
254
255 private:
256 HLoadString* const instruction_;
257
258 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
259};
260
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000261class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
262 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000263 TypeCheckSlowPathX86_64(HInstruction* instruction,
264 Location class_to_check,
265 Location object_class,
266 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000267 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000268 class_to_check_(class_to_check),
269 object_class_(object_class),
270 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000271
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000272 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000273 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000274 DCHECK(instruction_->IsCheckCast()
275 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276
277 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
278 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000279 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280
281 // We're moving two locations to locations that could overlap, so we need a parallel
282 // move resolver.
283 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000284 codegen->EmitParallelMoves(
285 class_to_check_,
286 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
287 object_class_,
288 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000289
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000290 if (instruction_->IsInstanceOf()) {
291 __ gs()->call(
292 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
293 } else {
294 DCHECK(instruction_->IsCheckCast());
295 __ gs()->call(
296 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
297 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000298 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000299
300 if (instruction_->IsInstanceOf()) {
301 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
302 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000303
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000304 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000305 __ jmp(GetExitLabel());
306 }
307
308 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000309 HInstruction* const instruction_;
310 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000311 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000312 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313
314 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
315};
316
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700317class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
318 public:
319 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
320 : instruction_(instruction) {}
321
322 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
323 __ Bind(GetEntryLabel());
324 SaveLiveRegisters(codegen, instruction_->GetLocations());
325 __ gs()->call(
326 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeoptimize), true));
327 DCHECK(instruction_->IsDeoptimize());
328 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
329 uint32_t dex_pc = deoptimize->GetDexPc();
330 codegen->RecordPcInfo(instruction_, dex_pc, this);
331 }
332
333 private:
334 HInstruction* const instruction_;
335 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
336};
337
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100338#undef __
339#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
340
Dave Allison20dfc792014-06-16 20:44:29 -0700341inline Condition X86_64Condition(IfCondition cond) {
342 switch (cond) {
343 case kCondEQ: return kEqual;
344 case kCondNE: return kNotEqual;
345 case kCondLT: return kLess;
346 case kCondLE: return kLessEqual;
347 case kCondGT: return kGreater;
348 case kCondGE: return kGreaterEqual;
349 default:
350 LOG(FATAL) << "Unknown if condition";
351 }
352 return kEqual;
353}
354
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800355void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
356 CpuRegister temp) {
357 // All registers are assumed to be correctly set up.
358
359 // TODO: Implement all kinds of calls:
360 // 1) boot -> boot
361 // 2) app -> boot
362 // 3) app -> app
363 //
364 // Currently we implement the app -> app logic, which looks up in the resolve cache.
365
366 // temp = method;
367 LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000368 if (!invoke->IsRecursive()) {
369 // temp = temp->dex_cache_resolved_methods_;
370 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
371 // temp = temp[index_in_cache]
372 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
373 // (temp + offset_of_quick_compiled_code)()
374 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
375 kX86_64WordSize).SizeValue()));
376 } else {
377 __ call(&frame_entry_label_);
378 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800379
380 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800381}
382
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100383void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
384 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
385}
386
387void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
388 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
389}
390
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100391size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
392 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
393 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100394}
395
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100396size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
397 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
398 return kX86_64WordSize;
399}
400
401size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
402 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
403 return kX86_64WordSize;
404}
405
406size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
407 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
408 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100409}
410
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000411static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000412// Use a fake return address register to mimic Quick.
413static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000414CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000415 : CodeGenerator(graph,
416 kNumberOfCpuRegisters,
417 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000418 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000419 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
420 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000421 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000422 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
423 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000424 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100425 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000427 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000428 move_resolver_(graph->GetArena(), this) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000429 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
430}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100431
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100432InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
433 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100434 : HGraphVisitor(graph),
435 assembler_(codegen->GetAssembler()),
436 codegen_(codegen) {}
437
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100438Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100439 switch (type) {
440 case Primitive::kPrimLong:
441 case Primitive::kPrimByte:
442 case Primitive::kPrimBoolean:
443 case Primitive::kPrimChar:
444 case Primitive::kPrimShort:
445 case Primitive::kPrimInt:
446 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100447 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100448 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100449 }
450
451 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100452 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100453 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100454 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100455 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100456
457 case Primitive::kPrimVoid:
458 LOG(FATAL) << "Unreachable type " << type;
459 }
460
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100461 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100462}
463
Nicolas Geoffray98893962015-01-21 12:32:32 +0000464void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100465 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100466 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100467
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000468 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100469 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000470
Nicolas Geoffray98893962015-01-21 12:32:32 +0000471 if (is_baseline) {
472 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
473 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
474 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000475 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
476 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
477 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000478 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100479}
480
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100481void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000482 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100483 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700484 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000485 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100486
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000487 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100488 __ testq(CpuRegister(RAX), Address(
489 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100490 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100491 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000492
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000493 if (HasEmptyFrame()) {
494 return;
495 }
496
Nicolas Geoffray98893962015-01-21 12:32:32 +0000497 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000498 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000499 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000500 __ pushq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000501 }
502 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100503
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000504 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
505 uint32_t xmm_spill_location = GetFpuSpillStart();
506 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100507
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000508 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
509 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
510 __ movsd(Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)),
511 XmmRegister(kFpuCalleeSaves[i]));
512 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100513 }
514
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100515 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
516}
517
518void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000519 if (HasEmptyFrame()) {
520 return;
521 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000522 uint32_t xmm_spill_location = GetFpuSpillStart();
523 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
524 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
525 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
526 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
527 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
528 }
529 }
530
531 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000532
533 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000534 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000535 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000536 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000537 }
538 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100539}
540
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100541void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
542 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100543}
544
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100545void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000546 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100547 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
548}
549
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100550Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
551 switch (load->GetType()) {
552 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100553 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100554 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
555 break;
556
557 case Primitive::kPrimInt:
558 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100559 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100560 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100561
562 case Primitive::kPrimBoolean:
563 case Primitive::kPrimByte:
564 case Primitive::kPrimChar:
565 case Primitive::kPrimShort:
566 case Primitive::kPrimVoid:
567 LOG(FATAL) << "Unexpected type " << load->GetType();
568 }
569
570 LOG(FATAL) << "Unreachable";
571 return Location();
572}
573
574void CodeGeneratorX86_64::Move(Location destination, Location source) {
575 if (source.Equals(destination)) {
576 return;
577 }
578 if (destination.IsRegister()) {
579 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000580 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100581 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000582 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100583 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000584 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100585 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586 } else {
587 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000588 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100589 Address(CpuRegister(RSP), source.GetStackIndex()));
590 }
591 } else if (destination.IsFpuRegister()) {
592 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000593 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000595 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100596 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000597 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100598 Address(CpuRegister(RSP), source.GetStackIndex()));
599 } else {
600 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000601 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100602 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100603 }
604 } else if (destination.IsStackSlot()) {
605 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100606 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000607 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100608 } else if (source.IsFpuRegister()) {
609 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000610 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500611 } else if (source.IsConstant()) {
612 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000613 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500614 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500616 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000617 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
618 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100619 }
620 } else {
621 DCHECK(destination.IsDoubleStackSlot());
622 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100623 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000624 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100625 } else if (source.IsFpuRegister()) {
626 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000627 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500628 } else if (source.IsConstant()) {
629 HConstant* constant = source.GetConstant();
630 int64_t value = constant->AsLongConstant()->GetValue();
631 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000632 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500633 } else {
634 DCHECK(constant->IsLongConstant());
635 value = constant->AsLongConstant()->GetValue();
636 }
637 __ movq(CpuRegister(TMP), Immediate(value));
638 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100639 } else {
640 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000641 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
642 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100643 }
644 }
645}
646
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100647void CodeGeneratorX86_64::Move(HInstruction* instruction,
648 Location location,
649 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000650 LocationSummary* locations = instruction->GetLocations();
651 if (locations != nullptr && locations->Out().Equals(location)) {
652 return;
653 }
654
655 if (locations != nullptr && locations->Out().IsConstant()) {
656 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000657 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
658 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000659 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000660 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000661 } else if (location.IsStackSlot()) {
662 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
663 } else {
664 DCHECK(location.IsConstant());
665 DCHECK_EQ(location.GetConstant(), const_to_move);
666 }
667 } else if (const_to_move->IsLongConstant()) {
668 int64_t value = const_to_move->AsLongConstant()->GetValue();
669 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000670 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000671 } else if (location.IsDoubleStackSlot()) {
672 __ movq(CpuRegister(TMP), Immediate(value));
673 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
674 } else {
675 DCHECK(location.IsConstant());
676 DCHECK_EQ(location.GetConstant(), const_to_move);
677 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100678 }
Roland Levillain476df552014-10-09 17:51:36 +0100679 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100680 switch (instruction->GetType()) {
681 case Primitive::kPrimBoolean:
682 case Primitive::kPrimByte:
683 case Primitive::kPrimChar:
684 case Primitive::kPrimShort:
685 case Primitive::kPrimInt:
686 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100687 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100688 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
689 break;
690
691 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100692 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000693 Move(location,
694 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100695 break;
696
697 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100698 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100699 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000700 } else if (instruction->IsTemporary()) {
701 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
702 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100703 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100704 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100705 switch (instruction->GetType()) {
706 case Primitive::kPrimBoolean:
707 case Primitive::kPrimByte:
708 case Primitive::kPrimChar:
709 case Primitive::kPrimShort:
710 case Primitive::kPrimInt:
711 case Primitive::kPrimNot:
712 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100713 case Primitive::kPrimFloat:
714 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000715 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100716 break;
717
718 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100719 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100720 }
721 }
722}
723
724void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
725 got->SetLocations(nullptr);
726}
727
728void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
729 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100730 DCHECK(!successor->IsExitBlock());
731
732 HBasicBlock* block = got->GetBlock();
733 HInstruction* previous = got->GetPrevious();
734
735 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000736 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100737 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
738 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
739 return;
740 }
741
742 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
743 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
744 }
745 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100746 __ jmp(codegen_->GetLabelOf(successor));
747 }
748}
749
750void LocationsBuilderX86_64::VisitExit(HExit* exit) {
751 exit->SetLocations(nullptr);
752}
753
754void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700755 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100756}
757
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700758void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
759 Label* true_target,
760 Label* false_target,
761 Label* always_true_target) {
762 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100763 if (cond->IsIntConstant()) {
764 // Constant condition, statically compared against 1.
765 int32_t cond_value = cond->AsIntConstant()->GetValue();
766 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700767 if (always_true_target != nullptr) {
768 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100769 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100770 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100771 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100772 DCHECK_EQ(cond_value, 0);
773 }
774 } else {
775 bool materialized =
776 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
777 // Moves do not affect the eflags register, so if the condition is
778 // evaluated just before the if, we don't need to evaluate it
779 // again.
780 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700781 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100782 if (materialized) {
783 if (!eflags_set) {
784 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700785 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100786 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000787 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100788 } else {
789 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
790 Immediate(0));
791 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700792 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100793 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700794 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100795 }
796 } else {
797 Location lhs = cond->GetLocations()->InAt(0);
798 Location rhs = cond->GetLocations()->InAt(1);
799 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000800 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100801 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000802 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000803 if (constant == 0) {
804 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
805 } else {
806 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
807 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100808 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000809 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100810 Address(CpuRegister(RSP), rhs.GetStackIndex()));
811 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700812 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700813 }
Dave Allison20dfc792014-06-16 20:44:29 -0700814 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700815 if (false_target != nullptr) {
816 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100817 }
818}
819
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700820void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
821 LocationSummary* locations =
822 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
823 HInstruction* cond = if_instr->InputAt(0);
824 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
825 locations->SetInAt(0, Location::Any());
826 }
827}
828
829void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
830 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
831 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
832 Label* always_true_target = true_target;
833 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
834 if_instr->IfTrueSuccessor())) {
835 always_true_target = nullptr;
836 }
837 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
838 if_instr->IfFalseSuccessor())) {
839 false_target = nullptr;
840 }
841 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
842}
843
844void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
845 LocationSummary* locations = new (GetGraph()->GetArena())
846 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
847 HInstruction* cond = deoptimize->InputAt(0);
848 DCHECK(cond->IsCondition());
849 if (cond->AsCondition()->NeedsMaterialization()) {
850 locations->SetInAt(0, Location::Any());
851 }
852}
853
854void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
855 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
856 DeoptimizationSlowPathX86_64(deoptimize);
857 codegen_->AddSlowPath(slow_path);
858 Label* slow_path_entry = slow_path->GetEntryLabel();
859 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
860}
861
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100862void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
863 local->SetLocations(nullptr);
864}
865
866void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
867 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
868}
869
870void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
871 local->SetLocations(nullptr);
872}
873
874void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
875 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700876 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100877}
878
879void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100880 LocationSummary* locations =
881 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100882 switch (store->InputAt(1)->GetType()) {
883 case Primitive::kPrimBoolean:
884 case Primitive::kPrimByte:
885 case Primitive::kPrimChar:
886 case Primitive::kPrimShort:
887 case Primitive::kPrimInt:
888 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100889 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100890 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
891 break;
892
893 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100894 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100895 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
896 break;
897
898 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100899 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100900 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100901}
902
903void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700904 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100905}
906
Dave Allison20dfc792014-06-16 20:44:29 -0700907void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100908 LocationSummary* locations =
909 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100910 locations->SetInAt(0, Location::RequiresRegister());
911 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100912 if (comp->NeedsMaterialization()) {
913 locations->SetOut(Location::RequiresRegister());
914 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100915}
916
Dave Allison20dfc792014-06-16 20:44:29 -0700917void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
918 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100919 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000920 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100921 // Clear register: setcc only sets the low byte.
922 __ xorq(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000923 Location lhs = locations->InAt(0);
924 Location rhs = locations->InAt(1);
925 if (rhs.IsRegister()) {
926 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
927 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800928 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000929 if (constant == 0) {
930 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
931 } else {
932 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
933 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100934 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000935 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100936 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100937 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700938 }
939}
940
941void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
942 VisitCondition(comp);
943}
944
945void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
946 VisitCondition(comp);
947}
948
949void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
950 VisitCondition(comp);
951}
952
953void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
954 VisitCondition(comp);
955}
956
957void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
958 VisitCondition(comp);
959}
960
961void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
962 VisitCondition(comp);
963}
964
965void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
966 VisitCondition(comp);
967}
968
969void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
970 VisitCondition(comp);
971}
972
973void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
974 VisitCondition(comp);
975}
976
977void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
978 VisitCondition(comp);
979}
980
981void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
982 VisitCondition(comp);
983}
984
985void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
986 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100987}
988
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100989void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100990 LocationSummary* locations =
991 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000992 switch (compare->InputAt(0)->GetType()) {
993 case Primitive::kPrimLong: {
994 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400995 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +0000996 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
997 break;
998 }
999 case Primitive::kPrimFloat:
1000 case Primitive::kPrimDouble: {
1001 locations->SetInAt(0, Location::RequiresFpuRegister());
1002 locations->SetInAt(1, Location::RequiresFpuRegister());
1003 locations->SetOut(Location::RequiresRegister());
1004 break;
1005 }
1006 default:
1007 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1008 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001009}
1010
1011void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001012 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001013 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001014 Location left = locations->InAt(0);
1015 Location right = locations->InAt(1);
1016
1017 Label less, greater, done;
1018 Primitive::Type type = compare->InputAt(0)->GetType();
1019 switch (type) {
1020 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001021 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1022 if (right.IsConstant()) {
1023 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1024 DCHECK(IsInt<32>(value));
1025 if (value == 0) {
1026 __ testq(left_reg, left_reg);
1027 } else {
1028 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1029 }
1030 } else {
1031 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1032 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001033 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001034 }
1035 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001036 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001037 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1038 break;
1039 }
1040 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001041 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001042 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1043 break;
1044 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001045 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001046 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001047 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001048 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001049 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001050 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001051
Calin Juravle91debbc2014-11-26 19:01:09 +00001052 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001053 __ movl(out, Immediate(1));
1054 __ jmp(&done);
1055
1056 __ Bind(&less);
1057 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001058
1059 __ Bind(&done);
1060}
1061
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001062void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001063 LocationSummary* locations =
1064 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001065 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001066}
1067
1068void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001069 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001070 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001071}
1072
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001073void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1074 LocationSummary* locations =
1075 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1076 locations->SetOut(Location::ConstantLocation(constant));
1077}
1078
1079void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1080 // Will be generated at use site.
1081 UNUSED(constant);
1082}
1083
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001084void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001085 LocationSummary* locations =
1086 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001087 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001088}
1089
1090void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001091 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001092 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001093}
1094
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001095void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1096 LocationSummary* locations =
1097 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1098 locations->SetOut(Location::ConstantLocation(constant));
1099}
1100
1101void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1102 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001103 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001104}
1105
1106void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1107 LocationSummary* locations =
1108 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1109 locations->SetOut(Location::ConstantLocation(constant));
1110}
1111
1112void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1113 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001114 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001115}
1116
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001117void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1118 ret->SetLocations(nullptr);
1119}
1120
1121void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001122 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001123 codegen_->GenerateFrameExit();
1124 __ ret();
1125}
1126
1127void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001128 LocationSummary* locations =
1129 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001130 switch (ret->InputAt(0)->GetType()) {
1131 case Primitive::kPrimBoolean:
1132 case Primitive::kPrimByte:
1133 case Primitive::kPrimChar:
1134 case Primitive::kPrimShort:
1135 case Primitive::kPrimInt:
1136 case Primitive::kPrimNot:
1137 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001138 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001139 break;
1140
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001141 case Primitive::kPrimFloat:
1142 case Primitive::kPrimDouble:
1143 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001144 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001145 break;
1146
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001147 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001148 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001149 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001150}
1151
1152void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1153 if (kIsDebugBuild) {
1154 switch (ret->InputAt(0)->GetType()) {
1155 case Primitive::kPrimBoolean:
1156 case Primitive::kPrimByte:
1157 case Primitive::kPrimChar:
1158 case Primitive::kPrimShort:
1159 case Primitive::kPrimInt:
1160 case Primitive::kPrimNot:
1161 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001162 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001163 break;
1164
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001165 case Primitive::kPrimFloat:
1166 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001167 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001168 XMM0);
1169 break;
1170
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001171 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001172 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001173 }
1174 }
1175 codegen_->GenerateFrameExit();
1176 __ ret();
1177}
1178
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001179Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1180 switch (type) {
1181 case Primitive::kPrimBoolean:
1182 case Primitive::kPrimByte:
1183 case Primitive::kPrimChar:
1184 case Primitive::kPrimShort:
1185 case Primitive::kPrimInt:
1186 case Primitive::kPrimNot: {
1187 uint32_t index = gp_index_++;
1188 stack_index_++;
1189 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001190 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001191 } else {
1192 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1193 }
1194 }
1195
1196 case Primitive::kPrimLong: {
1197 uint32_t index = gp_index_;
1198 stack_index_ += 2;
1199 if (index < calling_convention.GetNumberOfRegisters()) {
1200 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001201 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001202 } else {
1203 gp_index_ += 2;
1204 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1205 }
1206 }
1207
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001208 case Primitive::kPrimFloat: {
1209 uint32_t index = fp_index_++;
1210 stack_index_++;
1211 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001212 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001213 } else {
1214 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1215 }
1216 }
1217
1218 case Primitive::kPrimDouble: {
1219 uint32_t index = fp_index_++;
1220 stack_index_ += 2;
1221 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001222 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001223 } else {
1224 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1225 }
1226 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001227
1228 case Primitive::kPrimVoid:
1229 LOG(FATAL) << "Unexpected parameter type " << type;
1230 break;
1231 }
1232 return Location();
1233}
1234
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001235void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001236 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1237 if (intrinsic.TryDispatch(invoke)) {
1238 return;
1239 }
1240
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001241 HandleInvoke(invoke);
1242}
1243
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001244static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1245 if (invoke->GetLocations()->Intrinsified()) {
1246 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1247 intrinsic.Dispatch(invoke);
1248 return true;
1249 }
1250 return false;
1251}
1252
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001253void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001254 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1255 return;
1256 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001257
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001258 codegen_->GenerateStaticOrDirectCall(
1259 invoke,
1260 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001261 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001262}
1263
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001264void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001265 LocationSummary* locations =
1266 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001267 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001268
1269 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001270 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001271 HInstruction* input = invoke->InputAt(i);
1272 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1273 }
1274
1275 switch (invoke->GetType()) {
1276 case Primitive::kPrimBoolean:
1277 case Primitive::kPrimByte:
1278 case Primitive::kPrimChar:
1279 case Primitive::kPrimShort:
1280 case Primitive::kPrimInt:
1281 case Primitive::kPrimNot:
1282 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001283 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001284 break;
1285
1286 case Primitive::kPrimVoid:
1287 break;
1288
1289 case Primitive::kPrimDouble:
1290 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001291 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001292 break;
1293 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001294}
1295
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001296void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001297 IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
1298 if (intrinsic.TryDispatch(invoke)) {
1299 return;
1300 }
1301
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001302 HandleInvoke(invoke);
1303}
1304
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001305void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001306 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1307 return;
1308 }
1309
Roland Levillain271ab9c2014-11-27 15:23:57 +00001310 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001311 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1312 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1313 LocationSummary* locations = invoke->GetLocations();
1314 Location receiver = locations->InAt(0);
1315 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1316 // temp = object->GetClass();
1317 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001318 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1319 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001320 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001321 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001322 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001323 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001324 // temp = temp->GetMethodAt(method_offset);
1325 __ movl(temp, Address(temp, method_offset));
1326 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001327 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001328 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001329
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001330 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001331 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001332}
1333
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001334void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1335 HandleInvoke(invoke);
1336 // Add the hidden argument.
1337 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1338}
1339
1340void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1341 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001342 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001343 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1344 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1345 LocationSummary* locations = invoke->GetLocations();
1346 Location receiver = locations->InAt(0);
1347 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1348
1349 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001350 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001351 Immediate(invoke->GetDexMethodIndex()));
1352
1353 // temp = object->GetClass();
1354 if (receiver.IsStackSlot()) {
1355 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1356 __ movl(temp, Address(temp, class_offset));
1357 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001358 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001359 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001360 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001361 // temp = temp->GetImtEntryAt(method_offset);
1362 __ movl(temp, Address(temp, method_offset));
1363 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001364 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001365 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001366
1367 DCHECK(!codegen_->IsLeafMethod());
1368 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1369}
1370
Roland Levillain88cb1752014-10-20 16:36:47 +01001371void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1372 LocationSummary* locations =
1373 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1374 switch (neg->GetResultType()) {
1375 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001376 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001377 locations->SetInAt(0, Location::RequiresRegister());
1378 locations->SetOut(Location::SameAsFirstInput());
1379 break;
1380
Roland Levillain88cb1752014-10-20 16:36:47 +01001381 case Primitive::kPrimFloat:
1382 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001383 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001384 locations->SetOut(Location::SameAsFirstInput());
1385 locations->AddTemp(Location::RequiresRegister());
1386 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001387 break;
1388
1389 default:
1390 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1391 }
1392}
1393
1394void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1395 LocationSummary* locations = neg->GetLocations();
1396 Location out = locations->Out();
1397 Location in = locations->InAt(0);
1398 switch (neg->GetResultType()) {
1399 case Primitive::kPrimInt:
1400 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001401 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001402 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001403 break;
1404
1405 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001406 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001407 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001408 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001409 break;
1410
Roland Levillain5368c212014-11-27 15:03:41 +00001411 case Primitive::kPrimFloat: {
1412 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001413 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1414 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001415 // Implement float negation with an exclusive or with value
1416 // 0x80000000 (mask for bit 31, representing the sign of a
1417 // single-precision floating-point number).
1418 __ movq(constant, Immediate(INT64_C(0x80000000)));
1419 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001420 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001421 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001422 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001423
Roland Levillain5368c212014-11-27 15:03:41 +00001424 case Primitive::kPrimDouble: {
1425 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001426 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1427 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001428 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001429 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001430 // a double-precision floating-point number).
1431 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1432 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001433 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001434 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001435 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001436
1437 default:
1438 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1439 }
1440}
1441
Roland Levillaindff1f282014-11-05 14:15:05 +00001442void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1443 LocationSummary* locations =
1444 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1445 Primitive::Type result_type = conversion->GetResultType();
1446 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001447 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001448
David Brazdilb2bd1c52015-03-25 11:17:37 +00001449 // The Java language does not allow treating boolean as an integral type but
1450 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001451
Roland Levillaindff1f282014-11-05 14:15:05 +00001452 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001453 case Primitive::kPrimByte:
1454 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001455 case Primitive::kPrimBoolean:
1456 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001457 case Primitive::kPrimShort:
1458 case Primitive::kPrimInt:
1459 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001460 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001461 locations->SetInAt(0, Location::Any());
1462 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1463 break;
1464
1465 default:
1466 LOG(FATAL) << "Unexpected type conversion from " << input_type
1467 << " to " << result_type;
1468 }
1469 break;
1470
Roland Levillain01a8d712014-11-14 16:27:39 +00001471 case Primitive::kPrimShort:
1472 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001473 case Primitive::kPrimBoolean:
1474 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001475 case Primitive::kPrimByte:
1476 case Primitive::kPrimInt:
1477 case Primitive::kPrimChar:
1478 // Processing a Dex `int-to-short' instruction.
1479 locations->SetInAt(0, Location::Any());
1480 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1481 break;
1482
1483 default:
1484 LOG(FATAL) << "Unexpected type conversion from " << input_type
1485 << " to " << result_type;
1486 }
1487 break;
1488
Roland Levillain946e1432014-11-11 17:35:19 +00001489 case Primitive::kPrimInt:
1490 switch (input_type) {
1491 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001492 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001493 locations->SetInAt(0, Location::Any());
1494 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1495 break;
1496
1497 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001498 // Processing a Dex `float-to-int' instruction.
1499 locations->SetInAt(0, Location::RequiresFpuRegister());
1500 locations->SetOut(Location::RequiresRegister());
1501 locations->AddTemp(Location::RequiresFpuRegister());
1502 break;
1503
Roland Levillain946e1432014-11-11 17:35:19 +00001504 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001505 // Processing a Dex `double-to-int' instruction.
1506 locations->SetInAt(0, Location::RequiresFpuRegister());
1507 locations->SetOut(Location::RequiresRegister());
1508 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001509 break;
1510
1511 default:
1512 LOG(FATAL) << "Unexpected type conversion from " << input_type
1513 << " to " << result_type;
1514 }
1515 break;
1516
Roland Levillaindff1f282014-11-05 14:15:05 +00001517 case Primitive::kPrimLong:
1518 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001519 case Primitive::kPrimBoolean:
1520 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001521 case Primitive::kPrimByte:
1522 case Primitive::kPrimShort:
1523 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001524 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001525 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001526 // TODO: We would benefit from a (to-be-implemented)
1527 // Location::RegisterOrStackSlot requirement for this input.
1528 locations->SetInAt(0, Location::RequiresRegister());
1529 locations->SetOut(Location::RequiresRegister());
1530 break;
1531
1532 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001533 // Processing a Dex `float-to-long' instruction.
1534 locations->SetInAt(0, Location::RequiresFpuRegister());
1535 locations->SetOut(Location::RequiresRegister());
1536 locations->AddTemp(Location::RequiresFpuRegister());
1537 break;
1538
Roland Levillaindff1f282014-11-05 14:15:05 +00001539 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001540 // Processing a Dex `double-to-long' instruction.
1541 locations->SetInAt(0, Location::RequiresFpuRegister());
1542 locations->SetOut(Location::RequiresRegister());
1543 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001544 break;
1545
1546 default:
1547 LOG(FATAL) << "Unexpected type conversion from " << input_type
1548 << " to " << result_type;
1549 }
1550 break;
1551
Roland Levillain981e4542014-11-14 11:47:14 +00001552 case Primitive::kPrimChar:
1553 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001554 case Primitive::kPrimBoolean:
1555 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001556 case Primitive::kPrimByte:
1557 case Primitive::kPrimShort:
1558 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001559 // Processing a Dex `int-to-char' instruction.
1560 locations->SetInAt(0, Location::Any());
1561 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1562 break;
1563
1564 default:
1565 LOG(FATAL) << "Unexpected type conversion from " << input_type
1566 << " to " << result_type;
1567 }
1568 break;
1569
Roland Levillaindff1f282014-11-05 14:15:05 +00001570 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001571 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001572 case Primitive::kPrimBoolean:
1573 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001574 case Primitive::kPrimByte:
1575 case Primitive::kPrimShort:
1576 case Primitive::kPrimInt:
1577 case Primitive::kPrimChar:
1578 // Processing a Dex `int-to-float' instruction.
1579 locations->SetInAt(0, Location::RequiresRegister());
1580 locations->SetOut(Location::RequiresFpuRegister());
1581 break;
1582
1583 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001584 // Processing a Dex `long-to-float' instruction.
1585 locations->SetInAt(0, Location::RequiresRegister());
1586 locations->SetOut(Location::RequiresFpuRegister());
1587 break;
1588
Roland Levillaincff13742014-11-17 14:32:17 +00001589 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001590 // Processing a Dex `double-to-float' instruction.
1591 locations->SetInAt(0, Location::RequiresFpuRegister());
1592 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001593 break;
1594
1595 default:
1596 LOG(FATAL) << "Unexpected type conversion from " << input_type
1597 << " to " << result_type;
1598 };
1599 break;
1600
Roland Levillaindff1f282014-11-05 14:15:05 +00001601 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001602 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001603 case Primitive::kPrimBoolean:
1604 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001605 case Primitive::kPrimByte:
1606 case Primitive::kPrimShort:
1607 case Primitive::kPrimInt:
1608 case Primitive::kPrimChar:
1609 // Processing a Dex `int-to-double' instruction.
1610 locations->SetInAt(0, Location::RequiresRegister());
1611 locations->SetOut(Location::RequiresFpuRegister());
1612 break;
1613
1614 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001615 // Processing a Dex `long-to-double' instruction.
1616 locations->SetInAt(0, Location::RequiresRegister());
1617 locations->SetOut(Location::RequiresFpuRegister());
1618 break;
1619
Roland Levillaincff13742014-11-17 14:32:17 +00001620 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001621 // Processing a Dex `float-to-double' instruction.
1622 locations->SetInAt(0, Location::RequiresFpuRegister());
1623 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001624 break;
1625
1626 default:
1627 LOG(FATAL) << "Unexpected type conversion from " << input_type
1628 << " to " << result_type;
1629 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001630 break;
1631
1632 default:
1633 LOG(FATAL) << "Unexpected type conversion from " << input_type
1634 << " to " << result_type;
1635 }
1636}
1637
1638void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1639 LocationSummary* locations = conversion->GetLocations();
1640 Location out = locations->Out();
1641 Location in = locations->InAt(0);
1642 Primitive::Type result_type = conversion->GetResultType();
1643 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001644 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001645 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001646 case Primitive::kPrimByte:
1647 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001648 case Primitive::kPrimBoolean:
1649 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001650 case Primitive::kPrimShort:
1651 case Primitive::kPrimInt:
1652 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001653 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001654 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001655 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001656 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001657 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001658 Address(CpuRegister(RSP), in.GetStackIndex()));
1659 } else {
1660 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001661 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001662 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1663 }
1664 break;
1665
1666 default:
1667 LOG(FATAL) << "Unexpected type conversion from " << input_type
1668 << " to " << result_type;
1669 }
1670 break;
1671
Roland Levillain01a8d712014-11-14 16:27:39 +00001672 case Primitive::kPrimShort:
1673 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001674 case Primitive::kPrimBoolean:
1675 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001676 case Primitive::kPrimByte:
1677 case Primitive::kPrimInt:
1678 case Primitive::kPrimChar:
1679 // Processing a Dex `int-to-short' instruction.
1680 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001681 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001682 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001683 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001684 Address(CpuRegister(RSP), in.GetStackIndex()));
1685 } else {
1686 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001687 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001688 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1689 }
1690 break;
1691
1692 default:
1693 LOG(FATAL) << "Unexpected type conversion from " << input_type
1694 << " to " << result_type;
1695 }
1696 break;
1697
Roland Levillain946e1432014-11-11 17:35:19 +00001698 case Primitive::kPrimInt:
1699 switch (input_type) {
1700 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001701 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001702 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001703 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001704 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001705 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001706 Address(CpuRegister(RSP), in.GetStackIndex()));
1707 } else {
1708 DCHECK(in.IsConstant());
1709 DCHECK(in.GetConstant()->IsLongConstant());
1710 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001711 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001712 }
1713 break;
1714
Roland Levillain3f8f9362014-12-02 17:45:01 +00001715 case Primitive::kPrimFloat: {
1716 // Processing a Dex `float-to-int' instruction.
1717 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1718 CpuRegister output = out.AsRegister<CpuRegister>();
1719 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1720 Label done, nan;
1721
1722 __ movl(output, Immediate(kPrimIntMax));
1723 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001724 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001725 // if input >= temp goto done
1726 __ comiss(input, temp);
1727 __ j(kAboveEqual, &done);
1728 // if input == NaN goto nan
1729 __ j(kUnordered, &nan);
1730 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001731 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001732 __ jmp(&done);
1733 __ Bind(&nan);
1734 // output = 0
1735 __ xorl(output, output);
1736 __ Bind(&done);
1737 break;
1738 }
1739
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001740 case Primitive::kPrimDouble: {
1741 // Processing a Dex `double-to-int' instruction.
1742 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1743 CpuRegister output = out.AsRegister<CpuRegister>();
1744 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1745 Label done, nan;
1746
1747 __ movl(output, Immediate(kPrimIntMax));
1748 // temp = int-to-double(output)
1749 __ cvtsi2sd(temp, output);
1750 // if input >= temp goto done
1751 __ comisd(input, temp);
1752 __ j(kAboveEqual, &done);
1753 // if input == NaN goto nan
1754 __ j(kUnordered, &nan);
1755 // output = double-to-int-truncate(input)
1756 __ cvttsd2si(output, input);
1757 __ jmp(&done);
1758 __ Bind(&nan);
1759 // output = 0
1760 __ xorl(output, output);
1761 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001762 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001763 }
Roland Levillain946e1432014-11-11 17:35:19 +00001764
1765 default:
1766 LOG(FATAL) << "Unexpected type conversion from " << input_type
1767 << " to " << result_type;
1768 }
1769 break;
1770
Roland Levillaindff1f282014-11-05 14:15:05 +00001771 case Primitive::kPrimLong:
1772 switch (input_type) {
1773 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001774 case Primitive::kPrimBoolean:
1775 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001776 case Primitive::kPrimByte:
1777 case Primitive::kPrimShort:
1778 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001779 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001780 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001781 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001782 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001783 break;
1784
Roland Levillain624279f2014-12-04 11:54:28 +00001785 case Primitive::kPrimFloat: {
1786 // Processing a Dex `float-to-long' instruction.
1787 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1788 CpuRegister output = out.AsRegister<CpuRegister>();
1789 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1790 Label done, nan;
1791
1792 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001793 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001794 __ cvtsi2ss(temp, output, true);
1795 // if input >= temp goto done
1796 __ comiss(input, temp);
1797 __ j(kAboveEqual, &done);
1798 // if input == NaN goto nan
1799 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001800 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001801 __ cvttss2si(output, input, true);
1802 __ jmp(&done);
1803 __ Bind(&nan);
1804 // output = 0
1805 __ xorq(output, output);
1806 __ Bind(&done);
1807 break;
1808 }
1809
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001810 case Primitive::kPrimDouble: {
1811 // Processing a Dex `double-to-long' instruction.
1812 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1813 CpuRegister output = out.AsRegister<CpuRegister>();
1814 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1815 Label done, nan;
1816
1817 __ movq(output, Immediate(kPrimLongMax));
1818 // temp = long-to-double(output)
1819 __ cvtsi2sd(temp, output, true);
1820 // if input >= temp goto done
1821 __ comisd(input, temp);
1822 __ j(kAboveEqual, &done);
1823 // if input == NaN goto nan
1824 __ j(kUnordered, &nan);
1825 // output = double-to-long-truncate(input)
1826 __ cvttsd2si(output, input, true);
1827 __ jmp(&done);
1828 __ Bind(&nan);
1829 // output = 0
1830 __ xorq(output, output);
1831 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001832 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001833 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001834
1835 default:
1836 LOG(FATAL) << "Unexpected type conversion from " << input_type
1837 << " to " << result_type;
1838 }
1839 break;
1840
Roland Levillain981e4542014-11-14 11:47:14 +00001841 case Primitive::kPrimChar:
1842 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001843 case Primitive::kPrimBoolean:
1844 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001845 case Primitive::kPrimByte:
1846 case Primitive::kPrimShort:
1847 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001848 // Processing a Dex `int-to-char' instruction.
1849 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001850 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001851 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001852 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001853 Address(CpuRegister(RSP), in.GetStackIndex()));
1854 } else {
1855 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001856 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001857 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1858 }
1859 break;
1860
1861 default:
1862 LOG(FATAL) << "Unexpected type conversion from " << input_type
1863 << " to " << result_type;
1864 }
1865 break;
1866
Roland Levillaindff1f282014-11-05 14:15:05 +00001867 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001868 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001869 case Primitive::kPrimBoolean:
1870 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001871 case Primitive::kPrimByte:
1872 case Primitive::kPrimShort:
1873 case Primitive::kPrimInt:
1874 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001875 // Processing a Dex `int-to-float' instruction.
1876 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001877 break;
1878
1879 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001880 // Processing a Dex `long-to-float' instruction.
1881 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1882 break;
1883
Roland Levillaincff13742014-11-17 14:32:17 +00001884 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001885 // Processing a Dex `double-to-float' instruction.
1886 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001887 break;
1888
1889 default:
1890 LOG(FATAL) << "Unexpected type conversion from " << input_type
1891 << " to " << result_type;
1892 };
1893 break;
1894
Roland Levillaindff1f282014-11-05 14:15:05 +00001895 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001896 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001897 case Primitive::kPrimBoolean:
1898 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001899 case Primitive::kPrimByte:
1900 case Primitive::kPrimShort:
1901 case Primitive::kPrimInt:
1902 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001903 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001904 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001905 break;
1906
1907 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001908 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001909 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001910 break;
1911
Roland Levillaincff13742014-11-17 14:32:17 +00001912 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001913 // Processing a Dex `float-to-double' instruction.
1914 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001915 break;
1916
1917 default:
1918 LOG(FATAL) << "Unexpected type conversion from " << input_type
1919 << " to " << result_type;
1920 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001921 break;
1922
1923 default:
1924 LOG(FATAL) << "Unexpected type conversion from " << input_type
1925 << " to " << result_type;
1926 }
1927}
1928
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001929void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001930 LocationSummary* locations =
1931 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001932 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001933 case Primitive::kPrimInt: {
1934 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001935 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1936 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001937 break;
1938 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001939
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001940 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001941 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05001942 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001943 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05001944 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001945 break;
1946 }
1947
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001948 case Primitive::kPrimDouble:
1949 case Primitive::kPrimFloat: {
1950 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001951 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001952 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001953 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001954 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001955
1956 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001957 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001958 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001959}
1960
1961void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1962 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001963 Location first = locations->InAt(0);
1964 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001965 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01001966
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001967 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001968 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001969 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001970 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1971 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1972 } else {
1973 __ leal(out.AsRegister<CpuRegister>(), Address(
1974 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1975 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001976 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001977 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1978 __ addl(out.AsRegister<CpuRegister>(),
1979 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
1980 } else {
1981 __ leal(out.AsRegister<CpuRegister>(), Address(
1982 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
1983 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001984 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001985 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001986 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001987 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001988 break;
1989 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001990
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001991 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05001992 if (second.IsRegister()) {
1993 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1994 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1995 } else {
1996 __ leaq(out.AsRegister<CpuRegister>(), Address(
1997 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1998 }
1999 } else {
2000 DCHECK(second.IsConstant());
2001 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2002 int32_t int32_value = Low32Bits(value);
2003 DCHECK_EQ(int32_value, value);
2004 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2005 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2006 } else {
2007 __ leaq(out.AsRegister<CpuRegister>(), Address(
2008 first.AsRegister<CpuRegister>(), int32_value));
2009 }
2010 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002011 break;
2012 }
2013
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002014 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002015 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002016 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002017 }
2018
2019 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002020 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002021 break;
2022 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002023
2024 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002025 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002026 }
2027}
2028
2029void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002030 LocationSummary* locations =
2031 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002032 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002033 case Primitive::kPrimInt: {
2034 locations->SetInAt(0, Location::RequiresRegister());
2035 locations->SetInAt(1, Location::Any());
2036 locations->SetOut(Location::SameAsFirstInput());
2037 break;
2038 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002039 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002040 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002041 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002042 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002043 break;
2044 }
Calin Juravle11351682014-10-23 15:38:15 +01002045 case Primitive::kPrimFloat:
2046 case Primitive::kPrimDouble: {
2047 locations->SetInAt(0, Location::RequiresFpuRegister());
2048 locations->SetInAt(1, Location::RequiresFpuRegister());
2049 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002050 break;
Calin Juravle11351682014-10-23 15:38:15 +01002051 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002052 default:
Calin Juravle11351682014-10-23 15:38:15 +01002053 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002054 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002055}
2056
2057void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2058 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002059 Location first = locations->InAt(0);
2060 Location second = locations->InAt(1);
2061 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002062 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002063 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002064 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002065 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002066 } else if (second.IsConstant()) {
2067 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002068 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002069 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002070 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002071 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002072 break;
2073 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002074 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002075 if (second.IsConstant()) {
2076 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2077 DCHECK(IsInt<32>(value));
2078 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2079 } else {
2080 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2081 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002082 break;
2083 }
2084
Calin Juravle11351682014-10-23 15:38:15 +01002085 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002086 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002087 break;
Calin Juravle11351682014-10-23 15:38:15 +01002088 }
2089
2090 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002091 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002092 break;
2093 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002094
2095 default:
Calin Juravle11351682014-10-23 15:38:15 +01002096 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002097 }
2098}
2099
Calin Juravle34bacdf2014-10-07 20:23:36 +01002100void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2101 LocationSummary* locations =
2102 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2103 switch (mul->GetResultType()) {
2104 case Primitive::kPrimInt: {
2105 locations->SetInAt(0, Location::RequiresRegister());
2106 locations->SetInAt(1, Location::Any());
2107 locations->SetOut(Location::SameAsFirstInput());
2108 break;
2109 }
2110 case Primitive::kPrimLong: {
2111 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002112 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2113 if (locations->InAt(1).IsConstant()) {
2114 // Can use 3 operand multiply.
2115 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2116 } else {
2117 locations->SetOut(Location::SameAsFirstInput());
2118 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002119 break;
2120 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002121 case Primitive::kPrimFloat:
2122 case Primitive::kPrimDouble: {
2123 locations->SetInAt(0, Location::RequiresFpuRegister());
2124 locations->SetInAt(1, Location::RequiresFpuRegister());
2125 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002126 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002127 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002128
2129 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002130 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002131 }
2132}
2133
2134void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2135 LocationSummary* locations = mul->GetLocations();
2136 Location first = locations->InAt(0);
2137 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002138 switch (mul->GetResultType()) {
2139 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002140 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002141 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002142 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002143 } else if (second.IsConstant()) {
2144 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002145 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002146 } else {
2147 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002148 __ imull(first.AsRegister<CpuRegister>(),
2149 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002150 }
2151 break;
2152 }
2153 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002154 if (second.IsConstant()) {
2155 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2156 DCHECK(IsInt<32>(value));
2157 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2158 first.AsRegister<CpuRegister>(),
2159 Immediate(static_cast<int32_t>(value)));
2160 } else {
2161 DCHECK(first.Equals(locations->Out()));
2162 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2163 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002164 break;
2165 }
2166
Calin Juravleb5bfa962014-10-21 18:02:24 +01002167 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002168 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002169 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002170 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002171 }
2172
2173 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002174 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002175 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002176 break;
2177 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002178
2179 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002180 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002181 }
2182}
2183
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002184void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2185 uint32_t stack_adjustment, bool is_float) {
2186 if (source.IsStackSlot()) {
2187 DCHECK(is_float);
2188 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2189 } else if (source.IsDoubleStackSlot()) {
2190 DCHECK(!is_float);
2191 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2192 } else {
2193 // Write the value to the temporary location on the stack and load to FP stack.
2194 if (is_float) {
2195 Location stack_temp = Location::StackSlot(temp_offset);
2196 codegen_->Move(stack_temp, source);
2197 __ flds(Address(CpuRegister(RSP), temp_offset));
2198 } else {
2199 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2200 codegen_->Move(stack_temp, source);
2201 __ fldl(Address(CpuRegister(RSP), temp_offset));
2202 }
2203 }
2204}
2205
2206void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2207 Primitive::Type type = rem->GetResultType();
2208 bool is_float = type == Primitive::kPrimFloat;
2209 size_t elem_size = Primitive::ComponentSize(type);
2210 LocationSummary* locations = rem->GetLocations();
2211 Location first = locations->InAt(0);
2212 Location second = locations->InAt(1);
2213 Location out = locations->Out();
2214
2215 // Create stack space for 2 elements.
2216 // TODO: enhance register allocator to ask for stack temporaries.
2217 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2218
2219 // Load the values to the FP stack in reverse order, using temporaries if needed.
2220 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2221 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2222
2223 // Loop doing FPREM until we stabilize.
2224 Label retry;
2225 __ Bind(&retry);
2226 __ fprem();
2227
2228 // Move FP status to AX.
2229 __ fstsw();
2230
2231 // And see if the argument reduction is complete. This is signaled by the
2232 // C2 FPU flag bit set to 0.
2233 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2234 __ j(kNotEqual, &retry);
2235
2236 // We have settled on the final value. Retrieve it into an XMM register.
2237 // Store FP top of stack to real stack.
2238 if (is_float) {
2239 __ fsts(Address(CpuRegister(RSP), 0));
2240 } else {
2241 __ fstl(Address(CpuRegister(RSP), 0));
2242 }
2243
2244 // Pop the 2 items from the FP stack.
2245 __ fucompp();
2246
2247 // Load the value from the stack into an XMM register.
2248 DCHECK(out.IsFpuRegister()) << out;
2249 if (is_float) {
2250 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2251 } else {
2252 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2253 }
2254
2255 // And remove the temporary stack space we allocated.
2256 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2257}
2258
Calin Juravlebacfec32014-11-14 15:54:36 +00002259void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2260 DCHECK(instruction->IsDiv() || instruction->IsRem());
2261 Primitive::Type type = instruction->GetResultType();
2262 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2263
2264 bool is_div = instruction->IsDiv();
2265 LocationSummary* locations = instruction->GetLocations();
2266
Roland Levillain271ab9c2014-11-27 15:23:57 +00002267 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2268 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002269
Roland Levillain271ab9c2014-11-27 15:23:57 +00002270 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002271 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2272
2273 SlowPathCodeX86_64* slow_path =
2274 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2275 out_reg.AsRegister(), type, is_div);
2276 codegen_->AddSlowPath(slow_path);
2277
2278 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2279 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2280 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002281 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002282 __ cmpl(second_reg, Immediate(-1));
2283 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002284 // edx:eax <- sign-extended of eax
2285 __ cdq();
2286 // eax = quotient, edx = remainder
2287 __ idivl(second_reg);
2288 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002289 __ cmpq(second_reg, Immediate(-1));
2290 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002291 // rdx:rax <- sign-extended of rax
2292 __ cqo();
2293 // rax = quotient, rdx = remainder
2294 __ idivq(second_reg);
2295 }
2296
2297 __ Bind(slow_path->GetExitLabel());
2298}
2299
Calin Juravle7c4954d2014-10-28 16:57:40 +00002300void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2301 LocationSummary* locations =
2302 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2303 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002304 case Primitive::kPrimInt:
2305 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002306 locations->SetInAt(0, Location::RegisterLocation(RAX));
2307 locations->SetInAt(1, Location::RequiresRegister());
2308 locations->SetOut(Location::SameAsFirstInput());
2309 // Intel uses edx:eax as the dividend.
2310 locations->AddTemp(Location::RegisterLocation(RDX));
2311 break;
2312 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002313
Calin Juravle7c4954d2014-10-28 16:57:40 +00002314 case Primitive::kPrimFloat:
2315 case Primitive::kPrimDouble: {
2316 locations->SetInAt(0, Location::RequiresFpuRegister());
2317 locations->SetInAt(1, Location::RequiresFpuRegister());
2318 locations->SetOut(Location::SameAsFirstInput());
2319 break;
2320 }
2321
2322 default:
2323 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2324 }
2325}
2326
2327void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2328 LocationSummary* locations = div->GetLocations();
2329 Location first = locations->InAt(0);
2330 Location second = locations->InAt(1);
2331 DCHECK(first.Equals(locations->Out()));
2332
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002333 Primitive::Type type = div->GetResultType();
2334 switch (type) {
2335 case Primitive::kPrimInt:
2336 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002337 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002338 break;
2339 }
2340
Calin Juravle7c4954d2014-10-28 16:57:40 +00002341 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002342 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002343 break;
2344 }
2345
2346 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002347 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002348 break;
2349 }
2350
2351 default:
2352 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2353 }
2354}
2355
Calin Juravlebacfec32014-11-14 15:54:36 +00002356void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002357 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002358 LocationSummary* locations =
2359 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002360
2361 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002362 case Primitive::kPrimInt:
2363 case Primitive::kPrimLong: {
2364 locations->SetInAt(0, Location::RegisterLocation(RAX));
2365 locations->SetInAt(1, Location::RequiresRegister());
2366 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2367 locations->SetOut(Location::RegisterLocation(RDX));
2368 break;
2369 }
2370
2371 case Primitive::kPrimFloat:
2372 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002373 locations->SetInAt(0, Location::Any());
2374 locations->SetInAt(1, Location::Any());
2375 locations->SetOut(Location::RequiresFpuRegister());
2376 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002377 break;
2378 }
2379
2380 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002381 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002382 }
2383}
2384
2385void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2386 Primitive::Type type = rem->GetResultType();
2387 switch (type) {
2388 case Primitive::kPrimInt:
2389 case Primitive::kPrimLong: {
2390 GenerateDivRemIntegral(rem);
2391 break;
2392 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002393 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002394 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002395 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002396 break;
2397 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002398 default:
2399 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2400 }
2401}
2402
Calin Juravled0d48522014-11-04 16:40:20 +00002403void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2404 LocationSummary* locations =
2405 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2406 locations->SetInAt(0, Location::Any());
2407 if (instruction->HasUses()) {
2408 locations->SetOut(Location::SameAsFirstInput());
2409 }
2410}
2411
2412void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2413 SlowPathCodeX86_64* slow_path =
2414 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2415 codegen_->AddSlowPath(slow_path);
2416
2417 LocationSummary* locations = instruction->GetLocations();
2418 Location value = locations->InAt(0);
2419
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002420 switch (instruction->GetType()) {
2421 case Primitive::kPrimInt: {
2422 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002423 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002424 __ j(kEqual, slow_path->GetEntryLabel());
2425 } else if (value.IsStackSlot()) {
2426 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2427 __ j(kEqual, slow_path->GetEntryLabel());
2428 } else {
2429 DCHECK(value.IsConstant()) << value;
2430 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2431 __ jmp(slow_path->GetEntryLabel());
2432 }
2433 }
2434 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002435 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002436 case Primitive::kPrimLong: {
2437 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002438 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002439 __ j(kEqual, slow_path->GetEntryLabel());
2440 } else if (value.IsDoubleStackSlot()) {
2441 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2442 __ j(kEqual, slow_path->GetEntryLabel());
2443 } else {
2444 DCHECK(value.IsConstant()) << value;
2445 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2446 __ jmp(slow_path->GetEntryLabel());
2447 }
2448 }
2449 break;
2450 }
2451 default:
2452 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002453 }
Calin Juravled0d48522014-11-04 16:40:20 +00002454}
2455
Calin Juravle9aec02f2014-11-18 23:06:35 +00002456void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2457 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2458
2459 LocationSummary* locations =
2460 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2461
2462 switch (op->GetResultType()) {
2463 case Primitive::kPrimInt:
2464 case Primitive::kPrimLong: {
2465 locations->SetInAt(0, Location::RequiresRegister());
2466 // The shift count needs to be in CL.
2467 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2468 locations->SetOut(Location::SameAsFirstInput());
2469 break;
2470 }
2471 default:
2472 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2473 }
2474}
2475
2476void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2477 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2478
2479 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002480 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002481 Location second = locations->InAt(1);
2482
2483 switch (op->GetResultType()) {
2484 case Primitive::kPrimInt: {
2485 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002486 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002487 if (op->IsShl()) {
2488 __ shll(first_reg, second_reg);
2489 } else if (op->IsShr()) {
2490 __ sarl(first_reg, second_reg);
2491 } else {
2492 __ shrl(first_reg, second_reg);
2493 }
2494 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002495 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002496 if (op->IsShl()) {
2497 __ shll(first_reg, imm);
2498 } else if (op->IsShr()) {
2499 __ sarl(first_reg, imm);
2500 } else {
2501 __ shrl(first_reg, imm);
2502 }
2503 }
2504 break;
2505 }
2506 case Primitive::kPrimLong: {
2507 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002508 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002509 if (op->IsShl()) {
2510 __ shlq(first_reg, second_reg);
2511 } else if (op->IsShr()) {
2512 __ sarq(first_reg, second_reg);
2513 } else {
2514 __ shrq(first_reg, second_reg);
2515 }
2516 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002517 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002518 if (op->IsShl()) {
2519 __ shlq(first_reg, imm);
2520 } else if (op->IsShr()) {
2521 __ sarq(first_reg, imm);
2522 } else {
2523 __ shrq(first_reg, imm);
2524 }
2525 }
2526 break;
2527 }
2528 default:
2529 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2530 }
2531}
2532
2533void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2534 HandleShift(shl);
2535}
2536
2537void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2538 HandleShift(shl);
2539}
2540
2541void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2542 HandleShift(shr);
2543}
2544
2545void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2546 HandleShift(shr);
2547}
2548
2549void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2550 HandleShift(ushr);
2551}
2552
2553void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2554 HandleShift(ushr);
2555}
2556
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002557void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002558 LocationSummary* locations =
2559 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002560 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002561 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2562 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2563 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002564}
2565
2566void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2567 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002568 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002569 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2570
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002571 __ gs()->call(
2572 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002573
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002574 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002575 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002576}
2577
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002578void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2579 LocationSummary* locations =
2580 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2581 InvokeRuntimeCallingConvention calling_convention;
2582 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002583 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002584 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002585 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002586}
2587
2588void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2589 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002590 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002591 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2592
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002593 __ gs()->call(
2594 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002595
2596 DCHECK(!codegen_->IsLeafMethod());
2597 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2598}
2599
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002600void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002601 LocationSummary* locations =
2602 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002603 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2604 if (location.IsStackSlot()) {
2605 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2606 } else if (location.IsDoubleStackSlot()) {
2607 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2608 }
2609 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002610}
2611
2612void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2613 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002614 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002615}
2616
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002617void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002618 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002619 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002620 locations->SetInAt(0, Location::RequiresRegister());
2621 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002622}
2623
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002624void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2625 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002626 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2627 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002628 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002629 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002630 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002631 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002632 break;
2633
2634 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002635 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002636 break;
2637
2638 default:
2639 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2640 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002641}
2642
2643void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002644 LocationSummary* locations =
2645 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002646 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2647 locations->SetInAt(i, Location::Any());
2648 }
2649 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002650}
2651
2652void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002653 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002654 LOG(FATAL) << "Unimplemented";
2655}
2656
Calin Juravle52c48962014-12-16 17:02:57 +00002657void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2658 /*
2659 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2660 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2661 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2662 */
2663 switch (kind) {
2664 case MemBarrierKind::kAnyAny: {
2665 __ mfence();
2666 break;
2667 }
2668 case MemBarrierKind::kAnyStore:
2669 case MemBarrierKind::kLoadAny:
2670 case MemBarrierKind::kStoreStore: {
2671 // nop
2672 break;
2673 }
2674 default:
2675 LOG(FATAL) << "Unexpected memory barier " << kind;
2676 }
2677}
2678
2679void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2680 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2681
Nicolas Geoffray39468442014-09-02 15:17:15 +01002682 LocationSummary* locations =
2683 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002684 locations->SetInAt(0, Location::RequiresRegister());
2685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2686}
2687
2688void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2689 const FieldInfo& field_info) {
2690 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2691
2692 LocationSummary* locations = instruction->GetLocations();
2693 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2694 Location out = locations->Out();
2695 bool is_volatile = field_info.IsVolatile();
2696 Primitive::Type field_type = field_info.GetFieldType();
2697 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2698
2699 switch (field_type) {
2700 case Primitive::kPrimBoolean: {
2701 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2702 break;
2703 }
2704
2705 case Primitive::kPrimByte: {
2706 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2707 break;
2708 }
2709
2710 case Primitive::kPrimShort: {
2711 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2712 break;
2713 }
2714
2715 case Primitive::kPrimChar: {
2716 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2717 break;
2718 }
2719
2720 case Primitive::kPrimInt:
2721 case Primitive::kPrimNot: {
2722 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2723 break;
2724 }
2725
2726 case Primitive::kPrimLong: {
2727 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2728 break;
2729 }
2730
2731 case Primitive::kPrimFloat: {
2732 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2733 break;
2734 }
2735
2736 case Primitive::kPrimDouble: {
2737 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2738 break;
2739 }
2740
2741 case Primitive::kPrimVoid:
2742 LOG(FATAL) << "Unreachable type " << field_type;
2743 UNREACHABLE();
2744 }
2745
Calin Juravle77520bc2015-01-12 18:45:46 +00002746 codegen_->MaybeRecordImplicitNullCheck(instruction);
2747
Calin Juravle52c48962014-12-16 17:02:57 +00002748 if (is_volatile) {
2749 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2750 }
2751}
2752
2753void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2754 const FieldInfo& field_info) {
2755 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2756
2757 LocationSummary* locations =
2758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002759 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002760 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2761
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002762 locations->SetInAt(0, Location::RequiresRegister());
2763 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002764 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002765 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002766 locations->AddTemp(Location::RequiresRegister());
2767 locations->AddTemp(Location::RequiresRegister());
2768 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002769}
2770
Calin Juravle52c48962014-12-16 17:02:57 +00002771void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2772 const FieldInfo& field_info) {
2773 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2774
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002775 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002776 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2777 Location value = locations->InAt(1);
2778 bool is_volatile = field_info.IsVolatile();
2779 Primitive::Type field_type = field_info.GetFieldType();
2780 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2781
2782 if (is_volatile) {
2783 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2784 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002785
2786 switch (field_type) {
2787 case Primitive::kPrimBoolean:
2788 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002789 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002790 break;
2791 }
2792
2793 case Primitive::kPrimShort:
2794 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002795 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002796 break;
2797 }
2798
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002799 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002800 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002801 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002802 break;
2803 }
2804
2805 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002806 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002807 break;
2808 }
2809
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002810 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002811 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002812 break;
2813 }
2814
2815 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002816 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002817 break;
2818 }
2819
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002820 case Primitive::kPrimVoid:
2821 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002822 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002823 }
Calin Juravle52c48962014-12-16 17:02:57 +00002824
Calin Juravle77520bc2015-01-12 18:45:46 +00002825 codegen_->MaybeRecordImplicitNullCheck(instruction);
2826
2827 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2828 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2829 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2830 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2831 }
2832
Calin Juravle52c48962014-12-16 17:02:57 +00002833 if (is_volatile) {
2834 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2835 }
2836}
2837
2838void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2839 HandleFieldSet(instruction, instruction->GetFieldInfo());
2840}
2841
2842void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2843 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002844}
2845
2846void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002847 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002848}
2849
2850void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002851 HandleFieldGet(instruction, instruction->GetFieldInfo());
2852}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002853
Calin Juravle52c48962014-12-16 17:02:57 +00002854void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2855 HandleFieldGet(instruction);
2856}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002857
Calin Juravle52c48962014-12-16 17:02:57 +00002858void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2859 HandleFieldGet(instruction, instruction->GetFieldInfo());
2860}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002861
Calin Juravle52c48962014-12-16 17:02:57 +00002862void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2863 HandleFieldSet(instruction, instruction->GetFieldInfo());
2864}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002865
Calin Juravle52c48962014-12-16 17:02:57 +00002866void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2867 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002868}
2869
2870void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002871 LocationSummary* locations =
2872 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002873 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2874 ? Location::RequiresRegister()
2875 : Location::Any();
2876 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002877 if (instruction->HasUses()) {
2878 locations->SetOut(Location::SameAsFirstInput());
2879 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002880}
2881
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002882void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002883 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2884 return;
2885 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002886 LocationSummary* locations = instruction->GetLocations();
2887 Location obj = locations->InAt(0);
2888
2889 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2890 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2891}
2892
2893void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002894 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002895 codegen_->AddSlowPath(slow_path);
2896
2897 LocationSummary* locations = instruction->GetLocations();
2898 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002899
2900 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002901 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002902 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002903 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002904 } else {
2905 DCHECK(obj.IsConstant()) << obj;
2906 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2907 __ jmp(slow_path->GetEntryLabel());
2908 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002909 }
2910 __ j(kEqual, slow_path->GetEntryLabel());
2911}
2912
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002913void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2914 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2915 GenerateImplicitNullCheck(instruction);
2916 } else {
2917 GenerateExplicitNullCheck(instruction);
2918 }
2919}
2920
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002921void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002922 LocationSummary* locations =
2923 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002924 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002925 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002926 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2927 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002928}
2929
2930void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2931 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002932 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002933 Location index = locations->InAt(1);
2934
2935 switch (instruction->GetType()) {
2936 case Primitive::kPrimBoolean: {
2937 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002938 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002939 if (index.IsConstant()) {
2940 __ movzxb(out, Address(obj,
2941 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2942 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002943 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002944 }
2945 break;
2946 }
2947
2948 case Primitive::kPrimByte: {
2949 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002950 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002951 if (index.IsConstant()) {
2952 __ movsxb(out, Address(obj,
2953 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2954 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002955 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002956 }
2957 break;
2958 }
2959
2960 case Primitive::kPrimShort: {
2961 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002962 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002963 if (index.IsConstant()) {
2964 __ movsxw(out, Address(obj,
2965 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2966 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002967 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002968 }
2969 break;
2970 }
2971
2972 case Primitive::kPrimChar: {
2973 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002974 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002975 if (index.IsConstant()) {
2976 __ movzxw(out, Address(obj,
2977 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2978 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002979 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002980 }
2981 break;
2982 }
2983
2984 case Primitive::kPrimInt:
2985 case Primitive::kPrimNot: {
2986 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2987 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002988 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002989 if (index.IsConstant()) {
2990 __ movl(out, Address(obj,
2991 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2992 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002993 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002994 }
2995 break;
2996 }
2997
2998 case Primitive::kPrimLong: {
2999 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003000 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003001 if (index.IsConstant()) {
3002 __ movq(out, Address(obj,
3003 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3004 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003005 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003006 }
3007 break;
3008 }
3009
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003010 case Primitive::kPrimFloat: {
3011 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003012 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003013 if (index.IsConstant()) {
3014 __ movss(out, Address(obj,
3015 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3016 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003017 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003018 }
3019 break;
3020 }
3021
3022 case Primitive::kPrimDouble: {
3023 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003024 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003025 if (index.IsConstant()) {
3026 __ movsd(out, Address(obj,
3027 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3028 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003029 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003030 }
3031 break;
3032 }
3033
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003034 case Primitive::kPrimVoid:
3035 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003036 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003037 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003038 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003039}
3040
3041void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003042 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003043
3044 bool needs_write_barrier =
3045 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3046 bool needs_runtime_call = instruction->NeedsTypeCheck();
3047
Nicolas Geoffray39468442014-09-02 15:17:15 +01003048 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003049 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3050 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003051 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003052 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3053 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3054 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003055 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003056 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003057 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003058 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3059 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003060 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003061 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003062 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3063 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003064 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003065 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003066 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003067
3068 if (needs_write_barrier) {
3069 // Temporary registers for the write barrier.
3070 locations->AddTemp(Location::RequiresRegister());
3071 locations->AddTemp(Location::RequiresRegister());
3072 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003073 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003074}
3075
3076void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3077 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003078 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003079 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003080 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003081 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003082 bool needs_runtime_call = locations->WillCall();
3083 bool needs_write_barrier =
3084 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003085
3086 switch (value_type) {
3087 case Primitive::kPrimBoolean:
3088 case Primitive::kPrimByte: {
3089 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003090 if (index.IsConstant()) {
3091 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003092 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003093 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003094 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003095 __ movb(Address(obj, offset),
3096 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003097 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003098 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003099 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003100 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3101 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003102 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003103 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003104 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3105 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003106 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003107 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003108 break;
3109 }
3110
3111 case Primitive::kPrimShort:
3112 case Primitive::kPrimChar: {
3113 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003114 if (index.IsConstant()) {
3115 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003116 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003117 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003118 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003119 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003120 __ movw(Address(obj, offset),
3121 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003122 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003123 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003124 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003125 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003126 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3127 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003128 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003129 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003130 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003131 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3132 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003133 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003134 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003135 break;
3136 }
3137
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003138 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003139 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003140 if (!needs_runtime_call) {
3141 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3142 if (index.IsConstant()) {
3143 size_t offset =
3144 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3145 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003146 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003147 } else {
3148 DCHECK(value.IsConstant()) << value;
3149 __ movl(Address(obj, offset),
3150 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3151 }
3152 } else {
3153 DCHECK(index.IsRegister()) << index;
3154 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003155 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3156 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003157 } else {
3158 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003159 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003160 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3161 }
3162 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003163 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003164 if (needs_write_barrier) {
3165 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003166 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3167 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3168 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003169 }
3170 } else {
3171 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003172 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3173 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003174 DCHECK(!codegen_->IsLeafMethod());
3175 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3176 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003177 break;
3178 }
3179
3180 case Primitive::kPrimLong: {
3181 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003182 if (index.IsConstant()) {
3183 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003184 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003185 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003186 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003187 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003188 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3189 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003190 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003191 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003192 break;
3193 }
3194
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003195 case Primitive::kPrimFloat: {
3196 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3197 if (index.IsConstant()) {
3198 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3199 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003200 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003201 } else {
3202 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003203 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3204 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003205 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003206 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003207 break;
3208 }
3209
3210 case Primitive::kPrimDouble: {
3211 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3212 if (index.IsConstant()) {
3213 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3214 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003215 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003216 } else {
3217 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003218 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3219 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003220 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003221 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003222 break;
3223 }
3224
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003225 case Primitive::kPrimVoid:
3226 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003227 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003228 }
3229}
3230
3231void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003232 LocationSummary* locations =
3233 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003234 locations->SetInAt(0, Location::RequiresRegister());
3235 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003236}
3237
3238void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3239 LocationSummary* locations = instruction->GetLocations();
3240 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003241 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3242 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003243 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003244 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003245}
3246
3247void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003248 LocationSummary* locations =
3249 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003250 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003251 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003252 if (instruction->HasUses()) {
3253 locations->SetOut(Location::SameAsFirstInput());
3254 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003255}
3256
3257void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3258 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003259 Location index_loc = locations->InAt(0);
3260 Location length_loc = locations->InAt(1);
3261 SlowPathCodeX86_64* slow_path =
3262 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003263 codegen_->AddSlowPath(slow_path);
3264
Mark Mendellf60c90b2015-03-04 15:12:59 -05003265 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3266 if (index_loc.IsConstant()) {
3267 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3268 __ cmpl(length, Immediate(value));
3269 } else {
3270 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3271 }
3272 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003273}
3274
3275void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3276 CpuRegister card,
3277 CpuRegister object,
3278 CpuRegister value) {
3279 Label is_null;
3280 __ testl(value, value);
3281 __ j(kEqual, &is_null);
3282 __ gs()->movq(card, Address::Absolute(
3283 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3284 __ movq(temp, object);
3285 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3286 __ movb(Address(temp, card, TIMES_1, 0), card);
3287 __ Bind(&is_null);
3288}
3289
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003290void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3291 temp->SetLocations(nullptr);
3292}
3293
3294void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3295 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003296 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003297}
3298
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003299void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003300 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003301 LOG(FATAL) << "Unimplemented";
3302}
3303
3304void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003305 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3306}
3307
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003308void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3309 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3310}
3311
3312void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003313 HBasicBlock* block = instruction->GetBlock();
3314 if (block->GetLoopInformation() != nullptr) {
3315 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3316 // The back edge will generate the suspend check.
3317 return;
3318 }
3319 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3320 // The goto will generate the suspend check.
3321 return;
3322 }
3323 GenerateSuspendCheck(instruction, nullptr);
3324}
3325
3326void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3327 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003328 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003329 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003330 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003331 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003332 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003333 if (successor == nullptr) {
3334 __ j(kNotEqual, slow_path->GetEntryLabel());
3335 __ Bind(slow_path->GetReturnLabel());
3336 } else {
3337 __ j(kEqual, codegen_->GetLabelOf(successor));
3338 __ jmp(slow_path->GetEntryLabel());
3339 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003340}
3341
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003342X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3343 return codegen_->GetAssembler();
3344}
3345
3346void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3347 MoveOperands* move = moves_.Get(index);
3348 Location source = move->GetSource();
3349 Location destination = move->GetDestination();
3350
3351 if (source.IsRegister()) {
3352 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003353 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003354 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003355 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003356 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003357 } else {
3358 DCHECK(destination.IsDoubleStackSlot());
3359 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003360 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003361 }
3362 } else if (source.IsStackSlot()) {
3363 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003364 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003365 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003366 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003367 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003368 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003369 } else {
3370 DCHECK(destination.IsStackSlot());
3371 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3372 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3373 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003374 } else if (source.IsDoubleStackSlot()) {
3375 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003376 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003377 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003378 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003379 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3380 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003381 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003382 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003383 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3384 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3385 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003386 } else if (source.IsConstant()) {
3387 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003388 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3389 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003390 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003391 if (value == 0) {
3392 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3393 } else {
3394 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3395 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003396 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003397 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003398 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003399 }
3400 } else if (constant->IsLongConstant()) {
3401 int64_t value = constant->AsLongConstant()->GetValue();
3402 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003403 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003404 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003405 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003406 __ movq(CpuRegister(TMP), Immediate(value));
3407 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3408 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003409 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003410 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003411 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003412 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003413 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003414 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3415 if (value == 0) {
3416 // easy FP 0.0.
3417 __ xorps(dest, dest);
3418 } else {
3419 __ movl(CpuRegister(TMP), imm);
3420 __ movd(dest, CpuRegister(TMP));
3421 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003422 } else {
3423 DCHECK(destination.IsStackSlot()) << destination;
3424 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3425 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003426 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003427 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003428 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003429 int64_t value = bit_cast<int64_t, double>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003430 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003431 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003432 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3433 if (value == 0) {
3434 __ xorpd(dest, dest);
3435 } else {
3436 __ movq(CpuRegister(TMP), imm);
3437 __ movd(dest, CpuRegister(TMP));
3438 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003439 } else {
3440 DCHECK(destination.IsDoubleStackSlot()) << destination;
3441 __ movq(CpuRegister(TMP), imm);
3442 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3443 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003444 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003445 } else if (source.IsFpuRegister()) {
3446 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003447 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003448 } else if (destination.IsStackSlot()) {
3449 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003450 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003451 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003452 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003453 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003454 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003455 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003456 }
3457}
3458
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003459void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003460 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003461 __ movl(Address(CpuRegister(RSP), mem), reg);
3462 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003463}
3464
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003465void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003466 ScratchRegisterScope ensure_scratch(
3467 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3468
3469 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3470 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3471 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3472 Address(CpuRegister(RSP), mem2 + stack_offset));
3473 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3474 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3475 CpuRegister(ensure_scratch.GetRegister()));
3476}
3477
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003478void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3479 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3480 __ movq(Address(CpuRegister(RSP), mem), reg);
3481 __ movq(reg, CpuRegister(TMP));
3482}
3483
3484void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3485 ScratchRegisterScope ensure_scratch(
3486 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3487
3488 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3489 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3490 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3491 Address(CpuRegister(RSP), mem2 + stack_offset));
3492 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3493 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3494 CpuRegister(ensure_scratch.GetRegister()));
3495}
3496
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003497void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3498 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3499 __ movss(Address(CpuRegister(RSP), mem), reg);
3500 __ movd(reg, CpuRegister(TMP));
3501}
3502
3503void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3504 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3505 __ movsd(Address(CpuRegister(RSP), mem), reg);
3506 __ movd(reg, CpuRegister(TMP));
3507}
3508
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003509void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3510 MoveOperands* move = moves_.Get(index);
3511 Location source = move->GetSource();
3512 Location destination = move->GetDestination();
3513
3514 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003515 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003516 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003517 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003518 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003519 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003520 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003521 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3522 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003523 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003524 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003525 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003526 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3527 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003528 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003529 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3530 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3531 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003532 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003533 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003534 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003535 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003536 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003537 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003538 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003539 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003540 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003541 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003542 }
3543}
3544
3545
3546void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3547 __ pushq(CpuRegister(reg));
3548}
3549
3550
3551void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3552 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003553}
3554
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003555void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3556 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3557 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3558 Immediate(mirror::Class::kStatusInitialized));
3559 __ j(kLess, slow_path->GetEntryLabel());
3560 __ Bind(slow_path->GetExitLabel());
3561 // No need for memory fence, thanks to the X86_64 memory model.
3562}
3563
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003564void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003565 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3566 ? LocationSummary::kCallOnSlowPath
3567 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003568 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003569 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003570 locations->SetOut(Location::RequiresRegister());
3571}
3572
3573void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003574 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003575 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003576 DCHECK(!cls->CanCallRuntime());
3577 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003578 codegen_->LoadCurrentMethod(out);
3579 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3580 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003581 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003582 codegen_->LoadCurrentMethod(out);
3583 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3584 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003585 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3586 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3587 codegen_->AddSlowPath(slow_path);
3588 __ testl(out, out);
3589 __ j(kEqual, slow_path->GetEntryLabel());
3590 if (cls->MustGenerateClinitCheck()) {
3591 GenerateClassInitializationCheck(slow_path, out);
3592 } else {
3593 __ Bind(slow_path->GetExitLabel());
3594 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003595 }
3596}
3597
3598void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3599 LocationSummary* locations =
3600 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3601 locations->SetInAt(0, Location::RequiresRegister());
3602 if (check->HasUses()) {
3603 locations->SetOut(Location::SameAsFirstInput());
3604 }
3605}
3606
3607void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003608 // We assume the class to not be null.
3609 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3610 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003611 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003612 GenerateClassInitializationCheck(slow_path,
3613 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003614}
3615
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003616void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3617 LocationSummary* locations =
3618 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3619 locations->SetOut(Location::RequiresRegister());
3620}
3621
3622void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3623 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3624 codegen_->AddSlowPath(slow_path);
3625
Roland Levillain271ab9c2014-11-27 15:23:57 +00003626 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003627 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003628 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3629 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003630 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3631 __ testl(out, out);
3632 __ j(kEqual, slow_path->GetEntryLabel());
3633 __ Bind(slow_path->GetExitLabel());
3634}
3635
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003636void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3637 LocationSummary* locations =
3638 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3639 locations->SetOut(Location::RequiresRegister());
3640}
3641
3642void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3643 Address address = Address::Absolute(
3644 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003645 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003646 __ gs()->movl(address, Immediate(0));
3647}
3648
3649void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
3650 LocationSummary* locations =
3651 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3652 InvokeRuntimeCallingConvention calling_convention;
3653 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3654}
3655
3656void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
3657 __ gs()->call(
3658 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3659 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3660}
3661
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003662void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003663 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3664 ? LocationSummary::kNoCall
3665 : LocationSummary::kCallOnSlowPath;
3666 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3667 locations->SetInAt(0, Location::RequiresRegister());
3668 locations->SetInAt(1, Location::Any());
3669 locations->SetOut(Location::RequiresRegister());
3670}
3671
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003672void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003673 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003674 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003675 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003676 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003677 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3678 Label done, zero;
3679 SlowPathCodeX86_64* slow_path = nullptr;
3680
3681 // Return 0 if `obj` is null.
3682 // TODO: avoid this check if we know obj is not null.
3683 __ testl(obj, obj);
3684 __ j(kEqual, &zero);
3685 // Compare the class of `obj` with `cls`.
3686 __ movl(out, Address(obj, class_offset));
3687 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003688 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003689 } else {
3690 DCHECK(cls.IsStackSlot()) << cls;
3691 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3692 }
3693 if (instruction->IsClassFinal()) {
3694 // Classes must be equal for the instanceof to succeed.
3695 __ j(kNotEqual, &zero);
3696 __ movl(out, Immediate(1));
3697 __ jmp(&done);
3698 } else {
3699 // If the classes are not equal, we go into a slow path.
3700 DCHECK(locations->OnlyCallsOnSlowPath());
3701 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003702 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003703 codegen_->AddSlowPath(slow_path);
3704 __ j(kNotEqual, slow_path->GetEntryLabel());
3705 __ movl(out, Immediate(1));
3706 __ jmp(&done);
3707 }
3708 __ Bind(&zero);
3709 __ movl(out, Immediate(0));
3710 if (slow_path != nullptr) {
3711 __ Bind(slow_path->GetExitLabel());
3712 }
3713 __ Bind(&done);
3714}
3715
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003716void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3717 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3718 instruction, LocationSummary::kCallOnSlowPath);
3719 locations->SetInAt(0, Location::RequiresRegister());
3720 locations->SetInAt(1, Location::Any());
3721 locations->AddTemp(Location::RequiresRegister());
3722}
3723
3724void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3725 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003726 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003727 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003728 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003729 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3730 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3731 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3732 codegen_->AddSlowPath(slow_path);
3733
3734 // TODO: avoid this check if we know obj is not null.
3735 __ testl(obj, obj);
3736 __ j(kEqual, slow_path->GetExitLabel());
3737 // Compare the class of `obj` with `cls`.
3738 __ movl(temp, Address(obj, class_offset));
3739 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003740 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003741 } else {
3742 DCHECK(cls.IsStackSlot()) << cls;
3743 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3744 }
3745 // Classes must be equal for the checkcast to succeed.
3746 __ j(kNotEqual, slow_path->GetEntryLabel());
3747 __ Bind(slow_path->GetExitLabel());
3748}
3749
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003750void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3751 LocationSummary* locations =
3752 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3753 InvokeRuntimeCallingConvention calling_convention;
3754 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3755}
3756
3757void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3758 __ gs()->call(Address::Absolute(instruction->IsEnter()
3759 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3760 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3761 true));
3762 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3763}
3764
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003765void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3766void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3767void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3768
3769void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3770 LocationSummary* locations =
3771 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3772 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3773 || instruction->GetResultType() == Primitive::kPrimLong);
3774 locations->SetInAt(0, Location::RequiresRegister());
3775 if (instruction->GetType() == Primitive::kPrimInt) {
3776 locations->SetInAt(1, Location::Any());
3777 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003778 // We can handle 32 bit constants.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003779 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003780 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003781 }
3782 locations->SetOut(Location::SameAsFirstInput());
3783}
3784
3785void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3786 HandleBitwiseOperation(instruction);
3787}
3788
3789void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3790 HandleBitwiseOperation(instruction);
3791}
3792
3793void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3794 HandleBitwiseOperation(instruction);
3795}
3796
3797void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3798 LocationSummary* locations = instruction->GetLocations();
3799 Location first = locations->InAt(0);
3800 Location second = locations->InAt(1);
3801 DCHECK(first.Equals(locations->Out()));
3802
3803 if (instruction->GetResultType() == Primitive::kPrimInt) {
3804 if (second.IsRegister()) {
3805 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003806 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003807 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003808 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003809 } else {
3810 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003812 }
3813 } else if (second.IsConstant()) {
3814 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3815 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003816 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003817 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003818 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003819 } else {
3820 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003821 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003822 }
3823 } else {
3824 Address address(CpuRegister(RSP), second.GetStackIndex());
3825 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003826 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003827 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003828 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003829 } else {
3830 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003831 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003832 }
3833 }
3834 } else {
3835 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003836 CpuRegister first_reg = first.AsRegister<CpuRegister>();
3837 bool second_is_constant = false;
3838 int64_t value = 0;
3839 if (second.IsConstant()) {
3840 second_is_constant = true;
3841 value = second.GetConstant()->AsLongConstant()->GetValue();
3842 DCHECK(IsInt<32>(value));
3843 }
3844
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003845 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003846 if (second_is_constant) {
3847 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
3848 } else {
3849 __ andq(first_reg, second.AsRegister<CpuRegister>());
3850 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003851 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003852 if (second_is_constant) {
3853 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
3854 } else {
3855 __ orq(first_reg, second.AsRegister<CpuRegister>());
3856 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003857 } else {
3858 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003859 if (second_is_constant) {
3860 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
3861 } else {
3862 __ xorq(first_reg, second.AsRegister<CpuRegister>());
3863 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003864 }
3865 }
3866}
3867
Calin Juravleb1498f62015-02-16 13:13:29 +00003868void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
3869 // Nothing to do, this should be removed during prepare for register allocator.
3870 UNUSED(instruction);
3871 LOG(FATAL) << "Unreachable";
3872}
3873
3874void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
3875 // Nothing to do, this should be removed during prepare for register allocator.
3876 UNUSED(instruction);
3877 LOG(FATAL) << "Unreachable";
3878}
3879
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003880} // namespace x86_64
3881} // namespace art