blob: aac4c3aaefd2080e6e8c7460591a6acec9435a7d [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
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100317#undef __
318#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
319
Dave Allison20dfc792014-06-16 20:44:29 -0700320inline Condition X86_64Condition(IfCondition cond) {
321 switch (cond) {
322 case kCondEQ: return kEqual;
323 case kCondNE: return kNotEqual;
324 case kCondLT: return kLess;
325 case kCondLE: return kLessEqual;
326 case kCondGT: return kGreater;
327 case kCondGE: return kGreaterEqual;
328 default:
329 LOG(FATAL) << "Unknown if condition";
330 }
331 return kEqual;
332}
333
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800334void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
335 CpuRegister temp) {
336 // All registers are assumed to be correctly set up.
337
338 // TODO: Implement all kinds of calls:
339 // 1) boot -> boot
340 // 2) app -> boot
341 // 3) app -> app
342 //
343 // Currently we implement the app -> app logic, which looks up in the resolve cache.
344
345 // temp = method;
346 LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000347 if (!invoke->IsRecursive()) {
348 // temp = temp->dex_cache_resolved_methods_;
349 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
350 // temp = temp[index_in_cache]
351 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
352 // (temp + offset_of_quick_compiled_code)()
353 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
354 kX86_64WordSize).SizeValue()));
355 } else {
356 __ call(&frame_entry_label_);
357 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800358
359 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800360}
361
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100362void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
363 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
364}
365
366void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
367 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
368}
369
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100370size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
371 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
372 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100373}
374
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100375size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
376 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
377 return kX86_64WordSize;
378}
379
380size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
381 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
382 return kX86_64WordSize;
383}
384
385size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
386 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
387 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100388}
389
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000390static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000391// Use a fake return address register to mimic Quick.
392static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400393CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
394 const X86_64InstructionSetFeatures& isa_features,
395 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000396 : CodeGenerator(graph,
397 kNumberOfCpuRegisters,
398 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000399 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000400 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
401 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000402 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000403 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
404 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000405 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100406 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100407 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000408 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400409 move_resolver_(graph->GetArena(), this),
410 isa_features_(isa_features) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000411 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
412}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100413
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100414InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
415 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100416 : HGraphVisitor(graph),
417 assembler_(codegen->GetAssembler()),
418 codegen_(codegen) {}
419
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100420Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100421 switch (type) {
422 case Primitive::kPrimLong:
423 case Primitive::kPrimByte:
424 case Primitive::kPrimBoolean:
425 case Primitive::kPrimChar:
426 case Primitive::kPrimShort:
427 case Primitive::kPrimInt:
428 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100429 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100430 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100431 }
432
433 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100434 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100435 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100436 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100437 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100438
439 case Primitive::kPrimVoid:
440 LOG(FATAL) << "Unreachable type " << type;
441 }
442
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100443 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100444}
445
Nicolas Geoffray98893962015-01-21 12:32:32 +0000446void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100447 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100448 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100449
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000450 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100451 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000452
Nicolas Geoffray98893962015-01-21 12:32:32 +0000453 if (is_baseline) {
454 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
455 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
456 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000457 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
458 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
459 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000460 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100461}
462
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100463void CodeGeneratorX86_64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000464 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100465 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700466 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000467 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100468
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000469 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100470 __ testq(CpuRegister(RAX), Address(
471 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100472 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100473 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000474
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000475 if (HasEmptyFrame()) {
476 return;
477 }
478
Nicolas Geoffray98893962015-01-21 12:32:32 +0000479 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000480 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000481 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000482 __ pushq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000483 }
484 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100485
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000486 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
487 uint32_t xmm_spill_location = GetFpuSpillStart();
488 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100489
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000490 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
491 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
492 __ movsd(Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)),
493 XmmRegister(kFpuCalleeSaves[i]));
494 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100495 }
496
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100497 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
498}
499
500void CodeGeneratorX86_64::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000501 if (HasEmptyFrame()) {
502 return;
503 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000504 uint32_t xmm_spill_location = GetFpuSpillStart();
505 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
506 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
507 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
508 __ movsd(XmmRegister(kFpuCalleeSaves[i]),
509 Address(CpuRegister(RSP), xmm_spill_location + (xmm_spill_slot_size * i)));
510 }
511 }
512
513 __ addq(CpuRegister(RSP), Immediate(GetFrameSize() - GetCoreSpillSize()));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000514
515 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000516 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000517 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000518 __ popq(CpuRegister(reg));
Nicolas Geoffray98893962015-01-21 12:32:32 +0000519 }
520 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100521}
522
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100523void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
524 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100525}
526
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100527void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000528 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100529 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
530}
531
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100532Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
533 switch (load->GetType()) {
534 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100535 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
537 break;
538
539 case Primitive::kPrimInt:
540 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100541 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100542 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100543
544 case Primitive::kPrimBoolean:
545 case Primitive::kPrimByte:
546 case Primitive::kPrimChar:
547 case Primitive::kPrimShort:
548 case Primitive::kPrimVoid:
549 LOG(FATAL) << "Unexpected type " << load->GetType();
550 }
551
552 LOG(FATAL) << "Unreachable";
553 return Location();
554}
555
556void CodeGeneratorX86_64::Move(Location destination, Location source) {
557 if (source.Equals(destination)) {
558 return;
559 }
560 if (destination.IsRegister()) {
561 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000562 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100563 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000564 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100565 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000566 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100567 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100568 } else {
569 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000570 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100571 Address(CpuRegister(RSP), source.GetStackIndex()));
572 }
573 } else if (destination.IsFpuRegister()) {
574 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000575 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100576 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000577 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000579 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100580 Address(CpuRegister(RSP), source.GetStackIndex()));
581 } else {
582 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000583 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100584 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100585 }
586 } else if (destination.IsStackSlot()) {
587 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000589 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100590 } else if (source.IsFpuRegister()) {
591 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000592 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500593 } else if (source.IsConstant()) {
594 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000595 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500596 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100597 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500598 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000599 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
600 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100601 }
602 } else {
603 DCHECK(destination.IsDoubleStackSlot());
604 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100605 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000606 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100607 } else if (source.IsFpuRegister()) {
608 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000609 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500610 } else if (source.IsConstant()) {
611 HConstant* constant = source.GetConstant();
612 int64_t value = constant->AsLongConstant()->GetValue();
613 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000614 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500615 } else {
616 DCHECK(constant->IsLongConstant());
617 value = constant->AsLongConstant()->GetValue();
618 }
619 __ movq(CpuRegister(TMP), Immediate(value));
620 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100621 } else {
622 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000623 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
624 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100625 }
626 }
627}
628
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100629void CodeGeneratorX86_64::Move(HInstruction* instruction,
630 Location location,
631 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000632 LocationSummary* locations = instruction->GetLocations();
633 if (locations != nullptr && locations->Out().Equals(location)) {
634 return;
635 }
636
637 if (locations != nullptr && locations->Out().IsConstant()) {
638 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000639 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
640 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000641 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000642 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000643 } else if (location.IsStackSlot()) {
644 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
645 } else {
646 DCHECK(location.IsConstant());
647 DCHECK_EQ(location.GetConstant(), const_to_move);
648 }
649 } else if (const_to_move->IsLongConstant()) {
650 int64_t value = const_to_move->AsLongConstant()->GetValue();
651 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000652 __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
Calin Juravlea21f5982014-11-13 15:53:04 +0000653 } else if (location.IsDoubleStackSlot()) {
654 __ movq(CpuRegister(TMP), Immediate(value));
655 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
656 } else {
657 DCHECK(location.IsConstant());
658 DCHECK_EQ(location.GetConstant(), const_to_move);
659 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100660 }
Roland Levillain476df552014-10-09 17:51:36 +0100661 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100662 switch (instruction->GetType()) {
663 case Primitive::kPrimBoolean:
664 case Primitive::kPrimByte:
665 case Primitive::kPrimChar:
666 case Primitive::kPrimShort:
667 case Primitive::kPrimInt:
668 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100669 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100670 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
671 break;
672
673 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100674 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000675 Move(location,
676 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100677 break;
678
679 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100680 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100681 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000682 } else if (instruction->IsTemporary()) {
683 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
684 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100685 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100686 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100687 switch (instruction->GetType()) {
688 case Primitive::kPrimBoolean:
689 case Primitive::kPrimByte:
690 case Primitive::kPrimChar:
691 case Primitive::kPrimShort:
692 case Primitive::kPrimInt:
693 case Primitive::kPrimNot:
694 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100695 case Primitive::kPrimFloat:
696 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000697 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100698 break;
699
700 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100701 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100702 }
703 }
704}
705
706void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
707 got->SetLocations(nullptr);
708}
709
710void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
711 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100712 DCHECK(!successor->IsExitBlock());
713
714 HBasicBlock* block = got->GetBlock();
715 HInstruction* previous = got->GetPrevious();
716
717 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000718 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100719 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
720 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
721 return;
722 }
723
724 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
725 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
726 }
727 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100728 __ jmp(codegen_->GetLabelOf(successor));
729 }
730}
731
732void LocationsBuilderX86_64::VisitExit(HExit* exit) {
733 exit->SetLocations(nullptr);
734}
735
736void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700737 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100738}
739
Andreas Gampe0ba62732015-03-24 02:39:46 +0000740void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
741 LocationSummary* locations =
742 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
743 HInstruction* cond = if_instr->InputAt(0);
744 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
745 locations->SetInAt(0, Location::Any());
746 }
747}
748
749void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
750 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100751 if (cond->IsIntConstant()) {
752 // Constant condition, statically compared against 1.
753 int32_t cond_value = cond->AsIntConstant()->GetValue();
754 if (cond_value == 1) {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000755 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
756 if_instr->IfTrueSuccessor())) {
757 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100758 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100759 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100760 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100761 DCHECK_EQ(cond_value, 0);
762 }
763 } else {
764 bool materialized =
765 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
766 // Moves do not affect the eflags register, so if the condition is
767 // evaluated just before the if, we don't need to evaluate it
768 // again.
769 bool eflags_set = cond->IsCondition()
Andreas Gampe0ba62732015-03-24 02:39:46 +0000770 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100771 if (materialized) {
772 if (!eflags_set) {
773 // Materialized condition, compare against 0.
Andreas Gampe0ba62732015-03-24 02:39:46 +0000774 Location lhs = if_instr->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100775 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000776 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100777 } else {
778 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
779 Immediate(0));
780 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000781 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100782 } else {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000783 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
784 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100785 }
786 } else {
787 Location lhs = cond->GetLocations()->InAt(0);
788 Location rhs = cond->GetLocations()->InAt(1);
789 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000790 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100791 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000792 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000793 if (constant == 0) {
794 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
795 } else {
796 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
797 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100798 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000799 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100800 Address(CpuRegister(RSP), rhs.GetStackIndex()));
801 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000802 __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
803 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700804 }
Dave Allison20dfc792014-06-16 20:44:29 -0700805 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000806 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
807 if_instr->IfFalseSuccessor())) {
808 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100809 }
810}
811
812void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
813 local->SetLocations(nullptr);
814}
815
816void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
817 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
818}
819
820void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
821 local->SetLocations(nullptr);
822}
823
824void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
825 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700826 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100827}
828
829void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100830 LocationSummary* locations =
831 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100832 switch (store->InputAt(1)->GetType()) {
833 case Primitive::kPrimBoolean:
834 case Primitive::kPrimByte:
835 case Primitive::kPrimChar:
836 case Primitive::kPrimShort:
837 case Primitive::kPrimInt:
838 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100839 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
841 break;
842
843 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100844 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100845 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
846 break;
847
848 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100849 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100850 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100851}
852
853void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700854 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100855}
856
Dave Allison20dfc792014-06-16 20:44:29 -0700857void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100858 LocationSummary* locations =
859 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100860 locations->SetInAt(0, Location::RequiresRegister());
861 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100862 if (comp->NeedsMaterialization()) {
863 locations->SetOut(Location::RequiresRegister());
864 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865}
866
Dave Allison20dfc792014-06-16 20:44:29 -0700867void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
868 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100869 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000870 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100871 // Clear register: setcc only sets the low byte.
872 __ xorq(reg, reg);
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000873 Location lhs = locations->InAt(0);
874 Location rhs = locations->InAt(1);
875 if (rhs.IsRegister()) {
876 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
877 } else if (rhs.IsConstant()) {
Mingyao Yangdc5ac732015-02-25 11:28:05 -0800878 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000879 if (constant == 0) {
880 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
881 } else {
882 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
883 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100884 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +0000885 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100886 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100887 __ setcc(X86_64Condition(comp->GetCondition()), reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700888 }
889}
890
891void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
892 VisitCondition(comp);
893}
894
895void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
896 VisitCondition(comp);
897}
898
899void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
900 VisitCondition(comp);
901}
902
903void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
904 VisitCondition(comp);
905}
906
907void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
908 VisitCondition(comp);
909}
910
911void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
912 VisitCondition(comp);
913}
914
915void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
916 VisitCondition(comp);
917}
918
919void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
920 VisitCondition(comp);
921}
922
923void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
924 VisitCondition(comp);
925}
926
927void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
928 VisitCondition(comp);
929}
930
931void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
932 VisitCondition(comp);
933}
934
935void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
936 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100937}
938
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100939void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100940 LocationSummary* locations =
941 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +0000942 switch (compare->InputAt(0)->GetType()) {
943 case Primitive::kPrimLong: {
944 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400945 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +0000946 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
947 break;
948 }
949 case Primitive::kPrimFloat:
950 case Primitive::kPrimDouble: {
951 locations->SetInAt(0, Location::RequiresFpuRegister());
952 locations->SetInAt(1, Location::RequiresFpuRegister());
953 locations->SetOut(Location::RequiresRegister());
954 break;
955 }
956 default:
957 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
958 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100959}
960
961void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100962 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000963 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +0000964 Location left = locations->InAt(0);
965 Location right = locations->InAt(1);
966
967 Label less, greater, done;
968 Primitive::Type type = compare->InputAt(0)->GetType();
969 switch (type) {
970 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -0400971 CpuRegister left_reg = left.AsRegister<CpuRegister>();
972 if (right.IsConstant()) {
973 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
974 DCHECK(IsInt<32>(value));
975 if (value == 0) {
976 __ testq(left_reg, left_reg);
977 } else {
978 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
979 }
980 } else {
981 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
982 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100983 break;
Calin Juravleddb7df22014-11-25 20:56:51 +0000984 }
985 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000986 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000987 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
988 break;
989 }
990 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000991 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +0000992 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
993 break;
994 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100995 default:
Calin Juravleddb7df22014-11-25 20:56:51 +0000996 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100997 }
Calin Juravleddb7df22014-11-25 20:56:51 +0000998 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +0000999 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001000 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001001
Calin Juravle91debbc2014-11-26 19:01:09 +00001002 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001003 __ movl(out, Immediate(1));
1004 __ jmp(&done);
1005
1006 __ Bind(&less);
1007 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001008
1009 __ Bind(&done);
1010}
1011
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001012void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001013 LocationSummary* locations =
1014 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001015 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001016}
1017
1018void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001019 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001020 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001021}
1022
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001023void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1024 LocationSummary* locations =
1025 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1026 locations->SetOut(Location::ConstantLocation(constant));
1027}
1028
1029void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1030 // Will be generated at use site.
1031 UNUSED(constant);
1032}
1033
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001034void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001035 LocationSummary* locations =
1036 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001037 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001038}
1039
1040void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001041 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001042 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001043}
1044
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001045void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1046 LocationSummary* locations =
1047 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1048 locations->SetOut(Location::ConstantLocation(constant));
1049}
1050
1051void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1052 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001053 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001054}
1055
1056void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1057 LocationSummary* locations =
1058 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1059 locations->SetOut(Location::ConstantLocation(constant));
1060}
1061
1062void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1063 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001064 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001065}
1066
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001067void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1068 ret->SetLocations(nullptr);
1069}
1070
1071void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001072 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001073 codegen_->GenerateFrameExit();
1074 __ ret();
1075}
1076
1077void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001078 LocationSummary* locations =
1079 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001080 switch (ret->InputAt(0)->GetType()) {
1081 case Primitive::kPrimBoolean:
1082 case Primitive::kPrimByte:
1083 case Primitive::kPrimChar:
1084 case Primitive::kPrimShort:
1085 case Primitive::kPrimInt:
1086 case Primitive::kPrimNot:
1087 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001088 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001089 break;
1090
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001091 case Primitive::kPrimFloat:
1092 case Primitive::kPrimDouble:
1093 locations->SetInAt(0,
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001094 Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001095 break;
1096
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001097 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001099 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001100}
1101
1102void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1103 if (kIsDebugBuild) {
1104 switch (ret->InputAt(0)->GetType()) {
1105 case Primitive::kPrimBoolean:
1106 case Primitive::kPrimByte:
1107 case Primitive::kPrimChar:
1108 case Primitive::kPrimShort:
1109 case Primitive::kPrimInt:
1110 case Primitive::kPrimNot:
1111 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001112 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001113 break;
1114
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001115 case Primitive::kPrimFloat:
1116 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001117 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001118 XMM0);
1119 break;
1120
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001121 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001122 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001123 }
1124 }
1125 codegen_->GenerateFrameExit();
1126 __ ret();
1127}
1128
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001129Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
1130 switch (type) {
1131 case Primitive::kPrimBoolean:
1132 case Primitive::kPrimByte:
1133 case Primitive::kPrimChar:
1134 case Primitive::kPrimShort:
1135 case Primitive::kPrimInt:
1136 case Primitive::kPrimNot: {
1137 uint32_t index = gp_index_++;
1138 stack_index_++;
1139 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001140 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001141 } else {
1142 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1143 }
1144 }
1145
1146 case Primitive::kPrimLong: {
1147 uint32_t index = gp_index_;
1148 stack_index_ += 2;
1149 if (index < calling_convention.GetNumberOfRegisters()) {
1150 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001151 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001152 } else {
1153 gp_index_ += 2;
1154 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1155 }
1156 }
1157
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001158 case Primitive::kPrimFloat: {
1159 uint32_t index = fp_index_++;
1160 stack_index_++;
1161 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001162 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001163 } else {
1164 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1165 }
1166 }
1167
1168 case Primitive::kPrimDouble: {
1169 uint32_t index = fp_index_++;
1170 stack_index_ += 2;
1171 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001172 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001173 } else {
1174 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1175 }
1176 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001177
1178 case Primitive::kPrimVoid:
1179 LOG(FATAL) << "Unexpected parameter type " << type;
1180 break;
1181 }
1182 return Location();
1183}
1184
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001185void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001186 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001187 if (intrinsic.TryDispatch(invoke)) {
1188 return;
1189 }
1190
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001191 HandleInvoke(invoke);
1192}
1193
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001194static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1195 if (invoke->GetLocations()->Intrinsified()) {
1196 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1197 intrinsic.Dispatch(invoke);
1198 return true;
1199 }
1200 return false;
1201}
1202
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001203void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001204 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1205 return;
1206 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001207
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001208 codegen_->GenerateStaticOrDirectCall(
1209 invoke,
1210 invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001211 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001212}
1213
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001214void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001215 LocationSummary* locations =
1216 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001217 locations->AddTemp(Location::RegisterLocation(RDI));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001218
1219 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001220 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001221 HInstruction* input = invoke->InputAt(i);
1222 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1223 }
1224
1225 switch (invoke->GetType()) {
1226 case Primitive::kPrimBoolean:
1227 case Primitive::kPrimByte:
1228 case Primitive::kPrimChar:
1229 case Primitive::kPrimShort:
1230 case Primitive::kPrimInt:
1231 case Primitive::kPrimNot:
1232 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001233 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001234 break;
1235
1236 case Primitive::kPrimVoid:
1237 break;
1238
1239 case Primitive::kPrimDouble:
1240 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001241 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001242 break;
1243 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001244}
1245
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001246void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001247 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001248 if (intrinsic.TryDispatch(invoke)) {
1249 return;
1250 }
1251
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001252 HandleInvoke(invoke);
1253}
1254
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001255void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001256 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1257 return;
1258 }
1259
Roland Levillain271ab9c2014-11-27 15:23:57 +00001260 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001261 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1262 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1263 LocationSummary* locations = invoke->GetLocations();
1264 Location receiver = locations->InAt(0);
1265 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1266 // temp = object->GetClass();
1267 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001268 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1269 __ movl(temp, Address(temp, class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001270 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001271 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001272 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001273 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001274 // temp = temp->GetMethodAt(method_offset);
1275 __ movl(temp, Address(temp, method_offset));
1276 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001277 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001278 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001279
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001280 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001281 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001282}
1283
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001284void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1285 HandleInvoke(invoke);
1286 // Add the hidden argument.
1287 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1288}
1289
1290void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1291 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001292 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001293 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1294 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1295 LocationSummary* locations = invoke->GetLocations();
1296 Location receiver = locations->InAt(0);
1297 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1298
1299 // Set the hidden argument.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001300 __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001301 Immediate(invoke->GetDexMethodIndex()));
1302
1303 // temp = object->GetClass();
1304 if (receiver.IsStackSlot()) {
1305 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1306 __ movl(temp, Address(temp, class_offset));
1307 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001308 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001309 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001310 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001311 // temp = temp->GetImtEntryAt(method_offset);
1312 __ movl(temp, Address(temp, method_offset));
1313 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001314 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001315 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001316
1317 DCHECK(!codegen_->IsLeafMethod());
1318 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1319}
1320
Roland Levillain88cb1752014-10-20 16:36:47 +01001321void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1322 LocationSummary* locations =
1323 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1324 switch (neg->GetResultType()) {
1325 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001326 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001327 locations->SetInAt(0, Location::RequiresRegister());
1328 locations->SetOut(Location::SameAsFirstInput());
1329 break;
1330
Roland Levillain88cb1752014-10-20 16:36:47 +01001331 case Primitive::kPrimFloat:
1332 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001333 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001334 locations->SetOut(Location::SameAsFirstInput());
1335 locations->AddTemp(Location::RequiresRegister());
1336 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001337 break;
1338
1339 default:
1340 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1341 }
1342}
1343
1344void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1345 LocationSummary* locations = neg->GetLocations();
1346 Location out = locations->Out();
1347 Location in = locations->InAt(0);
1348 switch (neg->GetResultType()) {
1349 case Primitive::kPrimInt:
1350 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001351 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001352 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001353 break;
1354
1355 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001356 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001357 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001358 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001359 break;
1360
Roland Levillain5368c212014-11-27 15:03:41 +00001361 case Primitive::kPrimFloat: {
1362 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001363 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1364 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001365 // Implement float negation with an exclusive or with value
1366 // 0x80000000 (mask for bit 31, representing the sign of a
1367 // single-precision floating-point number).
1368 __ movq(constant, Immediate(INT64_C(0x80000000)));
1369 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001370 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001371 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001372 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001373
Roland Levillain5368c212014-11-27 15:03:41 +00001374 case Primitive::kPrimDouble: {
1375 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001376 CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
1377 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001378 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001379 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001380 // a double-precision floating-point number).
1381 __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
1382 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001383 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001384 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001385 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001386
1387 default:
1388 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1389 }
1390}
1391
Roland Levillaindff1f282014-11-05 14:15:05 +00001392void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1393 LocationSummary* locations =
1394 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1395 Primitive::Type result_type = conversion->GetResultType();
1396 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001397 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001398
David Brazdilb2bd1c52015-03-25 11:17:37 +00001399 // The Java language does not allow treating boolean as an integral type but
1400 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001401
Roland Levillaindff1f282014-11-05 14:15:05 +00001402 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001403 case Primitive::kPrimByte:
1404 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001405 case Primitive::kPrimBoolean:
1406 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001407 case Primitive::kPrimShort:
1408 case Primitive::kPrimInt:
1409 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001410 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001411 locations->SetInAt(0, Location::Any());
1412 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1413 break;
1414
1415 default:
1416 LOG(FATAL) << "Unexpected type conversion from " << input_type
1417 << " to " << result_type;
1418 }
1419 break;
1420
Roland Levillain01a8d712014-11-14 16:27:39 +00001421 case Primitive::kPrimShort:
1422 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001423 case Primitive::kPrimBoolean:
1424 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001425 case Primitive::kPrimByte:
1426 case Primitive::kPrimInt:
1427 case Primitive::kPrimChar:
1428 // Processing a Dex `int-to-short' instruction.
1429 locations->SetInAt(0, Location::Any());
1430 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1431 break;
1432
1433 default:
1434 LOG(FATAL) << "Unexpected type conversion from " << input_type
1435 << " to " << result_type;
1436 }
1437 break;
1438
Roland Levillain946e1432014-11-11 17:35:19 +00001439 case Primitive::kPrimInt:
1440 switch (input_type) {
1441 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001442 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001443 locations->SetInAt(0, Location::Any());
1444 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1445 break;
1446
1447 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001448 // Processing a Dex `float-to-int' instruction.
1449 locations->SetInAt(0, Location::RequiresFpuRegister());
1450 locations->SetOut(Location::RequiresRegister());
1451 locations->AddTemp(Location::RequiresFpuRegister());
1452 break;
1453
Roland Levillain946e1432014-11-11 17:35:19 +00001454 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001455 // Processing a Dex `double-to-int' instruction.
1456 locations->SetInAt(0, Location::RequiresFpuRegister());
1457 locations->SetOut(Location::RequiresRegister());
1458 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001459 break;
1460
1461 default:
1462 LOG(FATAL) << "Unexpected type conversion from " << input_type
1463 << " to " << result_type;
1464 }
1465 break;
1466
Roland Levillaindff1f282014-11-05 14:15:05 +00001467 case Primitive::kPrimLong:
1468 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001469 case Primitive::kPrimBoolean:
1470 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001471 case Primitive::kPrimByte:
1472 case Primitive::kPrimShort:
1473 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001474 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001475 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001476 // TODO: We would benefit from a (to-be-implemented)
1477 // Location::RegisterOrStackSlot requirement for this input.
1478 locations->SetInAt(0, Location::RequiresRegister());
1479 locations->SetOut(Location::RequiresRegister());
1480 break;
1481
1482 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001483 // Processing a Dex `float-to-long' instruction.
1484 locations->SetInAt(0, Location::RequiresFpuRegister());
1485 locations->SetOut(Location::RequiresRegister());
1486 locations->AddTemp(Location::RequiresFpuRegister());
1487 break;
1488
Roland Levillaindff1f282014-11-05 14:15:05 +00001489 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001490 // Processing a Dex `double-to-long' instruction.
1491 locations->SetInAt(0, Location::RequiresFpuRegister());
1492 locations->SetOut(Location::RequiresRegister());
1493 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001494 break;
1495
1496 default:
1497 LOG(FATAL) << "Unexpected type conversion from " << input_type
1498 << " to " << result_type;
1499 }
1500 break;
1501
Roland Levillain981e4542014-11-14 11:47:14 +00001502 case Primitive::kPrimChar:
1503 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001504 case Primitive::kPrimBoolean:
1505 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001506 case Primitive::kPrimByte:
1507 case Primitive::kPrimShort:
1508 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001509 // Processing a Dex `int-to-char' instruction.
1510 locations->SetInAt(0, Location::Any());
1511 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1512 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::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001521 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001522 case Primitive::kPrimBoolean:
1523 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001524 case Primitive::kPrimByte:
1525 case Primitive::kPrimShort:
1526 case Primitive::kPrimInt:
1527 case Primitive::kPrimChar:
1528 // Processing a Dex `int-to-float' instruction.
1529 locations->SetInAt(0, Location::RequiresRegister());
1530 locations->SetOut(Location::RequiresFpuRegister());
1531 break;
1532
1533 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001534 // Processing a Dex `long-to-float' instruction.
1535 locations->SetInAt(0, Location::RequiresRegister());
1536 locations->SetOut(Location::RequiresFpuRegister());
1537 break;
1538
Roland Levillaincff13742014-11-17 14:32:17 +00001539 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001540 // Processing a Dex `double-to-float' instruction.
1541 locations->SetInAt(0, Location::RequiresFpuRegister());
1542 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001543 break;
1544
1545 default:
1546 LOG(FATAL) << "Unexpected type conversion from " << input_type
1547 << " to " << result_type;
1548 };
1549 break;
1550
Roland Levillaindff1f282014-11-05 14:15:05 +00001551 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001552 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001553 case Primitive::kPrimBoolean:
1554 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001555 case Primitive::kPrimByte:
1556 case Primitive::kPrimShort:
1557 case Primitive::kPrimInt:
1558 case Primitive::kPrimChar:
1559 // Processing a Dex `int-to-double' instruction.
1560 locations->SetInAt(0, Location::RequiresRegister());
1561 locations->SetOut(Location::RequiresFpuRegister());
1562 break;
1563
1564 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001565 // Processing a Dex `long-to-double' instruction.
1566 locations->SetInAt(0, Location::RequiresRegister());
1567 locations->SetOut(Location::RequiresFpuRegister());
1568 break;
1569
Roland Levillaincff13742014-11-17 14:32:17 +00001570 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001571 // Processing a Dex `float-to-double' instruction.
1572 locations->SetInAt(0, Location::RequiresFpuRegister());
1573 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001574 break;
1575
1576 default:
1577 LOG(FATAL) << "Unexpected type conversion from " << input_type
1578 << " to " << result_type;
1579 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001580 break;
1581
1582 default:
1583 LOG(FATAL) << "Unexpected type conversion from " << input_type
1584 << " to " << result_type;
1585 }
1586}
1587
1588void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1589 LocationSummary* locations = conversion->GetLocations();
1590 Location out = locations->Out();
1591 Location in = locations->InAt(0);
1592 Primitive::Type result_type = conversion->GetResultType();
1593 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001594 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001595 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001596 case Primitive::kPrimByte:
1597 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001598 case Primitive::kPrimBoolean:
1599 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001600 case Primitive::kPrimShort:
1601 case Primitive::kPrimInt:
1602 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001603 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001604 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001605 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001606 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001607 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001608 Address(CpuRegister(RSP), in.GetStackIndex()));
1609 } else {
1610 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001611 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00001612 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1613 }
1614 break;
1615
1616 default:
1617 LOG(FATAL) << "Unexpected type conversion from " << input_type
1618 << " to " << result_type;
1619 }
1620 break;
1621
Roland Levillain01a8d712014-11-14 16:27:39 +00001622 case Primitive::kPrimShort:
1623 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001624 case Primitive::kPrimBoolean:
1625 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001626 case Primitive::kPrimByte:
1627 case Primitive::kPrimInt:
1628 case Primitive::kPrimChar:
1629 // Processing a Dex `int-to-short' instruction.
1630 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001631 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001632 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001633 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001634 Address(CpuRegister(RSP), in.GetStackIndex()));
1635 } else {
1636 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001637 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00001638 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1639 }
1640 break;
1641
1642 default:
1643 LOG(FATAL) << "Unexpected type conversion from " << input_type
1644 << " to " << result_type;
1645 }
1646 break;
1647
Roland Levillain946e1432014-11-11 17:35:19 +00001648 case Primitive::kPrimInt:
1649 switch (input_type) {
1650 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001651 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001652 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001653 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00001654 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001655 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00001656 Address(CpuRegister(RSP), in.GetStackIndex()));
1657 } else {
1658 DCHECK(in.IsConstant());
1659 DCHECK(in.GetConstant()->IsLongConstant());
1660 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001661 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001662 }
1663 break;
1664
Roland Levillain3f8f9362014-12-02 17:45:01 +00001665 case Primitive::kPrimFloat: {
1666 // Processing a Dex `float-to-int' instruction.
1667 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1668 CpuRegister output = out.AsRegister<CpuRegister>();
1669 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1670 Label done, nan;
1671
1672 __ movl(output, Immediate(kPrimIntMax));
1673 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001674 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001675 // if input >= temp goto done
1676 __ comiss(input, temp);
1677 __ j(kAboveEqual, &done);
1678 // if input == NaN goto nan
1679 __ j(kUnordered, &nan);
1680 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001681 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00001682 __ jmp(&done);
1683 __ Bind(&nan);
1684 // output = 0
1685 __ xorl(output, output);
1686 __ Bind(&done);
1687 break;
1688 }
1689
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001690 case Primitive::kPrimDouble: {
1691 // Processing a Dex `double-to-int' instruction.
1692 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1693 CpuRegister output = out.AsRegister<CpuRegister>();
1694 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1695 Label done, nan;
1696
1697 __ movl(output, Immediate(kPrimIntMax));
1698 // temp = int-to-double(output)
1699 __ cvtsi2sd(temp, output);
1700 // if input >= temp goto done
1701 __ comisd(input, temp);
1702 __ j(kAboveEqual, &done);
1703 // if input == NaN goto nan
1704 __ j(kUnordered, &nan);
1705 // output = double-to-int-truncate(input)
1706 __ cvttsd2si(output, input);
1707 __ jmp(&done);
1708 __ Bind(&nan);
1709 // output = 0
1710 __ xorl(output, output);
1711 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001712 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001713 }
Roland Levillain946e1432014-11-11 17:35:19 +00001714
1715 default:
1716 LOG(FATAL) << "Unexpected type conversion from " << input_type
1717 << " to " << result_type;
1718 }
1719 break;
1720
Roland Levillaindff1f282014-11-05 14:15:05 +00001721 case Primitive::kPrimLong:
1722 switch (input_type) {
1723 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00001724 case Primitive::kPrimBoolean:
1725 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001726 case Primitive::kPrimByte:
1727 case Primitive::kPrimShort:
1728 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001729 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001730 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001731 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001732 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001733 break;
1734
Roland Levillain624279f2014-12-04 11:54:28 +00001735 case Primitive::kPrimFloat: {
1736 // Processing a Dex `float-to-long' instruction.
1737 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1738 CpuRegister output = out.AsRegister<CpuRegister>();
1739 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1740 Label done, nan;
1741
1742 __ movq(output, Immediate(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001743 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00001744 __ cvtsi2ss(temp, output, true);
1745 // if input >= temp goto done
1746 __ comiss(input, temp);
1747 __ j(kAboveEqual, &done);
1748 // if input == NaN goto nan
1749 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001750 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00001751 __ cvttss2si(output, input, true);
1752 __ jmp(&done);
1753 __ Bind(&nan);
1754 // output = 0
1755 __ xorq(output, output);
1756 __ Bind(&done);
1757 break;
1758 }
1759
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001760 case Primitive::kPrimDouble: {
1761 // Processing a Dex `double-to-long' instruction.
1762 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1763 CpuRegister output = out.AsRegister<CpuRegister>();
1764 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1765 Label done, nan;
1766
1767 __ movq(output, Immediate(kPrimLongMax));
1768 // temp = long-to-double(output)
1769 __ cvtsi2sd(temp, output, true);
1770 // if input >= temp goto done
1771 __ comisd(input, temp);
1772 __ j(kAboveEqual, &done);
1773 // if input == NaN goto nan
1774 __ j(kUnordered, &nan);
1775 // output = double-to-long-truncate(input)
1776 __ cvttsd2si(output, input, true);
1777 __ jmp(&done);
1778 __ Bind(&nan);
1779 // output = 0
1780 __ xorq(output, output);
1781 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00001782 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001783 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001784
1785 default:
1786 LOG(FATAL) << "Unexpected type conversion from " << input_type
1787 << " to " << result_type;
1788 }
1789 break;
1790
Roland Levillain981e4542014-11-14 11:47:14 +00001791 case Primitive::kPrimChar:
1792 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001793 case Primitive::kPrimBoolean:
1794 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001795 case Primitive::kPrimByte:
1796 case Primitive::kPrimShort:
1797 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001798 // Processing a Dex `int-to-char' instruction.
1799 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001800 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00001801 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001802 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001803 Address(CpuRegister(RSP), in.GetStackIndex()));
1804 } else {
1805 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001806 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00001807 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
1808 }
1809 break;
1810
1811 default:
1812 LOG(FATAL) << "Unexpected type conversion from " << input_type
1813 << " to " << result_type;
1814 }
1815 break;
1816
Roland Levillaindff1f282014-11-05 14:15:05 +00001817 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001818 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001819 case Primitive::kPrimBoolean:
1820 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001821 case Primitive::kPrimByte:
1822 case Primitive::kPrimShort:
1823 case Primitive::kPrimInt:
1824 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001825 // Processing a Dex `int-to-float' instruction.
1826 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001827 break;
1828
1829 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001830 // Processing a Dex `long-to-float' instruction.
1831 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
1832 break;
1833
Roland Levillaincff13742014-11-17 14:32:17 +00001834 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001835 // Processing a Dex `double-to-float' instruction.
1836 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001837 break;
1838
1839 default:
1840 LOG(FATAL) << "Unexpected type conversion from " << input_type
1841 << " to " << result_type;
1842 };
1843 break;
1844
Roland Levillaindff1f282014-11-05 14:15:05 +00001845 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001846 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001847 case Primitive::kPrimBoolean:
1848 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001849 case Primitive::kPrimByte:
1850 case Primitive::kPrimShort:
1851 case Primitive::kPrimInt:
1852 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001853 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001854 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
Roland Levillaincff13742014-11-17 14:32:17 +00001855 break;
1856
1857 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001858 // Processing a Dex `long-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001859 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001860 break;
1861
Roland Levillaincff13742014-11-17 14:32:17 +00001862 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001863 // Processing a Dex `float-to-double' instruction.
1864 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001865 break;
1866
1867 default:
1868 LOG(FATAL) << "Unexpected type conversion from " << input_type
1869 << " to " << result_type;
1870 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001871 break;
1872
1873 default:
1874 LOG(FATAL) << "Unexpected type conversion from " << input_type
1875 << " to " << result_type;
1876 }
1877}
1878
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001879void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001880 LocationSummary* locations =
1881 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001882 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001883 case Primitive::kPrimInt: {
1884 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001885 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1886 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001887 break;
1888 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001889
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001890 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001891 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05001892 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001893 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05001894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001895 break;
1896 }
1897
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001898 case Primitive::kPrimDouble:
1899 case Primitive::kPrimFloat: {
1900 locations->SetInAt(0, Location::RequiresFpuRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001901 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001902 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001903 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001904 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001905
1906 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001907 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001908 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001909}
1910
1911void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
1912 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001913 Location first = locations->InAt(0);
1914 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001915 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01001916
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001917 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001918 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001919 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001920 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1921 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1922 } else {
1923 __ leal(out.AsRegister<CpuRegister>(), Address(
1924 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1925 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001926 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001927 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1928 __ addl(out.AsRegister<CpuRegister>(),
1929 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
1930 } else {
1931 __ leal(out.AsRegister<CpuRegister>(), Address(
1932 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
1933 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001934 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001935 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001936 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001937 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001938 break;
1939 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001940
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001941 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05001942 if (second.IsRegister()) {
1943 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1944 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
1945 } else {
1946 __ leaq(out.AsRegister<CpuRegister>(), Address(
1947 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
1948 }
1949 } else {
1950 DCHECK(second.IsConstant());
1951 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1952 int32_t int32_value = Low32Bits(value);
1953 DCHECK_EQ(int32_value, value);
1954 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1955 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
1956 } else {
1957 __ leaq(out.AsRegister<CpuRegister>(), Address(
1958 first.AsRegister<CpuRegister>(), int32_value));
1959 }
1960 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001961 break;
1962 }
1963
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001964 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001965 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001966 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001967 }
1968
1969 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001970 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001971 break;
1972 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001973
1974 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001975 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001976 }
1977}
1978
1979void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001980 LocationSummary* locations =
1981 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001982 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001983 case Primitive::kPrimInt: {
1984 locations->SetInAt(0, Location::RequiresRegister());
1985 locations->SetInAt(1, Location::Any());
1986 locations->SetOut(Location::SameAsFirstInput());
1987 break;
1988 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001989 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001990 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001991 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001992 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001993 break;
1994 }
Calin Juravle11351682014-10-23 15:38:15 +01001995 case Primitive::kPrimFloat:
1996 case Primitive::kPrimDouble: {
1997 locations->SetInAt(0, Location::RequiresFpuRegister());
1998 locations->SetInAt(1, Location::RequiresFpuRegister());
1999 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002000 break;
Calin Juravle11351682014-10-23 15:38:15 +01002001 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002002 default:
Calin Juravle11351682014-10-23 15:38:15 +01002003 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002004 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002005}
2006
2007void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2008 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002009 Location first = locations->InAt(0);
2010 Location second = locations->InAt(1);
2011 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002012 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002013 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002014 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002015 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002016 } else if (second.IsConstant()) {
2017 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002018 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002019 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002020 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002021 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002022 break;
2023 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002024 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002025 if (second.IsConstant()) {
2026 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2027 DCHECK(IsInt<32>(value));
2028 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2029 } else {
2030 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2031 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002032 break;
2033 }
2034
Calin Juravle11351682014-10-23 15:38:15 +01002035 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002036 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002037 break;
Calin Juravle11351682014-10-23 15:38:15 +01002038 }
2039
2040 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002041 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002042 break;
2043 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002044
2045 default:
Calin Juravle11351682014-10-23 15:38:15 +01002046 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002047 }
2048}
2049
Calin Juravle34bacdf2014-10-07 20:23:36 +01002050void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2051 LocationSummary* locations =
2052 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2053 switch (mul->GetResultType()) {
2054 case Primitive::kPrimInt: {
2055 locations->SetInAt(0, Location::RequiresRegister());
2056 locations->SetInAt(1, Location::Any());
2057 locations->SetOut(Location::SameAsFirstInput());
2058 break;
2059 }
2060 case Primitive::kPrimLong: {
2061 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002062 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(mul->InputAt(1)));
2063 if (locations->InAt(1).IsConstant()) {
2064 // Can use 3 operand multiply.
2065 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2066 } else {
2067 locations->SetOut(Location::SameAsFirstInput());
2068 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002069 break;
2070 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002071 case Primitive::kPrimFloat:
2072 case Primitive::kPrimDouble: {
2073 locations->SetInAt(0, Location::RequiresFpuRegister());
2074 locations->SetInAt(1, Location::RequiresFpuRegister());
2075 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002076 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002077 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002078
2079 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002080 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002081 }
2082}
2083
2084void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2085 LocationSummary* locations = mul->GetLocations();
2086 Location first = locations->InAt(0);
2087 Location second = locations->InAt(1);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002088 switch (mul->GetResultType()) {
2089 case Primitive::kPrimInt: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002090 DCHECK(first.Equals(locations->Out()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002091 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002092 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002093 } else if (second.IsConstant()) {
2094 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002095 __ imull(first.AsRegister<CpuRegister>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002096 } else {
2097 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002098 __ imull(first.AsRegister<CpuRegister>(),
2099 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002100 }
2101 break;
2102 }
2103 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002104 if (second.IsConstant()) {
2105 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2106 DCHECK(IsInt<32>(value));
2107 __ imulq(locations->Out().AsRegister<CpuRegister>(),
2108 first.AsRegister<CpuRegister>(),
2109 Immediate(static_cast<int32_t>(value)));
2110 } else {
2111 DCHECK(first.Equals(locations->Out()));
2112 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2113 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002114 break;
2115 }
2116
Calin Juravleb5bfa962014-10-21 18:02:24 +01002117 case Primitive::kPrimFloat: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002118 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002119 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002120 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002121 }
2122
2123 case Primitive::kPrimDouble: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002124 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002125 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002126 break;
2127 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002128
2129 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002130 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002131 }
2132}
2133
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002134void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2135 uint32_t stack_adjustment, bool is_float) {
2136 if (source.IsStackSlot()) {
2137 DCHECK(is_float);
2138 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2139 } else if (source.IsDoubleStackSlot()) {
2140 DCHECK(!is_float);
2141 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2142 } else {
2143 // Write the value to the temporary location on the stack and load to FP stack.
2144 if (is_float) {
2145 Location stack_temp = Location::StackSlot(temp_offset);
2146 codegen_->Move(stack_temp, source);
2147 __ flds(Address(CpuRegister(RSP), temp_offset));
2148 } else {
2149 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2150 codegen_->Move(stack_temp, source);
2151 __ fldl(Address(CpuRegister(RSP), temp_offset));
2152 }
2153 }
2154}
2155
2156void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2157 Primitive::Type type = rem->GetResultType();
2158 bool is_float = type == Primitive::kPrimFloat;
2159 size_t elem_size = Primitive::ComponentSize(type);
2160 LocationSummary* locations = rem->GetLocations();
2161 Location first = locations->InAt(0);
2162 Location second = locations->InAt(1);
2163 Location out = locations->Out();
2164
2165 // Create stack space for 2 elements.
2166 // TODO: enhance register allocator to ask for stack temporaries.
2167 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2168
2169 // Load the values to the FP stack in reverse order, using temporaries if needed.
2170 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2171 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2172
2173 // Loop doing FPREM until we stabilize.
2174 Label retry;
2175 __ Bind(&retry);
2176 __ fprem();
2177
2178 // Move FP status to AX.
2179 __ fstsw();
2180
2181 // And see if the argument reduction is complete. This is signaled by the
2182 // C2 FPU flag bit set to 0.
2183 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2184 __ j(kNotEqual, &retry);
2185
2186 // We have settled on the final value. Retrieve it into an XMM register.
2187 // Store FP top of stack to real stack.
2188 if (is_float) {
2189 __ fsts(Address(CpuRegister(RSP), 0));
2190 } else {
2191 __ fstl(Address(CpuRegister(RSP), 0));
2192 }
2193
2194 // Pop the 2 items from the FP stack.
2195 __ fucompp();
2196
2197 // Load the value from the stack into an XMM register.
2198 DCHECK(out.IsFpuRegister()) << out;
2199 if (is_float) {
2200 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2201 } else {
2202 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2203 }
2204
2205 // And remove the temporary stack space we allocated.
2206 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2207}
2208
Calin Juravlebacfec32014-11-14 15:54:36 +00002209void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2210 DCHECK(instruction->IsDiv() || instruction->IsRem());
2211 Primitive::Type type = instruction->GetResultType();
2212 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2213
2214 bool is_div = instruction->IsDiv();
2215 LocationSummary* locations = instruction->GetLocations();
2216
Roland Levillain271ab9c2014-11-27 15:23:57 +00002217 CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
2218 CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002219
Roland Levillain271ab9c2014-11-27 15:23:57 +00002220 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002221 DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
2222
2223 SlowPathCodeX86_64* slow_path =
2224 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
2225 out_reg.AsRegister(), type, is_div);
2226 codegen_->AddSlowPath(slow_path);
2227
2228 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
2229 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
2230 // so it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002231 if (type == Primitive::kPrimInt) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002232 __ cmpl(second_reg, Immediate(-1));
2233 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002234 // edx:eax <- sign-extended of eax
2235 __ cdq();
2236 // eax = quotient, edx = remainder
2237 __ idivl(second_reg);
2238 } else {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002239 __ cmpq(second_reg, Immediate(-1));
2240 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002241 // rdx:rax <- sign-extended of rax
2242 __ cqo();
2243 // rax = quotient, rdx = remainder
2244 __ idivq(second_reg);
2245 }
2246
2247 __ Bind(slow_path->GetExitLabel());
2248}
2249
Calin Juravle7c4954d2014-10-28 16:57:40 +00002250void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
2251 LocationSummary* locations =
2252 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
2253 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002254 case Primitive::kPrimInt:
2255 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00002256 locations->SetInAt(0, Location::RegisterLocation(RAX));
2257 locations->SetInAt(1, Location::RequiresRegister());
2258 locations->SetOut(Location::SameAsFirstInput());
2259 // Intel uses edx:eax as the dividend.
2260 locations->AddTemp(Location::RegisterLocation(RDX));
2261 break;
2262 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002263
Calin Juravle7c4954d2014-10-28 16:57:40 +00002264 case Primitive::kPrimFloat:
2265 case Primitive::kPrimDouble: {
2266 locations->SetInAt(0, Location::RequiresFpuRegister());
2267 locations->SetInAt(1, Location::RequiresFpuRegister());
2268 locations->SetOut(Location::SameAsFirstInput());
2269 break;
2270 }
2271
2272 default:
2273 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2274 }
2275}
2276
2277void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
2278 LocationSummary* locations = div->GetLocations();
2279 Location first = locations->InAt(0);
2280 Location second = locations->InAt(1);
2281 DCHECK(first.Equals(locations->Out()));
2282
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002283 Primitive::Type type = div->GetResultType();
2284 switch (type) {
2285 case Primitive::kPrimInt:
2286 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002287 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00002288 break;
2289 }
2290
Calin Juravle7c4954d2014-10-28 16:57:40 +00002291 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002292 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002293 break;
2294 }
2295
2296 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002297 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002298 break;
2299 }
2300
2301 default:
2302 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2303 }
2304}
2305
Calin Juravlebacfec32014-11-14 15:54:36 +00002306void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002307 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002308 LocationSummary* locations =
2309 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002310
2311 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002312 case Primitive::kPrimInt:
2313 case Primitive::kPrimLong: {
2314 locations->SetInAt(0, Location::RegisterLocation(RAX));
2315 locations->SetInAt(1, Location::RequiresRegister());
2316 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
2317 locations->SetOut(Location::RegisterLocation(RDX));
2318 break;
2319 }
2320
2321 case Primitive::kPrimFloat:
2322 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002323 locations->SetInAt(0, Location::Any());
2324 locations->SetInAt(1, Location::Any());
2325 locations->SetOut(Location::RequiresFpuRegister());
2326 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002327 break;
2328 }
2329
2330 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002331 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002332 }
2333}
2334
2335void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
2336 Primitive::Type type = rem->GetResultType();
2337 switch (type) {
2338 case Primitive::kPrimInt:
2339 case Primitive::kPrimLong: {
2340 GenerateDivRemIntegral(rem);
2341 break;
2342 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002343 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002344 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002345 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002346 break;
2347 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002348 default:
2349 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2350 }
2351}
2352
Calin Juravled0d48522014-11-04 16:40:20 +00002353void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2354 LocationSummary* locations =
2355 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2356 locations->SetInAt(0, Location::Any());
2357 if (instruction->HasUses()) {
2358 locations->SetOut(Location::SameAsFirstInput());
2359 }
2360}
2361
2362void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2363 SlowPathCodeX86_64* slow_path =
2364 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
2365 codegen_->AddSlowPath(slow_path);
2366
2367 LocationSummary* locations = instruction->GetLocations();
2368 Location value = locations->InAt(0);
2369
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002370 switch (instruction->GetType()) {
2371 case Primitive::kPrimInt: {
2372 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002373 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002374 __ j(kEqual, slow_path->GetEntryLabel());
2375 } else if (value.IsStackSlot()) {
2376 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2377 __ j(kEqual, slow_path->GetEntryLabel());
2378 } else {
2379 DCHECK(value.IsConstant()) << value;
2380 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2381 __ jmp(slow_path->GetEntryLabel());
2382 }
2383 }
2384 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002385 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002386 case Primitive::kPrimLong: {
2387 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002388 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002389 __ j(kEqual, slow_path->GetEntryLabel());
2390 } else if (value.IsDoubleStackSlot()) {
2391 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
2392 __ j(kEqual, slow_path->GetEntryLabel());
2393 } else {
2394 DCHECK(value.IsConstant()) << value;
2395 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2396 __ jmp(slow_path->GetEntryLabel());
2397 }
2398 }
2399 break;
2400 }
2401 default:
2402 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002403 }
Calin Juravled0d48522014-11-04 16:40:20 +00002404}
2405
Calin Juravle9aec02f2014-11-18 23:06:35 +00002406void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
2407 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2408
2409 LocationSummary* locations =
2410 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2411
2412 switch (op->GetResultType()) {
2413 case Primitive::kPrimInt:
2414 case Primitive::kPrimLong: {
2415 locations->SetInAt(0, Location::RequiresRegister());
2416 // The shift count needs to be in CL.
2417 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
2418 locations->SetOut(Location::SameAsFirstInput());
2419 break;
2420 }
2421 default:
2422 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2423 }
2424}
2425
2426void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
2427 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2428
2429 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002430 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002431 Location second = locations->InAt(1);
2432
2433 switch (op->GetResultType()) {
2434 case Primitive::kPrimInt: {
2435 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002436 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002437 if (op->IsShl()) {
2438 __ shll(first_reg, second_reg);
2439 } else if (op->IsShr()) {
2440 __ sarl(first_reg, second_reg);
2441 } else {
2442 __ shrl(first_reg, second_reg);
2443 }
2444 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002445 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002446 if (op->IsShl()) {
2447 __ shll(first_reg, imm);
2448 } else if (op->IsShr()) {
2449 __ sarl(first_reg, imm);
2450 } else {
2451 __ shrl(first_reg, imm);
2452 }
2453 }
2454 break;
2455 }
2456 case Primitive::kPrimLong: {
2457 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002458 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002459 if (op->IsShl()) {
2460 __ shlq(first_reg, second_reg);
2461 } else if (op->IsShr()) {
2462 __ sarq(first_reg, second_reg);
2463 } else {
2464 __ shrq(first_reg, second_reg);
2465 }
2466 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002467 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002468 if (op->IsShl()) {
2469 __ shlq(first_reg, imm);
2470 } else if (op->IsShr()) {
2471 __ sarq(first_reg, imm);
2472 } else {
2473 __ shrq(first_reg, imm);
2474 }
2475 }
2476 break;
2477 }
2478 default:
2479 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2480 }
2481}
2482
2483void LocationsBuilderX86_64::VisitShl(HShl* shl) {
2484 HandleShift(shl);
2485}
2486
2487void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
2488 HandleShift(shl);
2489}
2490
2491void LocationsBuilderX86_64::VisitShr(HShr* shr) {
2492 HandleShift(shr);
2493}
2494
2495void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
2496 HandleShift(shr);
2497}
2498
2499void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
2500 HandleShift(ushr);
2501}
2502
2503void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
2504 HandleShift(ushr);
2505}
2506
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002507void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002508 LocationSummary* locations =
2509 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002510 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002511 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2512 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2513 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002514}
2515
2516void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
2517 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002518 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002519 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2520
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002521 __ gs()->call(
2522 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002523
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002524 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002525 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002526}
2527
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002528void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
2529 LocationSummary* locations =
2530 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2531 InvokeRuntimeCallingConvention calling_convention;
2532 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002533 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002534 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002535 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002536}
2537
2538void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
2539 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002540 codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002541 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
2542
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002543 __ gs()->call(
2544 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002545
2546 DCHECK(!codegen_->IsLeafMethod());
2547 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2548}
2549
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002550void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002551 LocationSummary* locations =
2552 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002553 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2554 if (location.IsStackSlot()) {
2555 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2556 } else if (location.IsDoubleStackSlot()) {
2557 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2558 }
2559 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002560}
2561
2562void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
2563 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002564 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002565}
2566
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002567void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002568 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002569 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002570 locations->SetInAt(0, Location::RequiresRegister());
2571 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002572}
2573
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002574void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
2575 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002576 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
2577 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002578 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002579 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002580 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002581 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002582 break;
2583
2584 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002585 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002586 break;
2587
2588 default:
2589 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2590 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002591}
2592
2593void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002594 LocationSummary* locations =
2595 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002596 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2597 locations->SetInAt(i, Location::Any());
2598 }
2599 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002600}
2601
2602void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002603 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002604 LOG(FATAL) << "Unimplemented";
2605}
2606
Calin Juravle52c48962014-12-16 17:02:57 +00002607void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
2608 /*
2609 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2610 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2611 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2612 */
2613 switch (kind) {
2614 case MemBarrierKind::kAnyAny: {
2615 __ mfence();
2616 break;
2617 }
2618 case MemBarrierKind::kAnyStore:
2619 case MemBarrierKind::kLoadAny:
2620 case MemBarrierKind::kStoreStore: {
2621 // nop
2622 break;
2623 }
2624 default:
2625 LOG(FATAL) << "Unexpected memory barier " << kind;
2626 }
2627}
2628
2629void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
2630 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2631
Nicolas Geoffray39468442014-09-02 15:17:15 +01002632 LocationSummary* locations =
2633 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00002634 locations->SetInAt(0, Location::RequiresRegister());
2635 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2636}
2637
2638void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
2639 const FieldInfo& field_info) {
2640 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2641
2642 LocationSummary* locations = instruction->GetLocations();
2643 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2644 Location out = locations->Out();
2645 bool is_volatile = field_info.IsVolatile();
2646 Primitive::Type field_type = field_info.GetFieldType();
2647 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2648
2649 switch (field_type) {
2650 case Primitive::kPrimBoolean: {
2651 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2652 break;
2653 }
2654
2655 case Primitive::kPrimByte: {
2656 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
2657 break;
2658 }
2659
2660 case Primitive::kPrimShort: {
2661 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2662 break;
2663 }
2664
2665 case Primitive::kPrimChar: {
2666 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
2667 break;
2668 }
2669
2670 case Primitive::kPrimInt:
2671 case Primitive::kPrimNot: {
2672 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
2673 break;
2674 }
2675
2676 case Primitive::kPrimLong: {
2677 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
2678 break;
2679 }
2680
2681 case Primitive::kPrimFloat: {
2682 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2683 break;
2684 }
2685
2686 case Primitive::kPrimDouble: {
2687 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
2688 break;
2689 }
2690
2691 case Primitive::kPrimVoid:
2692 LOG(FATAL) << "Unreachable type " << field_type;
2693 UNREACHABLE();
2694 }
2695
Calin Juravle77520bc2015-01-12 18:45:46 +00002696 codegen_->MaybeRecordImplicitNullCheck(instruction);
2697
Calin Juravle52c48962014-12-16 17:02:57 +00002698 if (is_volatile) {
2699 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2700 }
2701}
2702
2703void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
2704 const FieldInfo& field_info) {
2705 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2706
2707 LocationSummary* locations =
2708 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002709 bool needs_write_barrier =
Calin Juravle52c48962014-12-16 17:02:57 +00002710 CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
2711
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002712 locations->SetInAt(0, Location::RequiresRegister());
2713 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002714 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002715 // Temporary registers for the write barrier.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002716 locations->AddTemp(Location::RequiresRegister());
2717 locations->AddTemp(Location::RequiresRegister());
2718 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002719}
2720
Calin Juravle52c48962014-12-16 17:02:57 +00002721void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
2722 const FieldInfo& field_info) {
2723 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2724
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002725 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002726 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
2727 Location value = locations->InAt(1);
2728 bool is_volatile = field_info.IsVolatile();
2729 Primitive::Type field_type = field_info.GetFieldType();
2730 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2731
2732 if (is_volatile) {
2733 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2734 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002735
2736 switch (field_type) {
2737 case Primitive::kPrimBoolean:
2738 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002739 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002740 break;
2741 }
2742
2743 case Primitive::kPrimShort:
2744 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002745 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002746 break;
2747 }
2748
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002749 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002750 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002751 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002752 break;
2753 }
2754
2755 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002756 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002757 break;
2758 }
2759
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002760 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002761 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002762 break;
2763 }
2764
2765 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002766 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002767 break;
2768 }
2769
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002770 case Primitive::kPrimVoid:
2771 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002772 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002773 }
Calin Juravle52c48962014-12-16 17:02:57 +00002774
Calin Juravle77520bc2015-01-12 18:45:46 +00002775 codegen_->MaybeRecordImplicitNullCheck(instruction);
2776
2777 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2778 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2779 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
2780 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
2781 }
2782
Calin Juravle52c48962014-12-16 17:02:57 +00002783 if (is_volatile) {
2784 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2785 }
2786}
2787
2788void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2789 HandleFieldSet(instruction, instruction->GetFieldInfo());
2790}
2791
2792void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2793 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002794}
2795
2796void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002797 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002798}
2799
2800void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002801 HandleFieldGet(instruction, instruction->GetFieldInfo());
2802}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002803
Calin Juravle52c48962014-12-16 17:02:57 +00002804void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2805 HandleFieldGet(instruction);
2806}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002807
Calin Juravle52c48962014-12-16 17:02:57 +00002808void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2809 HandleFieldGet(instruction, instruction->GetFieldInfo());
2810}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002811
Calin Juravle52c48962014-12-16 17:02:57 +00002812void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2813 HandleFieldSet(instruction, instruction->GetFieldInfo());
2814}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002815
Calin Juravle52c48962014-12-16 17:02:57 +00002816void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2817 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002818}
2819
2820void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002821 LocationSummary* locations =
2822 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002823 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
2824 ? Location::RequiresRegister()
2825 : Location::Any();
2826 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002827 if (instruction->HasUses()) {
2828 locations->SetOut(Location::SameAsFirstInput());
2829 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002830}
2831
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002832void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002833 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2834 return;
2835 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002836 LocationSummary* locations = instruction->GetLocations();
2837 Location obj = locations->InAt(0);
2838
2839 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
2840 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2841}
2842
2843void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002844 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002845 codegen_->AddSlowPath(slow_path);
2846
2847 LocationSummary* locations = instruction->GetLocations();
2848 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002849
2850 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002851 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002852 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002853 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002854 } else {
2855 DCHECK(obj.IsConstant()) << obj;
2856 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2857 __ jmp(slow_path->GetEntryLabel());
2858 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002859 }
2860 __ j(kEqual, slow_path->GetEntryLabel());
2861}
2862
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002863void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
2864 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2865 GenerateImplicitNullCheck(instruction);
2866 } else {
2867 GenerateExplicitNullCheck(instruction);
2868 }
2869}
2870
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002871void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002872 LocationSummary* locations =
2873 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002874 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01002875 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002876 1, Location::RegisterOrConstant(instruction->InputAt(1)));
2877 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002878}
2879
2880void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
2881 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002882 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002883 Location index = locations->InAt(1);
2884
2885 switch (instruction->GetType()) {
2886 case Primitive::kPrimBoolean: {
2887 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002888 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002889 if (index.IsConstant()) {
2890 __ movzxb(out, Address(obj,
2891 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2892 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002893 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002894 }
2895 break;
2896 }
2897
2898 case Primitive::kPrimByte: {
2899 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002900 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002901 if (index.IsConstant()) {
2902 __ movsxb(out, Address(obj,
2903 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
2904 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002905 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002906 }
2907 break;
2908 }
2909
2910 case Primitive::kPrimShort: {
2911 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002912 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002913 if (index.IsConstant()) {
2914 __ movsxw(out, Address(obj,
2915 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2916 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002917 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002918 }
2919 break;
2920 }
2921
2922 case Primitive::kPrimChar: {
2923 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002924 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002925 if (index.IsConstant()) {
2926 __ movzxw(out, Address(obj,
2927 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
2928 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002929 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002930 }
2931 break;
2932 }
2933
2934 case Primitive::kPrimInt:
2935 case Primitive::kPrimNot: {
2936 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2937 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002938 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002939 if (index.IsConstant()) {
2940 __ movl(out, Address(obj,
2941 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2942 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002943 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002944 }
2945 break;
2946 }
2947
2948 case Primitive::kPrimLong: {
2949 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002950 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002951 if (index.IsConstant()) {
2952 __ movq(out, Address(obj,
2953 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2954 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002955 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002956 }
2957 break;
2958 }
2959
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002960 case Primitive::kPrimFloat: {
2961 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002962 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002963 if (index.IsConstant()) {
2964 __ movss(out, Address(obj,
2965 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
2966 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002967 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002968 }
2969 break;
2970 }
2971
2972 case Primitive::kPrimDouble: {
2973 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002974 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002975 if (index.IsConstant()) {
2976 __ movsd(out, Address(obj,
2977 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
2978 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002979 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002980 }
2981 break;
2982 }
2983
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002984 case Primitive::kPrimVoid:
2985 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002986 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002987 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002988 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002989}
2990
2991void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002992 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002993
2994 bool needs_write_barrier =
2995 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2996 bool needs_runtime_call = instruction->NeedsTypeCheck();
2997
Nicolas Geoffray39468442014-09-02 15:17:15 +01002998 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00002999 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3000 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003001 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003002 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3003 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3004 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003005 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003006 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003007 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003008 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3009 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003010 if (value_type == Primitive::kPrimLong) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003011 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003012 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3013 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003014 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003015 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003016 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003017
3018 if (needs_write_barrier) {
3019 // Temporary registers for the write barrier.
3020 locations->AddTemp(Location::RequiresRegister());
3021 locations->AddTemp(Location::RequiresRegister());
3022 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003023 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003024}
3025
3026void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3027 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003028 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003029 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003030 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003031 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003032 bool needs_runtime_call = locations->WillCall();
3033 bool needs_write_barrier =
3034 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003035
3036 switch (value_type) {
3037 case Primitive::kPrimBoolean:
3038 case Primitive::kPrimByte: {
3039 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003040 if (index.IsConstant()) {
3041 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003042 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003043 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003044 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003045 __ movb(Address(obj, offset),
3046 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003047 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003048 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003049 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003050 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3051 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003052 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003053 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003054 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3055 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003056 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003057 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003058 break;
3059 }
3060
3061 case Primitive::kPrimShort:
3062 case Primitive::kPrimChar: {
3063 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003064 if (index.IsConstant()) {
3065 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003066 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003067 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003068 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003069 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003070 __ movw(Address(obj, offset),
3071 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003072 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003073 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003074 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003075 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003076 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3077 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003078 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003079 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003080 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003081 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3082 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003083 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003084 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003085 break;
3086 }
3087
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003088 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003089 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003090 if (!needs_runtime_call) {
3091 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3092 if (index.IsConstant()) {
3093 size_t offset =
3094 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3095 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003096 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003097 } else {
3098 DCHECK(value.IsConstant()) << value;
3099 __ movl(Address(obj, offset),
3100 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3101 }
3102 } else {
3103 DCHECK(index.IsRegister()) << index;
3104 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003105 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3106 value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003107 } else {
3108 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003109 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003110 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3111 }
3112 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003113 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003114 if (needs_write_barrier) {
3115 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003116 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3117 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
3118 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003119 }
3120 } else {
3121 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003122 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
3123 true));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003124 DCHECK(!codegen_->IsLeafMethod());
3125 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3126 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003127 break;
3128 }
3129
3130 case Primitive::kPrimLong: {
3131 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003132 if (index.IsConstant()) {
3133 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003134 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003135 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003136 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003137 DCHECK(value.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3139 value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003140 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003141 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003142 break;
3143 }
3144
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003145 case Primitive::kPrimFloat: {
3146 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3147 if (index.IsConstant()) {
3148 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3149 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003150 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003151 } else {
3152 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003153 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
3154 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003155 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003156 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003157 break;
3158 }
3159
3160 case Primitive::kPrimDouble: {
3161 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3162 if (index.IsConstant()) {
3163 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3164 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003165 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003166 } else {
3167 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003168 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
3169 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003170 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003171 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003172 break;
3173 }
3174
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003175 case Primitive::kPrimVoid:
3176 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003177 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003178 }
3179}
3180
3181void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003182 LocationSummary* locations =
3183 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003184 locations->SetInAt(0, Location::RequiresRegister());
3185 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003186}
3187
3188void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
3189 LocationSummary* locations = instruction->GetLocations();
3190 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003191 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
3192 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003193 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003194 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003195}
3196
3197void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003198 LocationSummary* locations =
3199 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003200 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003201 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003202 if (instruction->HasUses()) {
3203 locations->SetOut(Location::SameAsFirstInput());
3204 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003205}
3206
3207void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
3208 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003209 Location index_loc = locations->InAt(0);
3210 Location length_loc = locations->InAt(1);
3211 SlowPathCodeX86_64* slow_path =
3212 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003213 codegen_->AddSlowPath(slow_path);
3214
Mark Mendellf60c90b2015-03-04 15:12:59 -05003215 CpuRegister length = length_loc.AsRegister<CpuRegister>();
3216 if (index_loc.IsConstant()) {
3217 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3218 __ cmpl(length, Immediate(value));
3219 } else {
3220 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
3221 }
3222 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003223}
3224
3225void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
3226 CpuRegister card,
3227 CpuRegister object,
3228 CpuRegister value) {
3229 Label is_null;
3230 __ testl(value, value);
3231 __ j(kEqual, &is_null);
3232 __ gs()->movq(card, Address::Absolute(
3233 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
3234 __ movq(temp, object);
3235 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
3236 __ movb(Address(temp, card, TIMES_1, 0), card);
3237 __ Bind(&is_null);
3238}
3239
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003240void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
3241 temp->SetLocations(nullptr);
3242}
3243
3244void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
3245 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003246 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003247}
3248
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003249void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003250 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003251 LOG(FATAL) << "Unimplemented";
3252}
3253
3254void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003255 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3256}
3257
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003258void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
3259 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3260}
3261
3262void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003263 HBasicBlock* block = instruction->GetBlock();
3264 if (block->GetLoopInformation() != nullptr) {
3265 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3266 // The back edge will generate the suspend check.
3267 return;
3268 }
3269 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3270 // The goto will generate the suspend check.
3271 return;
3272 }
3273 GenerateSuspendCheck(instruction, nullptr);
3274}
3275
3276void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
3277 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003278 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003279 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003280 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003281 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003282 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003283 if (successor == nullptr) {
3284 __ j(kNotEqual, slow_path->GetEntryLabel());
3285 __ Bind(slow_path->GetReturnLabel());
3286 } else {
3287 __ j(kEqual, codegen_->GetLabelOf(successor));
3288 __ jmp(slow_path->GetEntryLabel());
3289 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003290}
3291
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003292X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
3293 return codegen_->GetAssembler();
3294}
3295
3296void ParallelMoveResolverX86_64::EmitMove(size_t index) {
3297 MoveOperands* move = moves_.Get(index);
3298 Location source = move->GetSource();
3299 Location destination = move->GetDestination();
3300
3301 if (source.IsRegister()) {
3302 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003303 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003304 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003305 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003306 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003307 } else {
3308 DCHECK(destination.IsDoubleStackSlot());
3309 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003310 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003311 }
3312 } else if (source.IsStackSlot()) {
3313 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003314 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003315 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003316 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003317 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003318 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003319 } else {
3320 DCHECK(destination.IsStackSlot());
3321 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3322 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3323 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003324 } else if (source.IsDoubleStackSlot()) {
3325 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003326 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003327 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003328 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003329 __ movsd(destination.AsFpuRegister<XmmRegister>(),
3330 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003331 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01003332 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003333 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
3334 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3335 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003336 } else if (source.IsConstant()) {
3337 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003338 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3339 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003340 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003341 if (value == 0) {
3342 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
3343 } else {
3344 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
3345 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003346 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003347 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003348 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003349 }
3350 } else if (constant->IsLongConstant()) {
3351 int64_t value = constant->AsLongConstant()->GetValue();
3352 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003353 __ movq(destination.AsRegister<CpuRegister>(), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003354 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003355 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003356 __ movq(CpuRegister(TMP), Immediate(value));
3357 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3358 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003359 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003360 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003361 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003362 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003363 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003364 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3365 if (value == 0) {
3366 // easy FP 0.0.
3367 __ xorps(dest, dest);
3368 } else {
3369 __ movl(CpuRegister(TMP), imm);
3370 __ movd(dest, CpuRegister(TMP));
3371 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003372 } else {
3373 DCHECK(destination.IsStackSlot()) << destination;
3374 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
3375 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003376 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003377 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003378 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003379 int64_t value = bit_cast<int64_t, double>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003380 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003381 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003382 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3383 if (value == 0) {
3384 __ xorpd(dest, dest);
3385 } else {
3386 __ movq(CpuRegister(TMP), imm);
3387 __ movd(dest, CpuRegister(TMP));
3388 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003389 } else {
3390 DCHECK(destination.IsDoubleStackSlot()) << destination;
3391 __ movq(CpuRegister(TMP), imm);
3392 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
3393 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003394 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003395 } else if (source.IsFpuRegister()) {
3396 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003397 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003398 } else if (destination.IsStackSlot()) {
3399 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003400 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003401 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00003402 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003403 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003404 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003405 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003406 }
3407}
3408
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003409void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003410 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003411 __ movl(Address(CpuRegister(RSP), mem), reg);
3412 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003413}
3414
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003415void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003416 ScratchRegisterScope ensure_scratch(
3417 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3418
3419 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3420 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3421 __ movl(CpuRegister(ensure_scratch.GetRegister()),
3422 Address(CpuRegister(RSP), mem2 + stack_offset));
3423 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3424 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
3425 CpuRegister(ensure_scratch.GetRegister()));
3426}
3427
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003428void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
3429 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3430 __ movq(Address(CpuRegister(RSP), mem), reg);
3431 __ movq(reg, CpuRegister(TMP));
3432}
3433
3434void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
3435 ScratchRegisterScope ensure_scratch(
3436 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
3437
3438 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
3439 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
3440 __ movq(CpuRegister(ensure_scratch.GetRegister()),
3441 Address(CpuRegister(RSP), mem2 + stack_offset));
3442 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
3443 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
3444 CpuRegister(ensure_scratch.GetRegister()));
3445}
3446
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003447void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
3448 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3449 __ movss(Address(CpuRegister(RSP), mem), reg);
3450 __ movd(reg, CpuRegister(TMP));
3451}
3452
3453void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
3454 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
3455 __ movsd(Address(CpuRegister(RSP), mem), reg);
3456 __ movd(reg, CpuRegister(TMP));
3457}
3458
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003459void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
3460 MoveOperands* move = moves_.Get(index);
3461 Location source = move->GetSource();
3462 Location destination = move->GetDestination();
3463
3464 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003465 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003466 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003467 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003468 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003469 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003470 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003471 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
3472 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003473 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003474 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003475 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003476 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3477 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003478 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003479 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
3480 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3481 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003482 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003483 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003484 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003485 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003486 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003487 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003488 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003489 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003490 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003491 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003492 }
3493}
3494
3495
3496void ParallelMoveResolverX86_64::SpillScratch(int reg) {
3497 __ pushq(CpuRegister(reg));
3498}
3499
3500
3501void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
3502 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003503}
3504
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003505void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
3506 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
3507 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3508 Immediate(mirror::Class::kStatusInitialized));
3509 __ j(kLess, slow_path->GetEntryLabel());
3510 __ Bind(slow_path->GetExitLabel());
3511 // No need for memory fence, thanks to the X86_64 memory model.
3512}
3513
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003514void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003515 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3516 ? LocationSummary::kCallOnSlowPath
3517 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003518 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003519 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003520 locations->SetOut(Location::RequiresRegister());
3521}
3522
3523void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003524 CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003525 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003526 DCHECK(!cls->CanCallRuntime());
3527 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003528 codegen_->LoadCurrentMethod(out);
3529 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3530 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003531 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003532 codegen_->LoadCurrentMethod(out);
3533 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3534 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003535 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3536 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3537 codegen_->AddSlowPath(slow_path);
3538 __ testl(out, out);
3539 __ j(kEqual, slow_path->GetEntryLabel());
3540 if (cls->MustGenerateClinitCheck()) {
3541 GenerateClassInitializationCheck(slow_path, out);
3542 } else {
3543 __ Bind(slow_path->GetExitLabel());
3544 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003545 }
3546}
3547
3548void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
3549 LocationSummary* locations =
3550 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3551 locations->SetInAt(0, Location::RequiresRegister());
3552 if (check->HasUses()) {
3553 locations->SetOut(Location::SameAsFirstInput());
3554 }
3555}
3556
3557void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003558 // We assume the class to not be null.
3559 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
3560 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003561 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003562 GenerateClassInitializationCheck(slow_path,
3563 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003564}
3565
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003566void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
3567 LocationSummary* locations =
3568 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3569 locations->SetOut(Location::RequiresRegister());
3570}
3571
3572void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
3573 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
3574 codegen_->AddSlowPath(slow_path);
3575
Roland Levillain271ab9c2014-11-27 15:23:57 +00003576 CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003577 codegen_->LoadCurrentMethod(CpuRegister(out));
Mathieu Chartiereace4582014-11-24 18:29:54 -08003578 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3579 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003580 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3581 __ testl(out, out);
3582 __ j(kEqual, slow_path->GetEntryLabel());
3583 __ Bind(slow_path->GetExitLabel());
3584}
3585
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003586void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
3587 LocationSummary* locations =
3588 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3589 locations->SetOut(Location::RequiresRegister());
3590}
3591
3592void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
3593 Address address = Address::Absolute(
3594 Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003595 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003596 __ gs()->movl(address, Immediate(0));
3597}
3598
3599void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
3600 LocationSummary* locations =
3601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3602 InvokeRuntimeCallingConvention calling_convention;
3603 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3604}
3605
3606void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
3607 __ gs()->call(
3608 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
3609 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3610}
3611
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003612void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003613 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3614 ? LocationSummary::kNoCall
3615 : LocationSummary::kCallOnSlowPath;
3616 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3617 locations->SetInAt(0, Location::RequiresRegister());
3618 locations->SetInAt(1, Location::Any());
3619 locations->SetOut(Location::RequiresRegister());
3620}
3621
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003622void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003623 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003624 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003625 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003626 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003627 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3628 Label done, zero;
3629 SlowPathCodeX86_64* slow_path = nullptr;
3630
3631 // Return 0 if `obj` is null.
3632 // TODO: avoid this check if we know obj is not null.
3633 __ testl(obj, obj);
3634 __ j(kEqual, &zero);
3635 // Compare the class of `obj` with `cls`.
3636 __ movl(out, Address(obj, class_offset));
3637 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003638 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003639 } else {
3640 DCHECK(cls.IsStackSlot()) << cls;
3641 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
3642 }
3643 if (instruction->IsClassFinal()) {
3644 // Classes must be equal for the instanceof to succeed.
3645 __ j(kNotEqual, &zero);
3646 __ movl(out, Immediate(1));
3647 __ jmp(&done);
3648 } else {
3649 // If the classes are not equal, we go into a slow path.
3650 DCHECK(locations->OnlyCallsOnSlowPath());
3651 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003652 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003653 codegen_->AddSlowPath(slow_path);
3654 __ j(kNotEqual, slow_path->GetEntryLabel());
3655 __ movl(out, Immediate(1));
3656 __ jmp(&done);
3657 }
3658 __ Bind(&zero);
3659 __ movl(out, Immediate(0));
3660 if (slow_path != nullptr) {
3661 __ Bind(slow_path->GetExitLabel());
3662 }
3663 __ Bind(&done);
3664}
3665
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003666void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
3667 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3668 instruction, LocationSummary::kCallOnSlowPath);
3669 locations->SetInAt(0, Location::RequiresRegister());
3670 locations->SetInAt(1, Location::Any());
3671 locations->AddTemp(Location::RequiresRegister());
3672}
3673
3674void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
3675 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003676 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003677 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003678 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003679 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3680 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
3681 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3682 codegen_->AddSlowPath(slow_path);
3683
3684 // TODO: avoid this check if we know obj is not null.
3685 __ testl(obj, obj);
3686 __ j(kEqual, slow_path->GetExitLabel());
3687 // Compare the class of `obj` with `cls`.
3688 __ movl(temp, Address(obj, class_offset));
3689 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003690 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003691 } else {
3692 DCHECK(cls.IsStackSlot()) << cls;
3693 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
3694 }
3695 // Classes must be equal for the checkcast to succeed.
3696 __ j(kNotEqual, slow_path->GetEntryLabel());
3697 __ Bind(slow_path->GetExitLabel());
3698}
3699
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003700void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3701 LocationSummary* locations =
3702 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3703 InvokeRuntimeCallingConvention calling_convention;
3704 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3705}
3706
3707void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
3708 __ gs()->call(Address::Absolute(instruction->IsEnter()
3709 ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
3710 : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
3711 true));
3712 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3713}
3714
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003715void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3716void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3717void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3718
3719void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3720 LocationSummary* locations =
3721 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3722 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3723 || instruction->GetResultType() == Primitive::kPrimLong);
3724 locations->SetInAt(0, Location::RequiresRegister());
3725 if (instruction->GetType() == Primitive::kPrimInt) {
3726 locations->SetInAt(1, Location::Any());
3727 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003728 // We can handle 32 bit constants.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003729 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003730 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003731 }
3732 locations->SetOut(Location::SameAsFirstInput());
3733}
3734
3735void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
3736 HandleBitwiseOperation(instruction);
3737}
3738
3739void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
3740 HandleBitwiseOperation(instruction);
3741}
3742
3743void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
3744 HandleBitwiseOperation(instruction);
3745}
3746
3747void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
3748 LocationSummary* locations = instruction->GetLocations();
3749 Location first = locations->InAt(0);
3750 Location second = locations->InAt(1);
3751 DCHECK(first.Equals(locations->Out()));
3752
3753 if (instruction->GetResultType() == Primitive::kPrimInt) {
3754 if (second.IsRegister()) {
3755 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003756 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003757 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003758 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003759 } else {
3760 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003761 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003762 }
3763 } else if (second.IsConstant()) {
3764 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
3765 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003766 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003767 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003768 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003769 } else {
3770 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003771 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003772 }
3773 } else {
3774 Address address(CpuRegister(RSP), second.GetStackIndex());
3775 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003776 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003777 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003778 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003779 } else {
3780 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003781 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003782 }
3783 }
3784 } else {
3785 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003786 CpuRegister first_reg = first.AsRegister<CpuRegister>();
3787 bool second_is_constant = false;
3788 int64_t value = 0;
3789 if (second.IsConstant()) {
3790 second_is_constant = true;
3791 value = second.GetConstant()->AsLongConstant()->GetValue();
3792 DCHECK(IsInt<32>(value));
3793 }
3794
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003795 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003796 if (second_is_constant) {
3797 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
3798 } else {
3799 __ andq(first_reg, second.AsRegister<CpuRegister>());
3800 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003801 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003802 if (second_is_constant) {
3803 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
3804 } else {
3805 __ orq(first_reg, second.AsRegister<CpuRegister>());
3806 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003807 } else {
3808 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003809 if (second_is_constant) {
3810 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
3811 } else {
3812 __ xorq(first_reg, second.AsRegister<CpuRegister>());
3813 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003814 }
3815 }
3816}
3817
Calin Juravleb1498f62015-02-16 13:13:29 +00003818void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
3819 // Nothing to do, this should be removed during prepare for register allocator.
3820 UNUSED(instruction);
3821 LOG(FATAL) << "Unreachable";
3822}
3823
3824void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
3825 // Nothing to do, this should be removed during prepare for register allocator.
3826 UNUSED(instruction);
3827 LOG(FATAL) << "Unreachable";
3828}
3829
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003830} // namespace x86_64
3831} // namespace art