blob: cdbc7780a84839464fc2d57461eb9c2f6dfb4046 [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);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400414CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
415 const X86_64InstructionSetFeatures& isa_features,
416 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000417 : CodeGenerator(graph,
418 kNumberOfCpuRegisters,
419 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000420 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000421 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
422 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000423 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000424 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
425 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000426 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100427 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000429 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400430 move_resolver_(graph->GetArena(), this),
431 isa_features_(isa_features) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000432 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
433}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100434
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100435InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
436 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100437 : HGraphVisitor(graph),
438 assembler_(codegen->GetAssembler()),
439 codegen_(codegen) {}
440
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100441Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100442 switch (type) {
443 case Primitive::kPrimLong:
444 case Primitive::kPrimByte:
445 case Primitive::kPrimBoolean:
446 case Primitive::kPrimChar:
447 case Primitive::kPrimShort:
448 case Primitive::kPrimInt:
449 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100450 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100451 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100452 }
453
454 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100455 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100456 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100457 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100458 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100459
460 case Primitive::kPrimVoid:
461 LOG(FATAL) << "Unreachable type " << type;
462 }
463
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100464 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100465}
466
Nicolas Geoffray98893962015-01-21 12:32:32 +0000467void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100468 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100469 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100470
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000471 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100472 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000473
Nicolas Geoffray98893962015-01-21 12:32:32 +0000474 if (is_baseline) {
475 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
476 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
477 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000478 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
479 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
480 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000481 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100482}
483
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100484void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000485 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100486 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700487 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000488 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100489
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000490 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100491 __ testq(CpuRegister(RAX), Address(
492 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100493 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100494 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000495
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000496 if (HasEmptyFrame()) {
497 return;
498 }
499
Nicolas Geoffray98893962015-01-21 12:32:32 +0000500 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000501 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000502 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000503 __ pushq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000504 }
505 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100506
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000507 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
508 uint32_t xmm_spill_location = GetFpuSpillStart();
509 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100510
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000511 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
512 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
513 __ movsd(Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)),
514 XmmRegister(kFpuCalleeSaves[i]));
515 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100516 }
517
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100518 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
519}
520
521void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000522 if (HasEmptyFrame()) {
523 return;
524 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000525 uint32_t xmm_spill_location = GetFpuSpillStart();
526 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
527 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
528 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
529 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
530 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
531 }
532 }
533
534 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000535
536 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000537 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000538 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000539 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000540 }
541 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100542}
543
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100544void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
545 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100546}
547
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100548void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000549 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100550 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
551}
552
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100553Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
554 switch (load->GetType()) {
555 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100556 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100557 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100558
559 case Primitive::kPrimInt:
560 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100561 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100562 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100563
564 case Primitive::kPrimBoolean:
565 case Primitive::kPrimByte:
566 case Primitive::kPrimChar:
567 case Primitive::kPrimShort:
568 case Primitive::kPrimVoid:
569 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700570 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100571 }
572
573 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700574 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100575}
576
577void CodeGeneratorX86_64::Move(Location destination, Location source) {
578 if (source.Equals(destination)) {
579 return;
580 }
581 if (destination.IsRegister()) {
582 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000583 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100584 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000585 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000587 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100589 } else {
590 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000591 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100592 Address(CpuRegister(RSP), source.GetStackIndex()));
593 }
594 } else if (destination.IsFpuRegister()) {
595 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000596 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100597 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000598 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100599 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000600 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100601 Address(CpuRegister(RSP), source.GetStackIndex()));
602 } else {
603 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000604 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100605 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100606 }
607 } else if (destination.IsStackSlot()) {
608 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100609 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000610 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100611 } else if (source.IsFpuRegister()) {
612 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000613 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500614 } else if (source.IsConstant()) {
615 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000616 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500617 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100618 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500619 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000620 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
621 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100622 }
623 } else {
624 DCHECK(destination.IsDoubleStackSlot());
625 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100626 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000627 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100628 } else if (source.IsFpuRegister()) {
629 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000630 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500631 } else if (source.IsConstant()) {
632 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800633 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500634 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000635 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500636 } else {
637 DCHECK(constant->IsLongConstant());
638 value = constant->AsLongConstant()->GetValue();
639 }
640 __ movq(CpuRegister(TMP), Immediate(value));
641 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100642 } else {
643 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000644 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
645 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100646 }
647 }
648}
649
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100650void CodeGeneratorX86_64::Move(HInstruction* instruction,
651 Location location,
652 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000653 LocationSummary* locations = instruction->GetLocations();
654 if (locations != nullptr && locations->Out().Equals(location)) {
655 return;
656 }
657
658 if (locations != nullptr && locations->Out().IsConstant()) {
659 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000660 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
661 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000662 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000663 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000664 } else if (location.IsStackSlot()) {
665 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
666 } else {
667 DCHECK(location.IsConstant());
668 DCHECK_EQ(location.GetConstant(), const_to_move);
669 }
670 } else if (const_to_move->IsLongConstant()) {
671 int64_t value = const_to_move->AsLongConstant()->GetValue();
672 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000673 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000674 } else if (location.IsDoubleStackSlot()) {
675 __ movq(CpuRegister(TMP), Immediate(value));
676 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
677 } else {
678 DCHECK(location.IsConstant());
679 DCHECK_EQ(location.GetConstant(), const_to_move);
680 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100681 }
Roland Levillain476df552014-10-09 17:51:36 +0100682 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100683 switch (instruction->GetType()) {
684 case Primitive::kPrimBoolean:
685 case Primitive::kPrimByte:
686 case Primitive::kPrimChar:
687 case Primitive::kPrimShort:
688 case Primitive::kPrimInt:
689 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100690 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100691 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
692 break;
693
694 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100695 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000696 Move(location,
697 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100698 break;
699
700 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100701 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100702 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000703 } else if (instruction->IsTemporary()) {
704 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
705 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100706 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100707 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100708 switch (instruction->GetType()) {
709 case Primitive::kPrimBoolean:
710 case Primitive::kPrimByte:
711 case Primitive::kPrimChar:
712 case Primitive::kPrimShort:
713 case Primitive::kPrimInt:
714 case Primitive::kPrimNot:
715 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100716 case Primitive::kPrimFloat:
717 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000718 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100719 break;
720
721 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100722 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100723 }
724 }
725}
726
727void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
728 got->SetLocations(nullptr);
729}
730
731void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
732 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100733 DCHECK(!successor->IsExitBlock());
734
735 HBasicBlock* block = got->GetBlock();
736 HInstruction* previous = got->GetPrevious();
737
738 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000739 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100740 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
741 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
742 return;
743 }
744
745 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
746 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
747 }
748 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100749 __ jmp(codegen_->GetLabelOf(successor));
750 }
751}
752
753void LocationsBuilderX86_64::VisitExit(HExit* exit) {
754 exit->SetLocations(nullptr);
755}
756
757void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700758 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100759}
760
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700761void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
762 Label* true_target,
763 Label* false_target,
764 Label* always_true_target) {
765 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100766 if (cond->IsIntConstant()) {
767 // Constant condition, statically compared against 1.
768 int32_t cond_value = cond->AsIntConstant()->GetValue();
769 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700770 if (always_true_target != nullptr) {
771 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100772 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100773 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100774 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100775 DCHECK_EQ(cond_value, 0);
776 }
777 } else {
778 bool materialized =
779 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
780 // Moves do not affect the eflags register, so if the condition is
781 // evaluated just before the if, we don't need to evaluate it
782 // again.
783 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700784 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100785 if (materialized) {
786 if (!eflags_set) {
787 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700788 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100789 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000790 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100791 } else {
792 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
793 Immediate(0));
794 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700795 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100796 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700797 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100798 }
799 } else {
800 Location lhs = cond->GetLocations()->InAt(0);
801 Location rhs = cond->GetLocations()->InAt(1);
802 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000803 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100804 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000805 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000806 if (constant == 0) {
807 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
808 } else {
809 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
810 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100811 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000812 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100813 Address(CpuRegister(RSP), rhs.GetStackIndex()));
814 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700815 __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700816 }
Dave Allison20dfc792014-06-16 20:44:29 -0700817 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700818 if (false_target != nullptr) {
819 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100820 }
821}
822
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700823void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
824 LocationSummary* locations =
825 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
826 HInstruction* cond = if_instr->InputAt(0);
827 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
828 locations->SetInAt(0, Location::Any());
829 }
830}
831
832void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
833 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
834 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
835 Label* always_true_target = true_target;
836 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
837 if_instr->IfTrueSuccessor())) {
838 always_true_target = nullptr;
839 }
840 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
841 if_instr->IfFalseSuccessor())) {
842 false_target = nullptr;
843 }
844 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
845}
846
847void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
848 LocationSummary* locations = new (GetGraph()->GetArena())
849 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
850 HInstruction* cond = deoptimize->InputAt(0);
851 DCHECK(cond->IsCondition());
852 if (cond->AsCondition()->NeedsMaterialization()) {
853 locations->SetInAt(0, Location::Any());
854 }
855}
856
857void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
858 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
859 DeoptimizationSlowPathX86_64(deoptimize);
860 codegen_->AddSlowPath(slow_path);
861 Label* slow_path_entry = slow_path->GetEntryLabel();
862 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
863}
864
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
866 local->SetLocations(nullptr);
867}
868
869void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
870 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
871}
872
873void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
874 local->SetLocations(nullptr);
875}
876
877void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
878 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700879 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100880}
881
882void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100883 LocationSummary* locations =
884 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100885 switch (store->InputAt(1)->GetType()) {
886 case Primitive::kPrimBoolean:
887 case Primitive::kPrimByte:
888 case Primitive::kPrimChar:
889 case Primitive::kPrimShort:
890 case Primitive::kPrimInt:
891 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100892 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100893 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
894 break;
895
896 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100897 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100898 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
899 break;
900
901 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100902 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100903 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100904}
905
906void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700907 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100908}
909
Dave Allison20dfc792014-06-16 20:44:29 -0700910void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100911 LocationSummary* locations =
912 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100913 locations->SetInAt(0, Location::RequiresRegister());
914 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100915 if (comp->NeedsMaterialization()) {
916 locations->SetOut(Location::RequiresRegister());
917 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100918}
919
Dave Allison20dfc792014-06-16 20:44:29 -0700920void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
921 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100922 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000923 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100924 // Clear register: setcc only sets the low byte.
925 __ xorq(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000926 Location lhs = locations->InAt(0);
927 Location rhs = locations->InAt(1);
928 if (rhs.IsRegister()) {
929 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
930 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800931 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000932 if (constant == 0) {
933 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
934 } else {
935 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
936 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100937 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000938 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100939 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100940 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700941 }
942}
943
944void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
945 VisitCondition(comp);
946}
947
948void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
949 VisitCondition(comp);
950}
951
952void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
953 VisitCondition(comp);
954}
955
956void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
957 VisitCondition(comp);
958}
959
960void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
961 VisitCondition(comp);
962}
963
964void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
965 VisitCondition(comp);
966}
967
968void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
969 VisitCondition(comp);
970}
971
972void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
973 VisitCondition(comp);
974}
975
976void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
977 VisitCondition(comp);
978}
979
980void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
981 VisitCondition(comp);
982}
983
984void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
985 VisitCondition(comp);
986}
987
988void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
989 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100990}
991
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100992void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100993 LocationSummary* locations =
994 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000995 switch (compare->InputAt(0)->GetType()) {
996 case Primitive::kPrimLong: {
997 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400998 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +0000999 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1000 break;
1001 }
1002 case Primitive::kPrimFloat:
1003 case Primitive::kPrimDouble: {
1004 locations->SetInAt(0, Location::RequiresFpuRegister());
1005 locations->SetInAt(1, Location::RequiresFpuRegister());
1006 locations->SetOut(Location::RequiresRegister());
1007 break;
1008 }
1009 default:
1010 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1011 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001012}
1013
1014void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001015 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001016 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001017 Location left = locations->InAt(0);
1018 Location right = locations->InAt(1);
1019
1020 Label less, greater, done;
1021 Primitive::Type type = compare->InputAt(0)->GetType();
1022 switch (type) {
1023 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001024 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1025 if (right.IsConstant()) {
1026 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1027 DCHECK(IsInt<32>(value));
1028 if (value == 0) {
1029 __ testq(left_reg, left_reg);
1030 } else {
1031 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1032 }
1033 } else {
1034 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1035 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001036 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001037 }
1038 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001039 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001040 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1041 break;
1042 }
1043 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001044 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00001045 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1046 break;
1047 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001048 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001049 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001050 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001051 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001052 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001053 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001054
Calin Juravle91debbc2014-11-26 19:01:09 +00001055 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001056 __ movl(out, Immediate(1));
1057 __ jmp(&done);
1058
1059 __ Bind(&less);
1060 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001061
1062 __ Bind(&done);
1063}
1064
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001065void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001066 LocationSummary* locations =
1067 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001068 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001069}
1070
1071void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001072 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001073 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001074}
1075
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001076void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1077 LocationSummary* locations =
1078 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1079 locations->SetOut(Location::ConstantLocation(constant));
1080}
1081
1082void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1083 // Will be generated at use site.
1084 UNUSED(constant);
1085}
1086
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001087void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001088 LocationSummary* locations =
1089 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001090 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001091}
1092
1093void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001094 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001095 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001096}
1097
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001098void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1099 LocationSummary* locations =
1100 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1101 locations->SetOut(Location::ConstantLocation(constant));
1102}
1103
1104void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1105 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001106 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001107}
1108
1109void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1110 LocationSummary* locations =
1111 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1112 locations->SetOut(Location::ConstantLocation(constant));
1113}
1114
1115void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1116 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001117 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001118}
1119
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001120void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1121 ret->SetLocations(nullptr);
1122}
1123
1124void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001125 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001126 codegen_->GenerateFrameExit();
1127 __ ret();
1128}
1129
1130void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001131 LocationSummary* locations =
1132 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001133 switch (ret->InputAt(0)->GetType()) {
1134 case Primitive::kPrimBoolean:
1135 case Primitive::kPrimByte:
1136 case Primitive::kPrimChar:
1137 case Primitive::kPrimShort:
1138 case Primitive::kPrimInt:
1139 case Primitive::kPrimNot:
1140 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001141 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001142 break;
1143
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001144 case Primitive::kPrimFloat:
1145 case Primitive::kPrimDouble:
1146 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001147 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001148 break;
1149
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001150 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001151 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001152 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001153}
1154
1155void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1156 if (kIsDebugBuild) {
1157 switch (ret->InputAt(0)->GetType()) {
1158 case Primitive::kPrimBoolean:
1159 case Primitive::kPrimByte:
1160 case Primitive::kPrimChar:
1161 case Primitive::kPrimShort:
1162 case Primitive::kPrimInt:
1163 case Primitive::kPrimNot:
1164 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001165 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001166 break;
1167
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001168 case Primitive::kPrimFloat:
1169 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001170 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001171 XMM0);
1172 break;
1173
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001174 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001175 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001176 }
1177 }
1178 codegen_->GenerateFrameExit();
1179 __ ret();
1180}
1181
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001182Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1183 switch (type) {
1184 case Primitive::kPrimBoolean:
1185 case Primitive::kPrimByte:
1186 case Primitive::kPrimChar:
1187 case Primitive::kPrimShort:
1188 case Primitive::kPrimInt:
1189 case Primitive::kPrimNot: {
1190 uint32_t index = gp_index_++;
1191 stack_index_++;
1192 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001193 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001194 } else {
1195 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1196 }
1197 }
1198
1199 case Primitive::kPrimLong: {
1200 uint32_t index = gp_index_;
1201 stack_index_ += 2;
1202 if (index < calling_convention.GetNumberOfRegisters()) {
1203 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001204 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001205 } else {
1206 gp_index_ += 2;
1207 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1208 }
1209 }
1210
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001211 case Primitive::kPrimFloat: {
1212 uint32_t index = fp_index_++;
1213 stack_index_++;
1214 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001215 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001216 } else {
1217 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1218 }
1219 }
1220
1221 case Primitive::kPrimDouble: {
1222 uint32_t index = fp_index_++;
1223 stack_index_ += 2;
1224 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001225 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001226 } else {
1227 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1228 }
1229 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001230
1231 case Primitive::kPrimVoid:
1232 LOG(FATAL) << "Unexpected parameter type " << type;
1233 break;
1234 }
1235 return Location();
1236}
1237
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001238void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001239 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001240 if (intrinsic.TryDispatch(invoke)) {
1241 return;
1242 }
1243
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001244 HandleInvoke(invoke);
1245}
1246
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001247static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1248 if (invoke->GetLocations()->Intrinsified()) {
1249 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1250 intrinsic.Dispatch(invoke);
1251 return true;
1252 }
1253 return false;
1254}
1255
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001256void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001257 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1258 return;
1259 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001260
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001261 codegen_->GenerateStaticOrDirectCall(
1262 invoke,
1263 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001264 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001265}
1266
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001267void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001268 LocationSummary* locations =
1269 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001270 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001271
1272 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001273 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001274 HInstruction* input = invoke->InputAt(i);
1275 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1276 }
1277
1278 switch (invoke->GetType()) {
1279 case Primitive::kPrimBoolean:
1280 case Primitive::kPrimByte:
1281 case Primitive::kPrimChar:
1282 case Primitive::kPrimShort:
1283 case Primitive::kPrimInt:
1284 case Primitive::kPrimNot:
1285 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001286 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001287 break;
1288
1289 case Primitive::kPrimVoid:
1290 break;
1291
1292 case Primitive::kPrimDouble:
1293 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001294 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001295 break;
1296 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001297}
1298
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001299void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001300 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001301 if (intrinsic.TryDispatch(invoke)) {
1302 return;
1303 }
1304
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001305 HandleInvoke(invoke);
1306}
1307
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001308void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001309 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1310 return;
1311 }
1312
Roland Levillain271ab9c2014-11-27 15:23:57 +00001313 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001314 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1315 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1316 LocationSummary* locations = invoke->GetLocations();
1317 Location receiver = locations->InAt(0);
1318 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1319 // temp = object->GetClass();
1320 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001321 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1322 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001323 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001324 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001325 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001326 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001327 // temp = temp->GetMethodAt(method_offset);
1328 __ movl(temp, Address(temp, method_offset));
1329 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001330 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001331 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001332
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001333 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001334 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001335}
1336
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001337void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1338 HandleInvoke(invoke);
1339 // Add the hidden argument.
1340 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1341}
1342
1343void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1344 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001345 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001346 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1347 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1348 LocationSummary* locations = invoke->GetLocations();
1349 Location receiver = locations->InAt(0);
1350 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1351
1352 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001353 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001354 Immediate(invoke->GetDexMethodIndex()));
1355
1356 // temp = object->GetClass();
1357 if (receiver.IsStackSlot()) {
1358 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1359 __ movl(temp, Address(temp, class_offset));
1360 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001361 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001362 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001363 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001364 // temp = temp->GetImtEntryAt(method_offset);
1365 __ movl(temp, Address(temp, method_offset));
1366 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001367 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001368 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001369
1370 DCHECK(!codegen_->IsLeafMethod());
1371 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1372}
1373
Roland Levillain88cb1752014-10-20 16:36:47 +01001374void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1375 LocationSummary* locations =
1376 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1377 switch (neg->GetResultType()) {
1378 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001379 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001380 locations->SetInAt(0, Location::RequiresRegister());
1381 locations->SetOut(Location::SameAsFirstInput());
1382 break;
1383
Roland Levillain88cb1752014-10-20 16:36:47 +01001384 case Primitive::kPrimFloat:
1385 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001386 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001387 locations->SetOut(Location::SameAsFirstInput());
1388 locations->AddTemp(Location::RequiresRegister());
1389 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001390 break;
1391
1392 default:
1393 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1394 }
1395}
1396
1397void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1398 LocationSummary* locations = neg->GetLocations();
1399 Location out = locations->Out();
1400 Location in = locations->InAt(0);
1401 switch (neg->GetResultType()) {
1402 case Primitive::kPrimInt:
1403 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001404 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001405 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001406 break;
1407
1408 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001409 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001410 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001411 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001412 break;
1413
Roland Levillain5368c212014-11-27 15:03:41 +00001414 case Primitive::kPrimFloat: {
1415 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001416 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1417 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001418 // Implement float negation with an exclusive or with value
1419 // 0x80000000 (mask for bit 31, representing the sign of a
1420 // single-precision floating-point number).
1421 __ movq(constant, Immediate(INT64_C(0x80000000)));
1422 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001423 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001424 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001425 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001426
Roland Levillain5368c212014-11-27 15:03:41 +00001427 case Primitive::kPrimDouble: {
1428 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001429 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1430 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001431 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001432 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001433 // a double-precision floating-point number).
1434 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1435 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001436 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001437 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001438 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001439
1440 default:
1441 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1442 }
1443}
1444
Roland Levillaindff1f282014-11-05 14:15:05 +00001445void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1446 LocationSummary* locations =
1447 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1448 Primitive::Type result_type = conversion->GetResultType();
1449 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001450 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001451
David Brazdilb2bd1c52015-03-25 11:17:37 +00001452 // The Java language does not allow treating boolean as an integral type but
1453 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001454
Roland Levillaindff1f282014-11-05 14:15:05 +00001455 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001456 case Primitive::kPrimByte:
1457 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001458 case Primitive::kPrimBoolean:
1459 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001460 case Primitive::kPrimShort:
1461 case Primitive::kPrimInt:
1462 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001463 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001464 locations->SetInAt(0, Location::Any());
1465 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1466 break;
1467
1468 default:
1469 LOG(FATAL) << "Unexpected type conversion from " << input_type
1470 << " to " << result_type;
1471 }
1472 break;
1473
Roland Levillain01a8d712014-11-14 16:27:39 +00001474 case Primitive::kPrimShort:
1475 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001476 case Primitive::kPrimBoolean:
1477 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001478 case Primitive::kPrimByte:
1479 case Primitive::kPrimInt:
1480 case Primitive::kPrimChar:
1481 // Processing a Dex `int-to-short' instruction.
1482 locations->SetInAt(0, Location::Any());
1483 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1484 break;
1485
1486 default:
1487 LOG(FATAL) << "Unexpected type conversion from " << input_type
1488 << " to " << result_type;
1489 }
1490 break;
1491
Roland Levillain946e1432014-11-11 17:35:19 +00001492 case Primitive::kPrimInt:
1493 switch (input_type) {
1494 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001495 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001496 locations->SetInAt(0, Location::Any());
1497 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1498 break;
1499
1500 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001501 // Processing a Dex `float-to-int' instruction.
1502 locations->SetInAt(0, Location::RequiresFpuRegister());
1503 locations->SetOut(Location::RequiresRegister());
1504 locations->AddTemp(Location::RequiresFpuRegister());
1505 break;
1506
Roland Levillain946e1432014-11-11 17:35:19 +00001507 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001508 // Processing a Dex `double-to-int' instruction.
1509 locations->SetInAt(0, Location::RequiresFpuRegister());
1510 locations->SetOut(Location::RequiresRegister());
1511 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001512 break;
1513
1514 default:
1515 LOG(FATAL) << "Unexpected type conversion from " << input_type
1516 << " to " << result_type;
1517 }
1518 break;
1519
Roland Levillaindff1f282014-11-05 14:15:05 +00001520 case Primitive::kPrimLong:
1521 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001522 case Primitive::kPrimBoolean:
1523 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001524 case Primitive::kPrimByte:
1525 case Primitive::kPrimShort:
1526 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001527 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001528 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001529 // TODO: We would benefit from a (to-be-implemented)
1530 // Location::RegisterOrStackSlot requirement for this input.
1531 locations->SetInAt(0, Location::RequiresRegister());
1532 locations->SetOut(Location::RequiresRegister());
1533 break;
1534
1535 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001536 // Processing a Dex `float-to-long' instruction.
1537 locations->SetInAt(0, Location::RequiresFpuRegister());
1538 locations->SetOut(Location::RequiresRegister());
1539 locations->AddTemp(Location::RequiresFpuRegister());
1540 break;
1541
Roland Levillaindff1f282014-11-05 14:15:05 +00001542 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001543 // Processing a Dex `double-to-long' instruction.
1544 locations->SetInAt(0, Location::RequiresFpuRegister());
1545 locations->SetOut(Location::RequiresRegister());
1546 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001547 break;
1548
1549 default:
1550 LOG(FATAL) << "Unexpected type conversion from " << input_type
1551 << " to " << result_type;
1552 }
1553 break;
1554
Roland Levillain981e4542014-11-14 11:47:14 +00001555 case Primitive::kPrimChar:
1556 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001557 case Primitive::kPrimBoolean:
1558 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001559 case Primitive::kPrimByte:
1560 case Primitive::kPrimShort:
1561 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001562 // Processing a Dex `int-to-char' instruction.
1563 locations->SetInAt(0, Location::Any());
1564 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1565 break;
1566
1567 default:
1568 LOG(FATAL) << "Unexpected type conversion from " << input_type
1569 << " to " << result_type;
1570 }
1571 break;
1572
Roland Levillaindff1f282014-11-05 14:15:05 +00001573 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001574 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001575 case Primitive::kPrimBoolean:
1576 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001577 case Primitive::kPrimByte:
1578 case Primitive::kPrimShort:
1579 case Primitive::kPrimInt:
1580 case Primitive::kPrimChar:
1581 // Processing a Dex `int-to-float' instruction.
1582 locations->SetInAt(0, Location::RequiresRegister());
1583 locations->SetOut(Location::RequiresFpuRegister());
1584 break;
1585
1586 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001587 // Processing a Dex `long-to-float' instruction.
1588 locations->SetInAt(0, Location::RequiresRegister());
1589 locations->SetOut(Location::RequiresFpuRegister());
1590 break;
1591
Roland Levillaincff13742014-11-17 14:32:17 +00001592 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001593 // Processing a Dex `double-to-float' instruction.
1594 locations->SetInAt(0, Location::RequiresFpuRegister());
1595 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001596 break;
1597
1598 default:
1599 LOG(FATAL) << "Unexpected type conversion from " << input_type
1600 << " to " << result_type;
1601 };
1602 break;
1603
Roland Levillaindff1f282014-11-05 14:15:05 +00001604 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001605 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001606 case Primitive::kPrimBoolean:
1607 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001608 case Primitive::kPrimByte:
1609 case Primitive::kPrimShort:
1610 case Primitive::kPrimInt:
1611 case Primitive::kPrimChar:
1612 // Processing a Dex `int-to-double' instruction.
1613 locations->SetInAt(0, Location::RequiresRegister());
1614 locations->SetOut(Location::RequiresFpuRegister());
1615 break;
1616
1617 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001618 // Processing a Dex `long-to-double' instruction.
1619 locations->SetInAt(0, Location::RequiresRegister());
1620 locations->SetOut(Location::RequiresFpuRegister());
1621 break;
1622
Roland Levillaincff13742014-11-17 14:32:17 +00001623 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001624 // Processing a Dex `float-to-double' instruction.
1625 locations->SetInAt(0, Location::RequiresFpuRegister());
1626 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001627 break;
1628
1629 default:
1630 LOG(FATAL) << "Unexpected type conversion from " << input_type
1631 << " to " << result_type;
1632 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001633 break;
1634
1635 default:
1636 LOG(FATAL) << "Unexpected type conversion from " << input_type
1637 << " to " << result_type;
1638 }
1639}
1640
1641void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1642 LocationSummary* locations = conversion->GetLocations();
1643 Location out = locations->Out();
1644 Location in = locations->InAt(0);
1645 Primitive::Type result_type = conversion->GetResultType();
1646 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001647 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001648 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001649 case Primitive::kPrimByte:
1650 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001651 case Primitive::kPrimBoolean:
1652 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001653 case Primitive::kPrimShort:
1654 case Primitive::kPrimInt:
1655 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001656 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001657 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001658 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001659 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001660 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001661 Address(CpuRegister(RSP), in.GetStackIndex()));
1662 } else {
1663 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001664 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001665 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1666 }
1667 break;
1668
1669 default:
1670 LOG(FATAL) << "Unexpected type conversion from " << input_type
1671 << " to " << result_type;
1672 }
1673 break;
1674
Roland Levillain01a8d712014-11-14 16:27:39 +00001675 case Primitive::kPrimShort:
1676 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001677 case Primitive::kPrimBoolean:
1678 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001679 case Primitive::kPrimByte:
1680 case Primitive::kPrimInt:
1681 case Primitive::kPrimChar:
1682 // Processing a Dex `int-to-short' instruction.
1683 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001684 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001685 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001686 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001687 Address(CpuRegister(RSP), in.GetStackIndex()));
1688 } else {
1689 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001690 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001691 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1692 }
1693 break;
1694
1695 default:
1696 LOG(FATAL) << "Unexpected type conversion from " << input_type
1697 << " to " << result_type;
1698 }
1699 break;
1700
Roland Levillain946e1432014-11-11 17:35:19 +00001701 case Primitive::kPrimInt:
1702 switch (input_type) {
1703 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001704 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001705 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001706 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001707 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001708 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001709 Address(CpuRegister(RSP), in.GetStackIndex()));
1710 } else {
1711 DCHECK(in.IsConstant());
1712 DCHECK(in.GetConstant()->IsLongConstant());
1713 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001714 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001715 }
1716 break;
1717
Roland Levillain3f8f9362014-12-02 17:45:01 +00001718 case Primitive::kPrimFloat: {
1719 // Processing a Dex `float-to-int' instruction.
1720 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1721 CpuRegister output = out.AsRegister<CpuRegister>();
1722 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1723 Label done, nan;
1724
1725 __ movl(output, Immediate(kPrimIntMax));
1726 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001727 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001728 // if input >= temp goto done
1729 __ comiss(input, temp);
1730 __ j(kAboveEqual, &done);
1731 // if input == NaN goto nan
1732 __ j(kUnordered, &nan);
1733 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001734 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001735 __ jmp(&done);
1736 __ Bind(&nan);
1737 // output = 0
1738 __ xorl(output, output);
1739 __ Bind(&done);
1740 break;
1741 }
1742
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001743 case Primitive::kPrimDouble: {
1744 // Processing a Dex `double-to-int' instruction.
1745 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1746 CpuRegister output = out.AsRegister<CpuRegister>();
1747 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1748 Label done, nan;
1749
1750 __ movl(output, Immediate(kPrimIntMax));
1751 // temp = int-to-double(output)
1752 __ cvtsi2sd(temp, output);
1753 // if input >= temp goto done
1754 __ comisd(input, temp);
1755 __ j(kAboveEqual, &done);
1756 // if input == NaN goto nan
1757 __ j(kUnordered, &nan);
1758 // output = double-to-int-truncate(input)
1759 __ cvttsd2si(output, input);
1760 __ jmp(&done);
1761 __ Bind(&nan);
1762 // output = 0
1763 __ xorl(output, output);
1764 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001765 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001766 }
Roland Levillain946e1432014-11-11 17:35:19 +00001767
1768 default:
1769 LOG(FATAL) << "Unexpected type conversion from " << input_type
1770 << " to " << result_type;
1771 }
1772 break;
1773
Roland Levillaindff1f282014-11-05 14:15:05 +00001774 case Primitive::kPrimLong:
1775 switch (input_type) {
1776 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001777 case Primitive::kPrimBoolean:
1778 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001779 case Primitive::kPrimByte:
1780 case Primitive::kPrimShort:
1781 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001782 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001783 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001784 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001785 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001786 break;
1787
Roland Levillain624279f2014-12-04 11:54:28 +00001788 case Primitive::kPrimFloat: {
1789 // Processing a Dex `float-to-long' instruction.
1790 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1791 CpuRegister output = out.AsRegister<CpuRegister>();
1792 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1793 Label done, nan;
1794
1795 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001796 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001797 __ cvtsi2ss(temp, output, true);
1798 // if input >= temp goto done
1799 __ comiss(input, temp);
1800 __ j(kAboveEqual, &done);
1801 // if input == NaN goto nan
1802 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001803 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001804 __ cvttss2si(output, input, true);
1805 __ jmp(&done);
1806 __ Bind(&nan);
1807 // output = 0
1808 __ xorq(output, output);
1809 __ Bind(&done);
1810 break;
1811 }
1812
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001813 case Primitive::kPrimDouble: {
1814 // Processing a Dex `double-to-long' instruction.
1815 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1816 CpuRegister output = out.AsRegister<CpuRegister>();
1817 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1818 Label done, nan;
1819
1820 __ movq(output, Immediate(kPrimLongMax));
1821 // temp = long-to-double(output)
1822 __ cvtsi2sd(temp, output, true);
1823 // if input >= temp goto done
1824 __ comisd(input, temp);
1825 __ j(kAboveEqual, &done);
1826 // if input == NaN goto nan
1827 __ j(kUnordered, &nan);
1828 // output = double-to-long-truncate(input)
1829 __ cvttsd2si(output, input, true);
1830 __ jmp(&done);
1831 __ Bind(&nan);
1832 // output = 0
1833 __ xorq(output, output);
1834 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001835 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001836 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001837
1838 default:
1839 LOG(FATAL) << "Unexpected type conversion from " << input_type
1840 << " to " << result_type;
1841 }
1842 break;
1843
Roland Levillain981e4542014-11-14 11:47:14 +00001844 case Primitive::kPrimChar:
1845 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001846 case Primitive::kPrimBoolean:
1847 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001848 case Primitive::kPrimByte:
1849 case Primitive::kPrimShort:
1850 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001851 // Processing a Dex `int-to-char' instruction.
1852 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001853 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001854 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001855 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001856 Address(CpuRegister(RSP), in.GetStackIndex()));
1857 } else {
1858 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001859 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001860 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1861 }
1862 break;
1863
1864 default:
1865 LOG(FATAL) << "Unexpected type conversion from " << input_type
1866 << " to " << result_type;
1867 }
1868 break;
1869
Roland Levillaindff1f282014-11-05 14:15:05 +00001870 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001871 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001872 case Primitive::kPrimBoolean:
1873 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001874 case Primitive::kPrimByte:
1875 case Primitive::kPrimShort:
1876 case Primitive::kPrimInt:
1877 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001878 // Processing a Dex `int-to-float' instruction.
1879 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001880 break;
1881
1882 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001883 // Processing a Dex `long-to-float' instruction.
1884 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1885 break;
1886
Roland Levillaincff13742014-11-17 14:32:17 +00001887 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001888 // Processing a Dex `double-to-float' instruction.
1889 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001890 break;
1891
1892 default:
1893 LOG(FATAL) << "Unexpected type conversion from " << input_type
1894 << " to " << result_type;
1895 };
1896 break;
1897
Roland Levillaindff1f282014-11-05 14:15:05 +00001898 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001899 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001900 case Primitive::kPrimBoolean:
1901 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001902 case Primitive::kPrimByte:
1903 case Primitive::kPrimShort:
1904 case Primitive::kPrimInt:
1905 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001906 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001907 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001908 break;
1909
1910 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001911 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001912 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001913 break;
1914
Roland Levillaincff13742014-11-17 14:32:17 +00001915 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001916 // Processing a Dex `float-to-double' instruction.
1917 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001918 break;
1919
1920 default:
1921 LOG(FATAL) << "Unexpected type conversion from " << input_type
1922 << " to " << result_type;
1923 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001924 break;
1925
1926 default:
1927 LOG(FATAL) << "Unexpected type conversion from " << input_type
1928 << " to " << result_type;
1929 }
1930}
1931
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001932void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001933 LocationSummary* locations =
1934 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001935 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001936 case Primitive::kPrimInt: {
1937 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001938 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1939 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001940 break;
1941 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001942
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001943 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001944 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05001945 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001946 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05001947 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001948 break;
1949 }
1950
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001951 case Primitive::kPrimDouble:
1952 case Primitive::kPrimFloat: {
1953 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001954 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001955 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001956 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001957 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001958
1959 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001960 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001961 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001962}
1963
1964void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1965 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001966 Location first = locations->InAt(0);
1967 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001968 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01001969
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001970 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001971 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001972 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001973 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1974 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1975 } else {
1976 __ leal(out.AsRegister<CpuRegister>(), Address(
1977 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1978 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001979 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001980 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1981 __ addl(out.AsRegister<CpuRegister>(),
1982 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
1983 } else {
1984 __ leal(out.AsRegister<CpuRegister>(), Address(
1985 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
1986 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001987 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001988 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001989 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001990 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001991 break;
1992 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001993
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001994 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05001995 if (second.IsRegister()) {
1996 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1997 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1998 } else {
1999 __ leaq(out.AsRegister<CpuRegister>(), Address(
2000 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2001 }
2002 } else {
2003 DCHECK(second.IsConstant());
2004 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2005 int32_t int32_value = Low32Bits(value);
2006 DCHECK_EQ(int32_value, value);
2007 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2008 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2009 } else {
2010 __ leaq(out.AsRegister<CpuRegister>(), Address(
2011 first.AsRegister<CpuRegister>(), int32_value));
2012 }
2013 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002014 break;
2015 }
2016
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002017 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002018 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002019 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002020 }
2021
2022 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002023 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002024 break;
2025 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002026
2027 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002028 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002029 }
2030}
2031
2032void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002033 LocationSummary* locations =
2034 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002035 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002036 case Primitive::kPrimInt: {
2037 locations->SetInAt(0, Location::RequiresRegister());
2038 locations->SetInAt(1, Location::Any());
2039 locations->SetOut(Location::SameAsFirstInput());
2040 break;
2041 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002042 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002043 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002044 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002045 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002046 break;
2047 }
Calin Juravle11351682014-10-23 15:38:15 +01002048 case Primitive::kPrimFloat:
2049 case Primitive::kPrimDouble: {
2050 locations->SetInAt(0, Location::RequiresFpuRegister());
2051 locations->SetInAt(1, Location::RequiresFpuRegister());
2052 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002053 break;
Calin Juravle11351682014-10-23 15:38:15 +01002054 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002055 default:
Calin Juravle11351682014-10-23 15:38:15 +01002056 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002057 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002058}
2059
2060void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2061 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002062 Location first = locations->InAt(0);
2063 Location second = locations->InAt(1);
2064 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002065 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002066 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002067 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002068 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002069 } else if (second.IsConstant()) {
2070 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002071 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002072 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002073 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002074 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002075 break;
2076 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002077 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002078 if (second.IsConstant()) {
2079 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2080 DCHECK(IsInt<32>(value));
2081 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2082 } else {
2083 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2084 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002085 break;
2086 }
2087
Calin Juravle11351682014-10-23 15:38:15 +01002088 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002089 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002090 break;
Calin Juravle11351682014-10-23 15:38:15 +01002091 }
2092
2093 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002094 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002095 break;
2096 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002097
2098 default:
Calin Juravle11351682014-10-23 15:38:15 +01002099 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002100 }
2101}
2102
Calin Juravle34bacdf2014-10-07 20:23:36 +01002103void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2104 LocationSummary* locations =
2105 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2106 switch (mul->GetResultType()) {
2107 case Primitive::kPrimInt: {
2108 locations->SetInAt(0, Location::RequiresRegister());
2109 locations->SetInAt(1, Location::Any());
2110 locations->SetOut(Location::SameAsFirstInput());
2111 break;
2112 }
2113 case Primitive::kPrimLong: {
2114 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002115 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2116 if (locations->InAt(1).IsConstant()) {
2117 // Can use 3 operand multiply.
2118 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2119 } else {
2120 locations->SetOut(Location::SameAsFirstInput());
2121 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002122 break;
2123 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002124 case Primitive::kPrimFloat:
2125 case Primitive::kPrimDouble: {
2126 locations->SetInAt(0, Location::RequiresFpuRegister());
2127 locations->SetInAt(1, Location::RequiresFpuRegister());
2128 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002129 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002130 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002131
2132 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002133 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002134 }
2135}
2136
2137void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2138 LocationSummary* locations = mul->GetLocations();
2139 Location first = locations->InAt(0);
2140 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002141 switch (mul->GetResultType()) {
2142 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002143 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002144 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002145 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002146 } else if (second.IsConstant()) {
2147 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002148 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002149 } else {
2150 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002151 __ imull(first.AsRegister<CpuRegister>(),
2152 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002153 }
2154 break;
2155 }
2156 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002157 if (second.IsConstant()) {
2158 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2159 DCHECK(IsInt<32>(value));
2160 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2161 first.AsRegister<CpuRegister>(),
2162 Immediate(static_cast<int32_t>(value)));
2163 } else {
2164 DCHECK(first.Equals(locations->Out()));
2165 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2166 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002167 break;
2168 }
2169
Calin Juravleb5bfa962014-10-21 18:02:24 +01002170 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002171 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002172 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002173 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002174 }
2175
2176 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002177 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002178 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002179 break;
2180 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002181
2182 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002183 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002184 }
2185}
2186
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002187void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2188 uint32_t stack_adjustment, bool is_float) {
2189 if (source.IsStackSlot()) {
2190 DCHECK(is_float);
2191 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2192 } else if (source.IsDoubleStackSlot()) {
2193 DCHECK(!is_float);
2194 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2195 } else {
2196 // Write the value to the temporary location on the stack and load to FP stack.
2197 if (is_float) {
2198 Location stack_temp = Location::StackSlot(temp_offset);
2199 codegen_->Move(stack_temp, source);
2200 __ flds(Address(CpuRegister(RSP), temp_offset));
2201 } else {
2202 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2203 codegen_->Move(stack_temp, source);
2204 __ fldl(Address(CpuRegister(RSP), temp_offset));
2205 }
2206 }
2207}
2208
2209void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2210 Primitive::Type type = rem->GetResultType();
2211 bool is_float = type == Primitive::kPrimFloat;
2212 size_t elem_size = Primitive::ComponentSize(type);
2213 LocationSummary* locations = rem->GetLocations();
2214 Location first = locations->InAt(0);
2215 Location second = locations->InAt(1);
2216 Location out = locations->Out();
2217
2218 // Create stack space for 2 elements.
2219 // TODO: enhance register allocator to ask for stack temporaries.
2220 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2221
2222 // Load the values to the FP stack in reverse order, using temporaries if needed.
2223 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2224 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2225
2226 // Loop doing FPREM until we stabilize.
2227 Label retry;
2228 __ Bind(&retry);
2229 __ fprem();
2230
2231 // Move FP status to AX.
2232 __ fstsw();
2233
2234 // And see if the argument reduction is complete. This is signaled by the
2235 // C2 FPU flag bit set to 0.
2236 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2237 __ j(kNotEqual, &retry);
2238
2239 // We have settled on the final value. Retrieve it into an XMM register.
2240 // Store FP top of stack to real stack.
2241 if (is_float) {
2242 __ fsts(Address(CpuRegister(RSP), 0));
2243 } else {
2244 __ fstl(Address(CpuRegister(RSP), 0));
2245 }
2246
2247 // Pop the 2 items from the FP stack.
2248 __ fucompp();
2249
2250 // Load the value from the stack into an XMM register.
2251 DCHECK(out.IsFpuRegister()) << out;
2252 if (is_float) {
2253 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2254 } else {
2255 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2256 }
2257
2258 // And remove the temporary stack space we allocated.
2259 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2260}
2261
Calin Juravlebacfec32014-11-14 15:54:36 +00002262void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2263 DCHECK(instruction->IsDiv() || instruction->IsRem());
2264 Primitive::Type type = instruction->GetResultType();
2265 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2266
2267 bool is_div = instruction->IsDiv();
2268 LocationSummary* locations = instruction->GetLocations();
2269
Roland Levillain271ab9c2014-11-27 15:23:57 +00002270 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2271 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002272
Roland Levillain271ab9c2014-11-27 15:23:57 +00002273 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002274 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2275
2276 SlowPathCodeX86_64* slow_path =
2277 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2278 out_reg.AsRegister(), type, is_div);
2279 codegen_->AddSlowPath(slow_path);
2280
2281 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2282 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2283 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002284 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002285 __ cmpl(second_reg, Immediate(-1));
2286 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002287 // edx:eax <- sign-extended of eax
2288 __ cdq();
2289 // eax = quotient, edx = remainder
2290 __ idivl(second_reg);
2291 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002292 __ cmpq(second_reg, Immediate(-1));
2293 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002294 // rdx:rax <- sign-extended of rax
2295 __ cqo();
2296 // rax = quotient, rdx = remainder
2297 __ idivq(second_reg);
2298 }
2299
2300 __ Bind(slow_path->GetExitLabel());
2301}
2302
Calin Juravle7c4954d2014-10-28 16:57:40 +00002303void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2304 LocationSummary* locations =
2305 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2306 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002307 case Primitive::kPrimInt:
2308 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002309 locations->SetInAt(0, Location::RegisterLocation(RAX));
2310 locations->SetInAt(1, Location::RequiresRegister());
2311 locations->SetOut(Location::SameAsFirstInput());
2312 // Intel uses edx:eax as the dividend.
2313 locations->AddTemp(Location::RegisterLocation(RDX));
2314 break;
2315 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002316
Calin Juravle7c4954d2014-10-28 16:57:40 +00002317 case Primitive::kPrimFloat:
2318 case Primitive::kPrimDouble: {
2319 locations->SetInAt(0, Location::RequiresFpuRegister());
2320 locations->SetInAt(1, Location::RequiresFpuRegister());
2321 locations->SetOut(Location::SameAsFirstInput());
2322 break;
2323 }
2324
2325 default:
2326 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2327 }
2328}
2329
2330void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2331 LocationSummary* locations = div->GetLocations();
2332 Location first = locations->InAt(0);
2333 Location second = locations->InAt(1);
2334 DCHECK(first.Equals(locations->Out()));
2335
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002336 Primitive::Type type = div->GetResultType();
2337 switch (type) {
2338 case Primitive::kPrimInt:
2339 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002340 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002341 break;
2342 }
2343
Calin Juravle7c4954d2014-10-28 16:57:40 +00002344 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002345 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002346 break;
2347 }
2348
2349 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002350 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002351 break;
2352 }
2353
2354 default:
2355 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2356 }
2357}
2358
Calin Juravlebacfec32014-11-14 15:54:36 +00002359void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002360 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002361 LocationSummary* locations =
2362 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002363
2364 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002365 case Primitive::kPrimInt:
2366 case Primitive::kPrimLong: {
2367 locations->SetInAt(0, Location::RegisterLocation(RAX));
2368 locations->SetInAt(1, Location::RequiresRegister());
2369 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2370 locations->SetOut(Location::RegisterLocation(RDX));
2371 break;
2372 }
2373
2374 case Primitive::kPrimFloat:
2375 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002376 locations->SetInAt(0, Location::Any());
2377 locations->SetInAt(1, Location::Any());
2378 locations->SetOut(Location::RequiresFpuRegister());
2379 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002380 break;
2381 }
2382
2383 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002384 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002385 }
2386}
2387
2388void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2389 Primitive::Type type = rem->GetResultType();
2390 switch (type) {
2391 case Primitive::kPrimInt:
2392 case Primitive::kPrimLong: {
2393 GenerateDivRemIntegral(rem);
2394 break;
2395 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002396 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002397 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002398 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002399 break;
2400 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002401 default:
2402 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2403 }
2404}
2405
Calin Juravled0d48522014-11-04 16:40:20 +00002406void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2407 LocationSummary* locations =
2408 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2409 locations->SetInAt(0, Location::Any());
2410 if (instruction->HasUses()) {
2411 locations->SetOut(Location::SameAsFirstInput());
2412 }
2413}
2414
2415void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2416 SlowPathCodeX86_64* slow_path =
2417 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2418 codegen_->AddSlowPath(slow_path);
2419
2420 LocationSummary* locations = instruction->GetLocations();
2421 Location value = locations->InAt(0);
2422
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002423 switch (instruction->GetType()) {
2424 case Primitive::kPrimInt: {
2425 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002426 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002427 __ j(kEqual, slow_path->GetEntryLabel());
2428 } else if (value.IsStackSlot()) {
2429 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2430 __ j(kEqual, slow_path->GetEntryLabel());
2431 } else {
2432 DCHECK(value.IsConstant()) << value;
2433 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2434 __ jmp(slow_path->GetEntryLabel());
2435 }
2436 }
2437 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002438 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002439 case Primitive::kPrimLong: {
2440 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002441 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002442 __ j(kEqual, slow_path->GetEntryLabel());
2443 } else if (value.IsDoubleStackSlot()) {
2444 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2445 __ j(kEqual, slow_path->GetEntryLabel());
2446 } else {
2447 DCHECK(value.IsConstant()) << value;
2448 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2449 __ jmp(slow_path->GetEntryLabel());
2450 }
2451 }
2452 break;
2453 }
2454 default:
2455 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002456 }
Calin Juravled0d48522014-11-04 16:40:20 +00002457}
2458
Calin Juravle9aec02f2014-11-18 23:06:35 +00002459void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2460 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2461
2462 LocationSummary* locations =
2463 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2464
2465 switch (op->GetResultType()) {
2466 case Primitive::kPrimInt:
2467 case Primitive::kPrimLong: {
2468 locations->SetInAt(0, Location::RequiresRegister());
2469 // The shift count needs to be in CL.
2470 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2471 locations->SetOut(Location::SameAsFirstInput());
2472 break;
2473 }
2474 default:
2475 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2476 }
2477}
2478
2479void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2480 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2481
2482 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002483 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002484 Location second = locations->InAt(1);
2485
2486 switch (op->GetResultType()) {
2487 case Primitive::kPrimInt: {
2488 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002489 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002490 if (op->IsShl()) {
2491 __ shll(first_reg, second_reg);
2492 } else if (op->IsShr()) {
2493 __ sarl(first_reg, second_reg);
2494 } else {
2495 __ shrl(first_reg, second_reg);
2496 }
2497 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002498 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002499 if (op->IsShl()) {
2500 __ shll(first_reg, imm);
2501 } else if (op->IsShr()) {
2502 __ sarl(first_reg, imm);
2503 } else {
2504 __ shrl(first_reg, imm);
2505 }
2506 }
2507 break;
2508 }
2509 case Primitive::kPrimLong: {
2510 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002511 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002512 if (op->IsShl()) {
2513 __ shlq(first_reg, second_reg);
2514 } else if (op->IsShr()) {
2515 __ sarq(first_reg, second_reg);
2516 } else {
2517 __ shrq(first_reg, second_reg);
2518 }
2519 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002520 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002521 if (op->IsShl()) {
2522 __ shlq(first_reg, imm);
2523 } else if (op->IsShr()) {
2524 __ sarq(first_reg, imm);
2525 } else {
2526 __ shrq(first_reg, imm);
2527 }
2528 }
2529 break;
2530 }
2531 default:
2532 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2533 }
2534}
2535
2536void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2537 HandleShift(shl);
2538}
2539
2540void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2541 HandleShift(shl);
2542}
2543
2544void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2545 HandleShift(shr);
2546}
2547
2548void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2549 HandleShift(shr);
2550}
2551
2552void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2553 HandleShift(ushr);
2554}
2555
2556void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2557 HandleShift(ushr);
2558}
2559
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002560void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002561 LocationSummary* locations =
2562 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002563 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002564 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2565 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2566 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002567}
2568
2569void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2570 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002571 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002572 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2573
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002574 __ gs()->call(
2575 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002576
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002577 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002578 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002579}
2580
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002581void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2582 LocationSummary* locations =
2583 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2584 InvokeRuntimeCallingConvention calling_convention;
2585 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002586 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002587 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002588 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002589}
2590
2591void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2592 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002593 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002594 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2595
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002596 __ gs()->call(
2597 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002598
2599 DCHECK(!codegen_->IsLeafMethod());
2600 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2601}
2602
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002603void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002604 LocationSummary* locations =
2605 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002606 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2607 if (location.IsStackSlot()) {
2608 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2609 } else if (location.IsDoubleStackSlot()) {
2610 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2611 }
2612 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002613}
2614
2615void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2616 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002617 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002618}
2619
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002620void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002621 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002622 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002623 locations->SetInAt(0, Location::RequiresRegister());
2624 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002625}
2626
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002627void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2628 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002629 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2630 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002631 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002632 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002633 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002634 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002635 break;
2636
2637 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002638 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002639 break;
2640
2641 default:
2642 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2643 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002644}
2645
2646void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002647 LocationSummary* locations =
2648 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002649 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2650 locations->SetInAt(i, Location::Any());
2651 }
2652 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002653}
2654
2655void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002656 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002657 LOG(FATAL) << "Unimplemented";
2658}
2659
Calin Juravle52c48962014-12-16 17:02:57 +00002660void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2661 /*
2662 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2663 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2664 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2665 */
2666 switch (kind) {
2667 case MemBarrierKind::kAnyAny: {
2668 __ mfence();
2669 break;
2670 }
2671 case MemBarrierKind::kAnyStore:
2672 case MemBarrierKind::kLoadAny:
2673 case MemBarrierKind::kStoreStore: {
2674 // nop
2675 break;
2676 }
2677 default:
2678 LOG(FATAL) << "Unexpected memory barier " << kind;
2679 }
2680}
2681
2682void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2683 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2684
Nicolas Geoffray39468442014-09-02 15:17:15 +01002685 LocationSummary* locations =
2686 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002687 locations->SetInAt(0, Location::RequiresRegister());
2688 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2689}
2690
2691void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2692 const FieldInfo& field_info) {
2693 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2694
2695 LocationSummary* locations = instruction->GetLocations();
2696 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2697 Location out = locations->Out();
2698 bool is_volatile = field_info.IsVolatile();
2699 Primitive::Type field_type = field_info.GetFieldType();
2700 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2701
2702 switch (field_type) {
2703 case Primitive::kPrimBoolean: {
2704 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2705 break;
2706 }
2707
2708 case Primitive::kPrimByte: {
2709 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2710 break;
2711 }
2712
2713 case Primitive::kPrimShort: {
2714 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2715 break;
2716 }
2717
2718 case Primitive::kPrimChar: {
2719 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2720 break;
2721 }
2722
2723 case Primitive::kPrimInt:
2724 case Primitive::kPrimNot: {
2725 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2726 break;
2727 }
2728
2729 case Primitive::kPrimLong: {
2730 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2731 break;
2732 }
2733
2734 case Primitive::kPrimFloat: {
2735 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2736 break;
2737 }
2738
2739 case Primitive::kPrimDouble: {
2740 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2741 break;
2742 }
2743
2744 case Primitive::kPrimVoid:
2745 LOG(FATAL) << "Unreachable type " << field_type;
2746 UNREACHABLE();
2747 }
2748
Calin Juravle77520bc2015-01-12 18:45:46 +00002749 codegen_->MaybeRecordImplicitNullCheck(instruction);
2750
Calin Juravle52c48962014-12-16 17:02:57 +00002751 if (is_volatile) {
2752 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2753 }
2754}
2755
2756void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2757 const FieldInfo& field_info) {
2758 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2759
2760 LocationSummary* locations =
2761 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002762 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002763 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2764
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002765 locations->SetInAt(0, Location::RequiresRegister());
2766 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002767 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002768 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002769 locations->AddTemp(Location::RequiresRegister());
2770 locations->AddTemp(Location::RequiresRegister());
2771 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002772}
2773
Calin Juravle52c48962014-12-16 17:02:57 +00002774void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2775 const FieldInfo& field_info) {
2776 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2777
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002778 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002779 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2780 Location value = locations->InAt(1);
2781 bool is_volatile = field_info.IsVolatile();
2782 Primitive::Type field_type = field_info.GetFieldType();
2783 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2784
2785 if (is_volatile) {
2786 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2787 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002788
2789 switch (field_type) {
2790 case Primitive::kPrimBoolean:
2791 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002792 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002793 break;
2794 }
2795
2796 case Primitive::kPrimShort:
2797 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002798 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002799 break;
2800 }
2801
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002802 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002803 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002804 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002805 break;
2806 }
2807
2808 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002809 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002810 break;
2811 }
2812
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002813 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002814 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002815 break;
2816 }
2817
2818 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002819 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002820 break;
2821 }
2822
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002823 case Primitive::kPrimVoid:
2824 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002825 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002826 }
Calin Juravle52c48962014-12-16 17:02:57 +00002827
Calin Juravle77520bc2015-01-12 18:45:46 +00002828 codegen_->MaybeRecordImplicitNullCheck(instruction);
2829
2830 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2831 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2832 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2833 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2834 }
2835
Calin Juravle52c48962014-12-16 17:02:57 +00002836 if (is_volatile) {
2837 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2838 }
2839}
2840
2841void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2842 HandleFieldSet(instruction, instruction->GetFieldInfo());
2843}
2844
2845void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2846 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002847}
2848
2849void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002850 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002851}
2852
2853void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002854 HandleFieldGet(instruction, instruction->GetFieldInfo());
2855}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002856
Calin Juravle52c48962014-12-16 17:02:57 +00002857void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2858 HandleFieldGet(instruction);
2859}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002860
Calin Juravle52c48962014-12-16 17:02:57 +00002861void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2862 HandleFieldGet(instruction, instruction->GetFieldInfo());
2863}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002864
Calin Juravle52c48962014-12-16 17:02:57 +00002865void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2866 HandleFieldSet(instruction, instruction->GetFieldInfo());
2867}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002868
Calin Juravle52c48962014-12-16 17:02:57 +00002869void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2870 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002871}
2872
2873void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002874 LocationSummary* locations =
2875 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002876 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2877 ? Location::RequiresRegister()
2878 : Location::Any();
2879 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002880 if (instruction->HasUses()) {
2881 locations->SetOut(Location::SameAsFirstInput());
2882 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002883}
2884
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002885void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002886 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2887 return;
2888 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002889 LocationSummary* locations = instruction->GetLocations();
2890 Location obj = locations->InAt(0);
2891
2892 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2893 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2894}
2895
2896void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002897 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002898 codegen_->AddSlowPath(slow_path);
2899
2900 LocationSummary* locations = instruction->GetLocations();
2901 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002902
2903 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002904 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002905 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002906 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002907 } else {
2908 DCHECK(obj.IsConstant()) << obj;
2909 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2910 __ jmp(slow_path->GetEntryLabel());
2911 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002912 }
2913 __ j(kEqual, slow_path->GetEntryLabel());
2914}
2915
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002916void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2917 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2918 GenerateImplicitNullCheck(instruction);
2919 } else {
2920 GenerateExplicitNullCheck(instruction);
2921 }
2922}
2923
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002924void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002925 LocationSummary* locations =
2926 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002927 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002928 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002929 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2930 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002931}
2932
2933void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2934 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002935 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002936 Location index = locations->InAt(1);
2937
2938 switch (instruction->GetType()) {
2939 case Primitive::kPrimBoolean: {
2940 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002941 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002942 if (index.IsConstant()) {
2943 __ movzxb(out, Address(obj,
2944 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2945 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002946 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002947 }
2948 break;
2949 }
2950
2951 case Primitive::kPrimByte: {
2952 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002953 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002954 if (index.IsConstant()) {
2955 __ movsxb(out, Address(obj,
2956 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2957 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002958 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002959 }
2960 break;
2961 }
2962
2963 case Primitive::kPrimShort: {
2964 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002965 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002966 if (index.IsConstant()) {
2967 __ movsxw(out, Address(obj,
2968 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2969 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002970 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002971 }
2972 break;
2973 }
2974
2975 case Primitive::kPrimChar: {
2976 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002977 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002978 if (index.IsConstant()) {
2979 __ movzxw(out, Address(obj,
2980 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2981 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002982 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002983 }
2984 break;
2985 }
2986
2987 case Primitive::kPrimInt:
2988 case Primitive::kPrimNot: {
2989 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2990 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002991 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002992 if (index.IsConstant()) {
2993 __ movl(out, Address(obj,
2994 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2995 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002996 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002997 }
2998 break;
2999 }
3000
3001 case Primitive::kPrimLong: {
3002 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003003 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003004 if (index.IsConstant()) {
3005 __ movq(out, Address(obj,
3006 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3007 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003008 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003009 }
3010 break;
3011 }
3012
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003013 case Primitive::kPrimFloat: {
3014 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003015 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003016 if (index.IsConstant()) {
3017 __ movss(out, Address(obj,
3018 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3019 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003020 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003021 }
3022 break;
3023 }
3024
3025 case Primitive::kPrimDouble: {
3026 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003027 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003028 if (index.IsConstant()) {
3029 __ movsd(out, Address(obj,
3030 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3031 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003032 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003033 }
3034 break;
3035 }
3036
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003037 case Primitive::kPrimVoid:
3038 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003039 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003040 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003041 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003042}
3043
3044void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003045 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003046
3047 bool needs_write_barrier =
3048 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3049 bool needs_runtime_call = instruction->NeedsTypeCheck();
3050
Nicolas Geoffray39468442014-09-02 15:17:15 +01003051 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003052 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3053 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003054 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003055 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3056 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3057 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003058 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003059 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003060 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003061 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3062 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003063 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003064 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003065 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3066 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003067 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003068 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003069 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003070
3071 if (needs_write_barrier) {
3072 // Temporary registers for the write barrier.
3073 locations->AddTemp(Location::RequiresRegister());
3074 locations->AddTemp(Location::RequiresRegister());
3075 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003076 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003077}
3078
3079void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3080 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003081 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003082 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003083 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003084 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003085 bool needs_runtime_call = locations->WillCall();
3086 bool needs_write_barrier =
3087 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003088
3089 switch (value_type) {
3090 case Primitive::kPrimBoolean:
3091 case Primitive::kPrimByte: {
3092 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003093 if (index.IsConstant()) {
3094 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003095 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003096 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003097 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003098 __ movb(Address(obj, offset),
3099 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003100 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003101 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003102 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003103 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3104 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003105 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003106 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003107 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3108 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003109 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003110 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003111 break;
3112 }
3113
3114 case Primitive::kPrimShort:
3115 case Primitive::kPrimChar: {
3116 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003117 if (index.IsConstant()) {
3118 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003119 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003120 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003121 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003122 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003123 __ movw(Address(obj, offset),
3124 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003125 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003126 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003127 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003128 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003129 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3130 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003131 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003132 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003133 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003134 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3135 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003136 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003137 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003138 break;
3139 }
3140
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003141 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003142 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003143 if (!needs_runtime_call) {
3144 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3145 if (index.IsConstant()) {
3146 size_t offset =
3147 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3148 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003149 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003150 } else {
3151 DCHECK(value.IsConstant()) << value;
3152 __ movl(Address(obj, offset),
3153 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3154 }
3155 } else {
3156 DCHECK(index.IsRegister()) << index;
3157 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003158 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3159 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003160 } else {
3161 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003162 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003163 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3164 }
3165 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003166 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003167 if (needs_write_barrier) {
3168 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003169 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3170 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3171 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003172 }
3173 } else {
3174 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003175 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3176 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003177 DCHECK(!codegen_->IsLeafMethod());
3178 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3179 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003180 break;
3181 }
3182
3183 case Primitive::kPrimLong: {
3184 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003185 if (index.IsConstant()) {
3186 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003187 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003188 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003189 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003190 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003191 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3192 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003193 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003194 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003195 break;
3196 }
3197
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003198 case Primitive::kPrimFloat: {
3199 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3200 if (index.IsConstant()) {
3201 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3202 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003203 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003204 } else {
3205 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003206 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3207 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003208 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003209 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003210 break;
3211 }
3212
3213 case Primitive::kPrimDouble: {
3214 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3215 if (index.IsConstant()) {
3216 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3217 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003218 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003219 } else {
3220 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003221 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3222 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003223 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003224 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003225 break;
3226 }
3227
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003228 case Primitive::kPrimVoid:
3229 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003230 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003231 }
3232}
3233
3234void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003235 LocationSummary* locations =
3236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003237 locations->SetInAt(0, Location::RequiresRegister());
3238 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003239}
3240
3241void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3242 LocationSummary* locations = instruction->GetLocations();
3243 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003244 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3245 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003246 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003247 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003248}
3249
3250void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003251 LocationSummary* locations =
3252 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003253 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003254 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003255 if (instruction->HasUses()) {
3256 locations->SetOut(Location::SameAsFirstInput());
3257 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003258}
3259
3260void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3261 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003262 Location index_loc = locations->InAt(0);
3263 Location length_loc = locations->InAt(1);
3264 SlowPathCodeX86_64* slow_path =
3265 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003266 codegen_->AddSlowPath(slow_path);
3267
Mark Mendellf60c90b2015-03-04 15:12:59 -05003268 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3269 if (index_loc.IsConstant()) {
3270 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3271 __ cmpl(length, Immediate(value));
3272 } else {
3273 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3274 }
3275 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003276}
3277
3278void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3279 CpuRegister card,
3280 CpuRegister object,
3281 CpuRegister value) {
3282 Label is_null;
3283 __ testl(value, value);
3284 __ j(kEqual, &is_null);
3285 __ gs()->movq(card, Address::Absolute(
3286 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3287 __ movq(temp, object);
3288 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3289 __ movb(Address(temp, card, TIMES_1, 0), card);
3290 __ Bind(&is_null);
3291}
3292
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003293void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3294 temp->SetLocations(nullptr);
3295}
3296
3297void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3298 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003299 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003300}
3301
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003302void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003303 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003304 LOG(FATAL) << "Unimplemented";
3305}
3306
3307void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003308 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3309}
3310
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003311void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3312 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3313}
3314
3315void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003316 HBasicBlock* block = instruction->GetBlock();
3317 if (block->GetLoopInformation() != nullptr) {
3318 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3319 // The back edge will generate the suspend check.
3320 return;
3321 }
3322 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3323 // The goto will generate the suspend check.
3324 return;
3325 }
3326 GenerateSuspendCheck(instruction, nullptr);
3327}
3328
3329void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3330 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003331 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003332 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003333 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003334 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003335 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003336 if (successor == nullptr) {
3337 __ j(kNotEqual, slow_path->GetEntryLabel());
3338 __ Bind(slow_path->GetReturnLabel());
3339 } else {
3340 __ j(kEqual, codegen_->GetLabelOf(successor));
3341 __ jmp(slow_path->GetEntryLabel());
3342 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003343}
3344
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003345X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3346 return codegen_->GetAssembler();
3347}
3348
3349void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3350 MoveOperands* move = moves_.Get(index);
3351 Location source = move->GetSource();
3352 Location destination = move->GetDestination();
3353
3354 if (source.IsRegister()) {
3355 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003356 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003357 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003358 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003359 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003360 } else {
3361 DCHECK(destination.IsDoubleStackSlot());
3362 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003363 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003364 }
3365 } else if (source.IsStackSlot()) {
3366 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003367 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003368 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003369 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003370 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003371 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003372 } else {
3373 DCHECK(destination.IsStackSlot());
3374 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3375 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3376 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003377 } else if (source.IsDoubleStackSlot()) {
3378 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003379 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003380 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003381 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003382 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3383 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003384 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003385 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003386 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3387 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3388 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003389 } else if (source.IsConstant()) {
3390 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003391 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3392 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003393 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003394 if (value == 0) {
3395 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3396 } else {
3397 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3398 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003399 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003400 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003401 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003402 }
3403 } else if (constant->IsLongConstant()) {
3404 int64_t value = constant->AsLongConstant()->GetValue();
3405 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003406 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003407 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003408 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003409 __ movq(CpuRegister(TMP), Immediate(value));
3410 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3411 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003412 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003413 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003414 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003415 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003416 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003417 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3418 if (value == 0) {
3419 // easy FP 0.0.
3420 __ xorps(dest, dest);
3421 } else {
3422 __ movl(CpuRegister(TMP), imm);
3423 __ movd(dest, CpuRegister(TMP));
3424 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003425 } else {
3426 DCHECK(destination.IsStackSlot()) << destination;
3427 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3428 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003429 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003430 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003431 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003432 int64_t value = bit_cast<int64_t, double>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003433 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003434 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003435 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3436 if (value == 0) {
3437 __ xorpd(dest, dest);
3438 } else {
3439 __ movq(CpuRegister(TMP), imm);
3440 __ movd(dest, CpuRegister(TMP));
3441 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003442 } else {
3443 DCHECK(destination.IsDoubleStackSlot()) << destination;
3444 __ movq(CpuRegister(TMP), imm);
3445 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3446 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003447 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003448 } else if (source.IsFpuRegister()) {
3449 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003450 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003451 } else if (destination.IsStackSlot()) {
3452 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003453 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003454 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003455 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003456 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003457 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003458 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003459 }
3460}
3461
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003462void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003463 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003464 __ movl(Address(CpuRegister(RSP), mem), reg);
3465 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003466}
3467
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003468void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003469 ScratchRegisterScope ensure_scratch(
3470 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3471
3472 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3473 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3474 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3475 Address(CpuRegister(RSP), mem2 + stack_offset));
3476 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3477 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3478 CpuRegister(ensure_scratch.GetRegister()));
3479}
3480
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003481void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3482 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3483 __ movq(Address(CpuRegister(RSP), mem), reg);
3484 __ movq(reg, CpuRegister(TMP));
3485}
3486
3487void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3488 ScratchRegisterScope ensure_scratch(
3489 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3490
3491 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3492 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3493 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3494 Address(CpuRegister(RSP), mem2 + stack_offset));
3495 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3496 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3497 CpuRegister(ensure_scratch.GetRegister()));
3498}
3499
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003500void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3501 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3502 __ movss(Address(CpuRegister(RSP), mem), reg);
3503 __ movd(reg, CpuRegister(TMP));
3504}
3505
3506void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3507 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3508 __ movsd(Address(CpuRegister(RSP), mem), reg);
3509 __ movd(reg, CpuRegister(TMP));
3510}
3511
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003512void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3513 MoveOperands* move = moves_.Get(index);
3514 Location source = move->GetSource();
3515 Location destination = move->GetDestination();
3516
3517 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003518 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003519 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003520 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003521 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003522 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003523 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003524 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3525 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003526 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003527 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003528 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003529 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3530 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003531 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003532 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3533 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3534 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003535 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003536 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003537 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003538 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003539 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003540 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003541 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003542 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003543 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003544 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003545 }
3546}
3547
3548
3549void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3550 __ pushq(CpuRegister(reg));
3551}
3552
3553
3554void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3555 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003556}
3557
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003558void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3559 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3560 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3561 Immediate(mirror::Class::kStatusInitialized));
3562 __ j(kLess, slow_path->GetEntryLabel());
3563 __ Bind(slow_path->GetExitLabel());
3564 // No need for memory fence, thanks to the X86_64 memory model.
3565}
3566
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003567void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003568 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3569 ? LocationSummary::kCallOnSlowPath
3570 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003571 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003572 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003573 locations->SetOut(Location::RequiresRegister());
3574}
3575
3576void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003577 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003578 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003579 DCHECK(!cls->CanCallRuntime());
3580 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003581 codegen_->LoadCurrentMethod(out);
3582 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3583 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003584 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003585 codegen_->LoadCurrentMethod(out);
3586 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3587 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003588 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3589 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3590 codegen_->AddSlowPath(slow_path);
3591 __ testl(out, out);
3592 __ j(kEqual, slow_path->GetEntryLabel());
3593 if (cls->MustGenerateClinitCheck()) {
3594 GenerateClassInitializationCheck(slow_path, out);
3595 } else {
3596 __ Bind(slow_path->GetExitLabel());
3597 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003598 }
3599}
3600
3601void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3602 LocationSummary* locations =
3603 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3604 locations->SetInAt(0, Location::RequiresRegister());
3605 if (check->HasUses()) {
3606 locations->SetOut(Location::SameAsFirstInput());
3607 }
3608}
3609
3610void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003611 // We assume the class to not be null.
3612 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3613 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003614 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003615 GenerateClassInitializationCheck(slow_path,
3616 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003617}
3618
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003619void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3620 LocationSummary* locations =
3621 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3622 locations->SetOut(Location::RequiresRegister());
3623}
3624
3625void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3626 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3627 codegen_->AddSlowPath(slow_path);
3628
Roland Levillain271ab9c2014-11-27 15:23:57 +00003629 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003630 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003631 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3632 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003633 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3634 __ testl(out, out);
3635 __ j(kEqual, slow_path->GetEntryLabel());
3636 __ Bind(slow_path->GetExitLabel());
3637}
3638
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003639void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3640 LocationSummary* locations =
3641 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3642 locations->SetOut(Location::RequiresRegister());
3643}
3644
3645void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3646 Address address = Address::Absolute(
3647 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003648 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003649 __ gs()->movl(address, Immediate(0));
3650}
3651
3652void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
3653 LocationSummary* locations =
3654 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3655 InvokeRuntimeCallingConvention calling_convention;
3656 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3657}
3658
3659void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
3660 __ gs()->call(
3661 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3662 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3663}
3664
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003665void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003666 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3667 ? LocationSummary::kNoCall
3668 : LocationSummary::kCallOnSlowPath;
3669 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3670 locations->SetInAt(0, Location::RequiresRegister());
3671 locations->SetInAt(1, Location::Any());
3672 locations->SetOut(Location::RequiresRegister());
3673}
3674
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003675void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003676 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003677 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003678 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003679 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003680 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3681 Label done, zero;
3682 SlowPathCodeX86_64* slow_path = nullptr;
3683
3684 // Return 0 if `obj` is null.
3685 // TODO: avoid this check if we know obj is not null.
3686 __ testl(obj, obj);
3687 __ j(kEqual, &zero);
3688 // Compare the class of `obj` with `cls`.
3689 __ movl(out, Address(obj, class_offset));
3690 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003691 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003692 } else {
3693 DCHECK(cls.IsStackSlot()) << cls;
3694 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3695 }
3696 if (instruction->IsClassFinal()) {
3697 // Classes must be equal for the instanceof to succeed.
3698 __ j(kNotEqual, &zero);
3699 __ movl(out, Immediate(1));
3700 __ jmp(&done);
3701 } else {
3702 // If the classes are not equal, we go into a slow path.
3703 DCHECK(locations->OnlyCallsOnSlowPath());
3704 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003705 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003706 codegen_->AddSlowPath(slow_path);
3707 __ j(kNotEqual, slow_path->GetEntryLabel());
3708 __ movl(out, Immediate(1));
3709 __ jmp(&done);
3710 }
3711 __ Bind(&zero);
3712 __ movl(out, Immediate(0));
3713 if (slow_path != nullptr) {
3714 __ Bind(slow_path->GetExitLabel());
3715 }
3716 __ Bind(&done);
3717}
3718
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003719void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3720 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3721 instruction, LocationSummary::kCallOnSlowPath);
3722 locations->SetInAt(0, Location::RequiresRegister());
3723 locations->SetInAt(1, Location::Any());
3724 locations->AddTemp(Location::RequiresRegister());
3725}
3726
3727void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3728 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003729 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003730 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003731 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003732 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3733 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3734 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3735 codegen_->AddSlowPath(slow_path);
3736
3737 // TODO: avoid this check if we know obj is not null.
3738 __ testl(obj, obj);
3739 __ j(kEqual, slow_path->GetExitLabel());
3740 // Compare the class of `obj` with `cls`.
3741 __ movl(temp, Address(obj, class_offset));
3742 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003743 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003744 } else {
3745 DCHECK(cls.IsStackSlot()) << cls;
3746 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3747 }
3748 // Classes must be equal for the checkcast to succeed.
3749 __ j(kNotEqual, slow_path->GetEntryLabel());
3750 __ Bind(slow_path->GetExitLabel());
3751}
3752
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003753void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3754 LocationSummary* locations =
3755 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3756 InvokeRuntimeCallingConvention calling_convention;
3757 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3758}
3759
3760void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3761 __ gs()->call(Address::Absolute(instruction->IsEnter()
3762 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3763 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3764 true));
3765 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3766}
3767
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003768void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3769void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3770void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3771
3772void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3773 LocationSummary* locations =
3774 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3775 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3776 || instruction->GetResultType() == Primitive::kPrimLong);
3777 locations->SetInAt(0, Location::RequiresRegister());
3778 if (instruction->GetType() == Primitive::kPrimInt) {
3779 locations->SetInAt(1, Location::Any());
3780 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003781 // We can handle 32 bit constants.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003782 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003783 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003784 }
3785 locations->SetOut(Location::SameAsFirstInput());
3786}
3787
3788void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3789 HandleBitwiseOperation(instruction);
3790}
3791
3792void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3793 HandleBitwiseOperation(instruction);
3794}
3795
3796void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3797 HandleBitwiseOperation(instruction);
3798}
3799
3800void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3801 LocationSummary* locations = instruction->GetLocations();
3802 Location first = locations->InAt(0);
3803 Location second = locations->InAt(1);
3804 DCHECK(first.Equals(locations->Out()));
3805
3806 if (instruction->GetResultType() == Primitive::kPrimInt) {
3807 if (second.IsRegister()) {
3808 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003809 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003810 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003812 } else {
3813 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003814 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003815 }
3816 } else if (second.IsConstant()) {
3817 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3818 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003819 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003820 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003821 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003822 } else {
3823 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003824 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003825 }
3826 } else {
3827 Address address(CpuRegister(RSP), second.GetStackIndex());
3828 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003829 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003830 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003831 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003832 } else {
3833 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003834 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003835 }
3836 }
3837 } else {
3838 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003839 CpuRegister first_reg = first.AsRegister<CpuRegister>();
3840 bool second_is_constant = false;
3841 int64_t value = 0;
3842 if (second.IsConstant()) {
3843 second_is_constant = true;
3844 value = second.GetConstant()->AsLongConstant()->GetValue();
3845 DCHECK(IsInt<32>(value));
3846 }
3847
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003848 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003849 if (second_is_constant) {
3850 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
3851 } else {
3852 __ andq(first_reg, second.AsRegister<CpuRegister>());
3853 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003854 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003855 if (second_is_constant) {
3856 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
3857 } else {
3858 __ orq(first_reg, second.AsRegister<CpuRegister>());
3859 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003860 } else {
3861 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003862 if (second_is_constant) {
3863 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
3864 } else {
3865 __ xorq(first_reg, second.AsRegister<CpuRegister>());
3866 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003867 }
3868 }
3869}
3870
Calin Juravleb1498f62015-02-16 13:13:29 +00003871void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
3872 // Nothing to do, this should be removed during prepare for register allocator.
3873 UNUSED(instruction);
3874 LOG(FATAL) << "Unreachable";
3875}
3876
3877void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
3878 // Nothing to do, this should be removed during prepare for register allocator.
3879 UNUSED(instruction);
3880 LOG(FATAL) << "Unreachable";
3881}
3882
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003883} // namespace x86_64
3884} // namespace art