blob: 2b5fcbd71c2e5381b6723a8a89ba88c8b82f379e [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
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010020#include "code_generator_utils.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010021#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010022#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080023#include "intrinsics.h"
24#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070025#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070026#include "mirror/class-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010027#include "mirror/object_reference.h"
28#include "thread.h"
29#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010030#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010031#include "utils/x86_64/assembler_x86_64.h"
32#include "utils/x86_64/managed_register_x86_64.h"
33
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010034namespace art {
35
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010036namespace x86_64 {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038// Some x86_64 instructions require a register to be available as temp.
39static constexpr Register TMP = R11;
40
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010041static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010042static constexpr Register kMethodRegisterArgument = RDI;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010043
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000044static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000045static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010046
Mark Mendell24f2dfa2015-01-14 19:51:45 -050047static constexpr int kC2ConditionMask = 0x400;
48
Roland Levillain62a46b22015-06-01 18:24:13 +010049#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
Alexandre Rames8158f282015-08-07 10:26:17 +010050#define QUICK_ENTRY_POINT(x) Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x), true)
Nicolas Geoffraye5038322014-07-04 09:41:32 +010051
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010052class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010053 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010054 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010055
Alexandre Rames2ed20af2015-03-06 13:55:35 +000056 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010057 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010058 __ Bind(GetEntryLabel());
Alexandre Rames8158f282015-08-07 10:26:17 +010059 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
60 instruction_,
61 instruction_->GetDexPc(),
62 this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063 }
64
Alexandre Rames8158f282015-08-07 10:26:17 +010065 bool IsFatal() const OVERRIDE { return true; }
66
Alexandre Rames9931f312015-06-19 14:47:01 +010067 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
68
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010070 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
72};
73
Calin Juravled0d48522014-11-04 16:40:20 +000074class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
75 public:
76 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
77
Alexandre Rames2ed20af2015-03-06 13:55:35 +000078 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010079 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000080 __ Bind(GetEntryLabel());
Alexandre Rames8158f282015-08-07 10:26:17 +010081 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
82 instruction_,
83 instruction_->GetDexPc(),
84 this);
Calin Juravled0d48522014-11-04 16:40:20 +000085 }
86
Alexandre Rames8158f282015-08-07 10:26:17 +010087 bool IsFatal() const OVERRIDE { return true; }
88
Alexandre Rames9931f312015-06-19 14:47:01 +010089 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
90
Calin Juravled0d48522014-11-04 16:40:20 +000091 private:
92 HDivZeroCheck* const instruction_;
93 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
94};
95
Calin Juravlebacfec32014-11-14 15:54:36 +000096class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +000097 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000098 explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
99 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000100
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000101 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000102 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000103 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000104 if (is_div_) {
105 __ negl(cpu_reg_);
106 } else {
107 __ movl(cpu_reg_, Immediate(0));
108 }
109
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000110 } else {
111 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000112 if (is_div_) {
113 __ negq(cpu_reg_);
114 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400115 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000116 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000117 }
Calin Juravled0d48522014-11-04 16:40:20 +0000118 __ jmp(GetExitLabel());
119 }
120
Alexandre Rames9931f312015-06-19 14:47:01 +0100121 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
122
Calin Juravled0d48522014-11-04 16:40:20 +0000123 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000124 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000125 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000126 const bool is_div_;
127 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000128};
129
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100130class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000131 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100132 explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
133 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000134
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000135 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100136 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000138 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100139 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
140 instruction_,
141 instruction_->GetDexPc(),
142 this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000143 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100144 if (successor_ == nullptr) {
145 __ jmp(GetReturnLabel());
146 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100147 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100148 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000149 }
150
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100151 Label* GetReturnLabel() {
152 DCHECK(successor_ == nullptr);
153 return &return_label_;
154 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000155
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100156 HBasicBlock* GetSuccessor() const {
157 return successor_;
158 }
159
Alexandre Rames9931f312015-06-19 14:47:01 +0100160 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
161
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000162 private:
163 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100164 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000165 Label return_label_;
166
167 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
168};
169
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100170class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100172 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
173 Location index_location,
174 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100175 : instruction_(instruction),
176 index_location_(index_location),
177 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100178
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000179 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100180 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100181 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000182 // We're moving two locations to locations that could overlap, so we need a parallel
183 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100184 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000185 codegen->EmitParallelMoves(
186 index_location_,
187 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100188 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000189 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100190 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
191 Primitive::kPrimInt);
Alexandre Rames8158f282015-08-07 10:26:17 +0100192 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
193 instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100194 }
195
Alexandre Rames8158f282015-08-07 10:26:17 +0100196 bool IsFatal() const OVERRIDE { return true; }
197
Alexandre Rames9931f312015-06-19 14:47:01 +0100198 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
199
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100200 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100201 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100202 const Location index_location_;
203 const Location length_location_;
204
205 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
206};
207
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 LoadClassSlowPathX86_64(HLoadClass* cls,
211 HInstruction* at,
212 uint32_t dex_pc,
213 bool do_clinit)
214 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
215 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
216 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100217
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000218 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100220 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
221 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100222
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000223 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100225 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100227 x64_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
228 : QUICK_ENTRY_POINT(pInitializeType),
229 at_, dex_pc_, this);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000231 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000232 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000233 if (out.IsValid()) {
234 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
235 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000236 }
237
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000238 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100239 __ jmp(GetExitLabel());
240 }
241
Alexandre Rames9931f312015-06-19 14:47:01 +0100242 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
243
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100244 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000245 // The class this slow path will load.
246 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100247
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000248 // The instruction where this slow path is happening.
249 // (Might be the load class or an initialization check).
250 HInstruction* const at_;
251
252 // The dex PC of `at_`.
253 const uint32_t dex_pc_;
254
255 // Whether to initialize the class.
256 const bool do_clinit_;
257
258 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100259};
260
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000261class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
262 public:
263 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
264
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000265 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000266 LocationSummary* locations = instruction_->GetLocations();
267 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
268
269 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
270 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000271 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000272
273 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800274 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000275 Immediate(instruction_->GetStringIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100276 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
277 instruction_,
278 instruction_->GetDexPc(),
279 this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000280 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000281 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000282 __ jmp(GetExitLabel());
283 }
284
Alexandre Rames9931f312015-06-19 14:47:01 +0100285 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
286
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000287 private:
288 HLoadString* const instruction_;
289
290 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
291};
292
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000293class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
294 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000295 TypeCheckSlowPathX86_64(HInstruction* instruction,
296 Location class_to_check,
297 Location object_class,
298 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000300 class_to_check_(class_to_check),
301 object_class_(object_class),
302 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000303
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000304 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000305 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000306 DCHECK(instruction_->IsCheckCast()
307 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000308
309 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
310 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000311 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000312
313 // We're moving two locations to locations that could overlap, so we need a parallel
314 // move resolver.
315 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000316 codegen->EmitParallelMoves(
317 class_to_check_,
318 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100319 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000320 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100321 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
322 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000323
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000324 if (instruction_->IsInstanceOf()) {
Alexandre Rames8158f282015-08-07 10:26:17 +0100325 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
326 instruction_,
327 dex_pc_,
328 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000329 } else {
330 DCHECK(instruction_->IsCheckCast());
Alexandre Rames8158f282015-08-07 10:26:17 +0100331 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
332 instruction_,
333 dex_pc_,
334 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000335 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000336
337 if (instruction_->IsInstanceOf()) {
338 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
339 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000341 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000342 __ jmp(GetExitLabel());
343 }
344
Alexandre Rames9931f312015-06-19 14:47:01 +0100345 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
346
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000347 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000348 HInstruction* const instruction_;
349 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000350 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000351 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000352
353 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
354};
355
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700356class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
357 public:
358 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
359 : instruction_(instruction) {}
360
361 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100362 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700363 __ Bind(GetEntryLabel());
364 SaveLiveRegisters(codegen, instruction_->GetLocations());
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700365 DCHECK(instruction_->IsDeoptimize());
366 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
Alexandre Rames8158f282015-08-07 10:26:17 +0100367 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
368 deoptimize,
369 deoptimize->GetDexPc(),
370 this);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700371 }
372
Alexandre Rames9931f312015-06-19 14:47:01 +0100373 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
374
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700375 private:
376 HInstruction* const instruction_;
377 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
378};
379
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100380#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100381#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100382
Roland Levillain4fa13f62015-07-06 18:11:54 +0100383inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700384 switch (cond) {
385 case kCondEQ: return kEqual;
386 case kCondNE: return kNotEqual;
387 case kCondLT: return kLess;
388 case kCondLE: return kLessEqual;
389 case kCondGT: return kGreater;
390 case kCondGE: return kGreaterEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700391 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100392 LOG(FATAL) << "Unreachable";
393 UNREACHABLE();
394}
395
396inline Condition X86_64FPCondition(IfCondition cond) {
397 switch (cond) {
398 case kCondEQ: return kEqual;
399 case kCondNE: return kNotEqual;
400 case kCondLT: return kBelow;
401 case kCondLE: return kBelowEqual;
402 case kCondGT: return kAbove;
403 case kCondGE: return kAboveEqual;
404 };
405 LOG(FATAL) << "Unreachable";
406 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700407}
408
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800409void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100410 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800411 // All registers are assumed to be correctly set up.
412
413 // TODO: Implement all kinds of calls:
414 // 1) boot -> boot
415 // 2) app -> boot
416 // 3) app -> app
417 //
418 // Currently we implement the app -> app logic, which looks up in the resolve cache.
419
Jeff Hao848f70a2014-01-15 13:49:50 -0800420 if (invoke->IsStringInit()) {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100421 CpuRegister reg = temp.AsRegister<CpuRegister>();
Jeff Hao848f70a2014-01-15 13:49:50 -0800422 // temp = thread->string_init_entrypoint
Jeff Haocad65422015-06-18 21:16:08 -0700423 __ gs()->movq(reg, Address::Absolute(invoke->GetStringInitOffset(), true));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000424 // (temp + offset_of_quick_compiled_code)()
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100425 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000426 kX86_64WordSize).SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100427 } else if (invoke->IsRecursive()) {
428 __ call(&frame_entry_label_);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000429 } else {
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100430 CpuRegister reg = temp.AsRegister<CpuRegister>();
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100431 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
432 Register method_reg;
433 if (current_method.IsRegister()) {
434 method_reg = current_method.AsRegister<Register>();
435 } else {
436 DCHECK(invoke->GetLocations()->Intrinsified());
437 DCHECK(!current_method.IsValid());
438 method_reg = reg.AsRegister();
439 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
440 }
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100441 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +0100442 __ movl(reg, Address(CpuRegister(method_reg),
443 ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100444 // temp = temp[index_in_cache]
445 __ movq(reg, Address(
446 reg, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
447 // (temp + offset_of_quick_compiled_code)()
448 __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
449 kX86_64WordSize).SizeValue()));
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000450 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800451
452 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800453}
454
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100455void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100456 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100457}
458
459void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100460 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100461}
462
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100463size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
464 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
465 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100466}
467
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100468size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
469 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
470 return kX86_64WordSize;
471}
472
473size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
474 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
475 return kX86_64WordSize;
476}
477
478size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
479 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
480 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100481}
482
Alexandre Rames8158f282015-08-07 10:26:17 +0100483void CodeGeneratorX86_64::InvokeRuntime(Address entry_point,
484 HInstruction* instruction,
485 uint32_t dex_pc,
486 SlowPathCode* slow_path) {
487 // Ensure that the call kind indication given to the register allocator is
488 // coherent with the runtime call generated.
489 if (slow_path == nullptr) {
490 DCHECK(instruction->GetLocations()->WillCall());
491 } else {
492 DCHECK(instruction->GetLocations()->OnlyCallsOnSlowPath() || slow_path->IsFatal());
493 }
494
495 __ gs()->call(entry_point);
496 RecordPcInfo(instruction, dex_pc, slow_path);
497 DCHECK(instruction->IsSuspendCheck()
498 || instruction->IsBoundsCheck()
499 || instruction->IsNullCheck()
500 || instruction->IsDivZeroCheck()
501 || !IsLeafMethod());
502}
503
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000504static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000505// Use a fake return address register to mimic Quick.
506static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400507CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
508 const X86_64InstructionSetFeatures& isa_features,
509 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000510 : CodeGenerator(graph,
511 kNumberOfCpuRegisters,
512 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000513 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000514 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
515 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000516 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000517 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
518 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000519 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100520 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100521 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000522 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400523 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400524 isa_features_(isa_features),
525 constant_area_start_(0) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000526 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
527}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100528
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100529InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
530 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100531 : HGraphVisitor(graph),
532 assembler_(codegen->GetAssembler()),
533 codegen_(codegen) {}
534
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100535Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100536 switch (type) {
537 case Primitive::kPrimLong:
538 case Primitive::kPrimByte:
539 case Primitive::kPrimBoolean:
540 case Primitive::kPrimChar:
541 case Primitive::kPrimShort:
542 case Primitive::kPrimInt:
543 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100544 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100545 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100546 }
547
548 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100549 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100550 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100551 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100552 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100553
554 case Primitive::kPrimVoid:
555 LOG(FATAL) << "Unreachable type " << type;
556 }
557
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100558 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100559}
560
Nicolas Geoffray98893962015-01-21 12:32:32 +0000561void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100562 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100563 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100564
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000565 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100566 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000567
Nicolas Geoffray98893962015-01-21 12:32:32 +0000568 if (is_baseline) {
569 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
570 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
571 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000572 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
573 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
574 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000575 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100576}
577
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100578static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100579 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100580}
David Srbecky9d8606d2015-04-12 09:35:32 +0100581
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100582static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100583 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100584}
585
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100587 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000588 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100589 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700590 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000591 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100592
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000593 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100594 __ testq(CpuRegister(RAX), Address(
595 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100596 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100597 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000598
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000599 if (HasEmptyFrame()) {
600 return;
601 }
602
Nicolas Geoffray98893962015-01-21 12:32:32 +0000603 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000604 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000605 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000606 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100607 __ cfi().AdjustCFAOffset(kX86_64WordSize);
608 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000609 }
610 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100611
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100612 int adjust = GetFrameSize() - GetCoreSpillSize();
613 __ subq(CpuRegister(RSP), Immediate(adjust));
614 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000615 uint32_t xmm_spill_location = GetFpuSpillStart();
616 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100617
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000618 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
619 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100620 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
621 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
622 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000623 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100624 }
625
Mathieu Chartiere401d142015-04-22 13:56:20 -0700626 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100627 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100628}
629
630void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100631 __ cfi().RememberState();
632 if (!HasEmptyFrame()) {
633 uint32_t xmm_spill_location = GetFpuSpillStart();
634 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
635 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
636 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
637 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
638 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
639 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
640 }
641 }
642
643 int adjust = GetFrameSize() - GetCoreSpillSize();
644 __ addq(CpuRegister(RSP), Immediate(adjust));
645 __ cfi().AdjustCFAOffset(-adjust);
646
647 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
648 Register reg = kCoreCalleeSaves[i];
649 if (allocated_registers_.ContainsCoreRegister(reg)) {
650 __ popq(CpuRegister(reg));
651 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
652 __ cfi().Restore(DWARFReg(reg));
653 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000654 }
655 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100656 __ ret();
657 __ cfi().RestoreState();
658 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100659}
660
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100661void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
662 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100663}
664
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100665Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
666 switch (load->GetType()) {
667 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100668 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100669 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100670
671 case Primitive::kPrimInt:
672 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100673 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100674 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100675
676 case Primitive::kPrimBoolean:
677 case Primitive::kPrimByte:
678 case Primitive::kPrimChar:
679 case Primitive::kPrimShort:
680 case Primitive::kPrimVoid:
681 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700682 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100683 }
684
685 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700686 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100687}
688
689void CodeGeneratorX86_64::Move(Location destination, Location source) {
690 if (source.Equals(destination)) {
691 return;
692 }
693 if (destination.IsRegister()) {
694 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000695 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100696 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000697 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100698 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000699 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100700 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100701 } else {
702 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000703 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100704 Address(CpuRegister(RSP), source.GetStackIndex()));
705 }
706 } else if (destination.IsFpuRegister()) {
707 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000708 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100709 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000710 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100711 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000712 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100713 Address(CpuRegister(RSP), source.GetStackIndex()));
714 } else {
715 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000716 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100717 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100718 }
719 } else if (destination.IsStackSlot()) {
720 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100721 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000722 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100723 } else if (source.IsFpuRegister()) {
724 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000725 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500726 } else if (source.IsConstant()) {
727 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000728 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500729 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100730 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500731 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000732 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
733 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100734 }
735 } else {
736 DCHECK(destination.IsDoubleStackSlot());
737 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100738 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000739 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100740 } else if (source.IsFpuRegister()) {
741 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000742 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500743 } else if (source.IsConstant()) {
744 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800745 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500746 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000747 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500748 } else {
749 DCHECK(constant->IsLongConstant());
750 value = constant->AsLongConstant()->GetValue();
751 }
Mark Mendell92e83bf2015-05-07 11:25:03 -0400752 Load64BitValue(CpuRegister(TMP), value);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500753 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100754 } else {
755 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000756 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
757 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100758 }
759 }
760}
761
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100762void CodeGeneratorX86_64::Move(HInstruction* instruction,
763 Location location,
764 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000765 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100766 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700767 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100768 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000769 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100770 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000771 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000772 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
773 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000774 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000775 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000776 } else if (location.IsStackSlot()) {
777 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
778 } else {
779 DCHECK(location.IsConstant());
780 DCHECK_EQ(location.GetConstant(), const_to_move);
781 }
782 } else if (const_to_move->IsLongConstant()) {
783 int64_t value = const_to_move->AsLongConstant()->GetValue();
784 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400785 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000786 } else if (location.IsDoubleStackSlot()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400787 Load64BitValue(CpuRegister(TMP), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000788 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
789 } else {
790 DCHECK(location.IsConstant());
791 DCHECK_EQ(location.GetConstant(), const_to_move);
792 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100793 }
Roland Levillain476df552014-10-09 17:51:36 +0100794 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100795 switch (instruction->GetType()) {
796 case Primitive::kPrimBoolean:
797 case Primitive::kPrimByte:
798 case Primitive::kPrimChar:
799 case Primitive::kPrimShort:
800 case Primitive::kPrimInt:
801 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100802 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100803 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
804 break;
805
806 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100807 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000808 Move(location,
809 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100810 break;
811
812 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100813 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100814 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000815 } else if (instruction->IsTemporary()) {
816 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
817 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100818 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100819 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100820 switch (instruction->GetType()) {
821 case Primitive::kPrimBoolean:
822 case Primitive::kPrimByte:
823 case Primitive::kPrimChar:
824 case Primitive::kPrimShort:
825 case Primitive::kPrimInt:
826 case Primitive::kPrimNot:
827 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100828 case Primitive::kPrimFloat:
829 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000830 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100831 break;
832
833 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100834 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100835 }
836 }
837}
838
David Brazdilfc6a86a2015-06-26 10:33:45 +0000839void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100840 DCHECK(!successor->IsExitBlock());
841
842 HBasicBlock* block = got->GetBlock();
843 HInstruction* previous = got->GetPrevious();
844
845 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000846 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100847 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
848 return;
849 }
850
851 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
852 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
853 }
854 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100855 __ jmp(codegen_->GetLabelOf(successor));
856 }
857}
858
David Brazdilfc6a86a2015-06-26 10:33:45 +0000859void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
860 got->SetLocations(nullptr);
861}
862
863void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
864 HandleGoto(got, got->GetSuccessor());
865}
866
867void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
868 try_boundary->SetLocations(nullptr);
869}
870
871void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
872 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
873 if (!successor->IsExitBlock()) {
874 HandleGoto(try_boundary, successor);
875 }
876}
877
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100878void LocationsBuilderX86_64::VisitExit(HExit* exit) {
879 exit->SetLocations(nullptr);
880}
881
882void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700883 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100884}
885
Mark Mendellc4701932015-04-10 13:18:51 -0400886void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
887 Label* true_label,
888 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100889 if (cond->IsFPConditionTrueIfNaN()) {
890 __ j(kUnordered, true_label);
891 } else if (cond->IsFPConditionFalseIfNaN()) {
892 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400893 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100894 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400895}
896
897void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
898 HCondition* condition,
899 Label* true_target,
900 Label* false_target,
901 Label* always_true_target) {
902 LocationSummary* locations = condition->GetLocations();
903 Location left = locations->InAt(0);
904 Location right = locations->InAt(1);
905
906 // We don't want true_target as a nullptr.
907 if (true_target == nullptr) {
908 true_target = always_true_target;
909 }
910 bool falls_through = (false_target == nullptr);
911
912 // FP compares don't like null false_targets.
913 if (false_target == nullptr) {
914 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
915 }
916
917 Primitive::Type type = condition->InputAt(0)->GetType();
918 switch (type) {
919 case Primitive::kPrimLong: {
920 CpuRegister left_reg = left.AsRegister<CpuRegister>();
921 if (right.IsConstant()) {
922 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
923 if (IsInt<32>(value)) {
924 if (value == 0) {
925 __ testq(left_reg, left_reg);
926 } else {
927 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
928 }
929 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100930 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -0400931 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
932 }
933 } else if (right.IsDoubleStackSlot()) {
934 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
935 } else {
936 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
937 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100938 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -0400939 break;
940 }
941 case Primitive::kPrimFloat: {
942 if (right.IsFpuRegister()) {
943 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
944 } else if (right.IsConstant()) {
945 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
946 codegen_->LiteralFloatAddress(
947 right.GetConstant()->AsFloatConstant()->GetValue()));
948 } else {
949 DCHECK(right.IsStackSlot());
950 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
951 Address(CpuRegister(RSP), right.GetStackIndex()));
952 }
953 GenerateFPJumps(condition, true_target, false_target);
954 break;
955 }
956 case Primitive::kPrimDouble: {
957 if (right.IsFpuRegister()) {
958 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
959 } else if (right.IsConstant()) {
960 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
961 codegen_->LiteralDoubleAddress(
962 right.GetConstant()->AsDoubleConstant()->GetValue()));
963 } else {
964 DCHECK(right.IsDoubleStackSlot());
965 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
966 Address(CpuRegister(RSP), right.GetStackIndex()));
967 }
968 GenerateFPJumps(condition, true_target, false_target);
969 break;
970 }
971 default:
972 LOG(FATAL) << "Unexpected condition type " << type;
973 }
974
975 if (!falls_through) {
976 __ jmp(false_target);
977 }
978}
979
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700980void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
981 Label* true_target,
982 Label* false_target,
983 Label* always_true_target) {
984 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100985 if (cond->IsIntConstant()) {
986 // Constant condition, statically compared against 1.
987 int32_t cond_value = cond->AsIntConstant()->GetValue();
988 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700989 if (always_true_target != nullptr) {
990 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100991 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100992 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100993 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100994 DCHECK_EQ(cond_value, 0);
995 }
996 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100997 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100998 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
999 // Moves do not affect the eflags register, so if the condition is
1000 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001001 // again. We can't use the eflags on FP conditions if they are
1002 // materialized due to the complex branching.
1003 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001004 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001005 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
1006 && !Primitive::IsFloatingPointType(type);
1007
Roland Levillain4fa13f62015-07-06 18:11:54 +01001008 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001009 if (!eflags_set) {
1010 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001011 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001012 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001013 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001014 } else {
1015 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
1016 Immediate(0));
1017 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001018 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001019 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001020 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001021 }
1022 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001023 // Condition has not been materialized, use its inputs as the
1024 // comparison and its condition as the branch condition.
1025
Mark Mendellc4701932015-04-10 13:18:51 -04001026 // Is this a long or FP comparison that has been folded into the HCondition?
1027 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001028 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -04001029 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1030 true_target, false_target, always_true_target);
1031 return;
1032 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001033
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001034 Location lhs = cond->GetLocations()->InAt(0);
1035 Location rhs = cond->GetLocations()->InAt(1);
1036 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001037 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001038 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001039 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001040 if (constant == 0) {
1041 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1042 } else {
1043 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1044 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001045 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001046 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001047 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1048 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001049 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001050 }
Dave Allison20dfc792014-06-16 20:44:29 -07001051 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001052 if (false_target != nullptr) {
1053 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001054 }
1055}
1056
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001057void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1058 LocationSummary* locations =
1059 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1060 HInstruction* cond = if_instr->InputAt(0);
1061 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1062 locations->SetInAt(0, Location::Any());
1063 }
1064}
1065
1066void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1067 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1068 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1069 Label* always_true_target = true_target;
1070 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1071 if_instr->IfTrueSuccessor())) {
1072 always_true_target = nullptr;
1073 }
1074 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1075 if_instr->IfFalseSuccessor())) {
1076 false_target = nullptr;
1077 }
1078 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1079}
1080
1081void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1082 LocationSummary* locations = new (GetGraph()->GetArena())
1083 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1084 HInstruction* cond = deoptimize->InputAt(0);
1085 DCHECK(cond->IsCondition());
1086 if (cond->AsCondition()->NeedsMaterialization()) {
1087 locations->SetInAt(0, Location::Any());
1088 }
1089}
1090
1091void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1092 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
1093 DeoptimizationSlowPathX86_64(deoptimize);
1094 codegen_->AddSlowPath(slow_path);
1095 Label* slow_path_entry = slow_path->GetEntryLabel();
1096 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1097}
1098
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001099void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1100 local->SetLocations(nullptr);
1101}
1102
1103void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1104 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1105}
1106
1107void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1108 local->SetLocations(nullptr);
1109}
1110
1111void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
1112 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001113 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001114}
1115
1116void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001117 LocationSummary* locations =
1118 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001119 switch (store->InputAt(1)->GetType()) {
1120 case Primitive::kPrimBoolean:
1121 case Primitive::kPrimByte:
1122 case Primitive::kPrimChar:
1123 case Primitive::kPrimShort:
1124 case Primitive::kPrimInt:
1125 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001126 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001127 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1128 break;
1129
1130 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001131 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001132 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1133 break;
1134
1135 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001136 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001137 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001138}
1139
1140void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001141 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001142}
1143
Roland Levillain0d37cd02015-05-27 16:39:19 +01001144void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001145 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001146 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001147 // Handle the long/FP comparisons made in instruction simplification.
1148 switch (cond->InputAt(0)->GetType()) {
1149 case Primitive::kPrimLong:
1150 locations->SetInAt(0, Location::RequiresRegister());
1151 locations->SetInAt(1, Location::Any());
1152 break;
1153 case Primitive::kPrimFloat:
1154 case Primitive::kPrimDouble:
1155 locations->SetInAt(0, Location::RequiresFpuRegister());
1156 locations->SetInAt(1, Location::Any());
1157 break;
1158 default:
1159 locations->SetInAt(0, Location::RequiresRegister());
1160 locations->SetInAt(1, Location::Any());
1161 break;
1162 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001163 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001164 locations->SetOut(Location::RequiresRegister());
1165 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001166}
1167
Roland Levillain0d37cd02015-05-27 16:39:19 +01001168void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001169 if (!cond->NeedsMaterialization()) {
1170 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001171 }
Mark Mendellc4701932015-04-10 13:18:51 -04001172
1173 LocationSummary* locations = cond->GetLocations();
1174 Location lhs = locations->InAt(0);
1175 Location rhs = locations->InAt(1);
1176 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1177 Label true_label, false_label;
1178
1179 switch (cond->InputAt(0)->GetType()) {
1180 default:
1181 // Integer case.
1182
1183 // Clear output register: setcc only sets the low byte.
1184 __ xorl(reg, reg);
1185
1186 if (rhs.IsRegister()) {
1187 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1188 } else if (rhs.IsConstant()) {
1189 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1190 if (constant == 0) {
1191 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1192 } else {
1193 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1194 }
1195 } else {
1196 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1197 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001198 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001199 return;
1200 case Primitive::kPrimLong:
1201 // Clear output register: setcc only sets the low byte.
1202 __ xorl(reg, reg);
1203
1204 if (rhs.IsRegister()) {
1205 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1206 } else if (rhs.IsConstant()) {
1207 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1208 if (IsInt<32>(value)) {
1209 if (value == 0) {
1210 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1211 } else {
1212 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1213 }
1214 } else {
1215 // Value won't fit in an int.
1216 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1217 }
1218 } else {
1219 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1220 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001221 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001222 return;
1223 case Primitive::kPrimFloat: {
1224 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1225 if (rhs.IsConstant()) {
1226 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1227 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1228 } else if (rhs.IsStackSlot()) {
1229 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1230 } else {
1231 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1232 }
1233 GenerateFPJumps(cond, &true_label, &false_label);
1234 break;
1235 }
1236 case Primitive::kPrimDouble: {
1237 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1238 if (rhs.IsConstant()) {
1239 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1240 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1241 } else if (rhs.IsDoubleStackSlot()) {
1242 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1243 } else {
1244 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1245 }
1246 GenerateFPJumps(cond, &true_label, &false_label);
1247 break;
1248 }
1249 }
1250
1251 // Convert the jumps into the result.
1252 Label done_label;
1253
Roland Levillain4fa13f62015-07-06 18:11:54 +01001254 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001255 __ Bind(&false_label);
1256 __ xorl(reg, reg);
1257 __ jmp(&done_label);
1258
Roland Levillain4fa13f62015-07-06 18:11:54 +01001259 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001260 __ Bind(&true_label);
1261 __ movl(reg, Immediate(1));
1262 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001263}
1264
1265void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1266 VisitCondition(comp);
1267}
1268
1269void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1270 VisitCondition(comp);
1271}
1272
1273void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1274 VisitCondition(comp);
1275}
1276
1277void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1278 VisitCondition(comp);
1279}
1280
1281void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1282 VisitCondition(comp);
1283}
1284
1285void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1286 VisitCondition(comp);
1287}
1288
1289void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1290 VisitCondition(comp);
1291}
1292
1293void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1294 VisitCondition(comp);
1295}
1296
1297void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1298 VisitCondition(comp);
1299}
1300
1301void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1302 VisitCondition(comp);
1303}
1304
1305void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1306 VisitCondition(comp);
1307}
1308
1309void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1310 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001311}
1312
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001313void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001314 LocationSummary* locations =
1315 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001316 switch (compare->InputAt(0)->GetType()) {
1317 case Primitive::kPrimLong: {
1318 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001319 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001320 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1321 break;
1322 }
1323 case Primitive::kPrimFloat:
1324 case Primitive::kPrimDouble: {
1325 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001326 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001327 locations->SetOut(Location::RequiresRegister());
1328 break;
1329 }
1330 default:
1331 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1332 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001333}
1334
1335void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001336 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001337 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001338 Location left = locations->InAt(0);
1339 Location right = locations->InAt(1);
1340
1341 Label less, greater, done;
1342 Primitive::Type type = compare->InputAt(0)->GetType();
1343 switch (type) {
1344 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001345 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1346 if (right.IsConstant()) {
1347 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001348 if (IsInt<32>(value)) {
1349 if (value == 0) {
1350 __ testq(left_reg, left_reg);
1351 } else {
1352 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1353 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001354 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001355 // Value won't fit in an int.
1356 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001357 }
Mark Mendell40741f32015-04-20 22:10:34 -04001358 } else if (right.IsDoubleStackSlot()) {
1359 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001360 } else {
1361 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1362 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001363 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001364 }
1365 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001366 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1367 if (right.IsConstant()) {
1368 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1369 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1370 } else if (right.IsStackSlot()) {
1371 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1372 } else {
1373 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1374 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001375 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1376 break;
1377 }
1378 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001379 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1380 if (right.IsConstant()) {
1381 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1382 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1383 } else if (right.IsDoubleStackSlot()) {
1384 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1385 } else {
1386 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1387 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001388 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1389 break;
1390 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001391 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001392 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001393 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001394 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001395 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001396 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001397
Calin Juravle91debbc2014-11-26 19:01:09 +00001398 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001399 __ movl(out, Immediate(1));
1400 __ jmp(&done);
1401
1402 __ Bind(&less);
1403 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001404
1405 __ Bind(&done);
1406}
1407
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001408void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001409 LocationSummary* locations =
1410 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001411 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001412}
1413
1414void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001415 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001416 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001417}
1418
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001419void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1420 LocationSummary* locations =
1421 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1422 locations->SetOut(Location::ConstantLocation(constant));
1423}
1424
1425void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1426 // Will be generated at use site.
1427 UNUSED(constant);
1428}
1429
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001430void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001431 LocationSummary* locations =
1432 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001433 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001434}
1435
1436void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001437 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001438 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001439}
1440
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001441void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1442 LocationSummary* locations =
1443 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1444 locations->SetOut(Location::ConstantLocation(constant));
1445}
1446
1447void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1448 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001449 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001450}
1451
1452void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1453 LocationSummary* locations =
1454 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1455 locations->SetOut(Location::ConstantLocation(constant));
1456}
1457
1458void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1459 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001460 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001461}
1462
Calin Juravle27df7582015-04-17 19:12:31 +01001463void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1464 memory_barrier->SetLocations(nullptr);
1465}
1466
1467void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1468 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1469}
1470
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001471void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1472 ret->SetLocations(nullptr);
1473}
1474
1475void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001476 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001477 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001478}
1479
1480void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001481 LocationSummary* locations =
1482 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001483 switch (ret->InputAt(0)->GetType()) {
1484 case Primitive::kPrimBoolean:
1485 case Primitive::kPrimByte:
1486 case Primitive::kPrimChar:
1487 case Primitive::kPrimShort:
1488 case Primitive::kPrimInt:
1489 case Primitive::kPrimNot:
1490 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001491 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001492 break;
1493
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001494 case Primitive::kPrimFloat:
1495 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001496 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001497 break;
1498
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001499 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001500 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001501 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001502}
1503
1504void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1505 if (kIsDebugBuild) {
1506 switch (ret->InputAt(0)->GetType()) {
1507 case Primitive::kPrimBoolean:
1508 case Primitive::kPrimByte:
1509 case Primitive::kPrimChar:
1510 case Primitive::kPrimShort:
1511 case Primitive::kPrimInt:
1512 case Primitive::kPrimNot:
1513 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001514 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001515 break;
1516
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001517 case Primitive::kPrimFloat:
1518 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001519 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001520 XMM0);
1521 break;
1522
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001523 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001524 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001525 }
1526 }
1527 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001528}
1529
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001530Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1531 switch (type) {
1532 case Primitive::kPrimBoolean:
1533 case Primitive::kPrimByte:
1534 case Primitive::kPrimChar:
1535 case Primitive::kPrimShort:
1536 case Primitive::kPrimInt:
1537 case Primitive::kPrimNot:
1538 case Primitive::kPrimLong:
1539 return Location::RegisterLocation(RAX);
1540
1541 case Primitive::kPrimVoid:
1542 return Location::NoLocation();
1543
1544 case Primitive::kPrimDouble:
1545 case Primitive::kPrimFloat:
1546 return Location::FpuRegisterLocation(XMM0);
1547 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001548
1549 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001550}
1551
1552Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1553 return Location::RegisterLocation(kMethodRegisterArgument);
1554}
1555
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001556Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001557 switch (type) {
1558 case Primitive::kPrimBoolean:
1559 case Primitive::kPrimByte:
1560 case Primitive::kPrimChar:
1561 case Primitive::kPrimShort:
1562 case Primitive::kPrimInt:
1563 case Primitive::kPrimNot: {
1564 uint32_t index = gp_index_++;
1565 stack_index_++;
1566 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001567 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001568 } else {
1569 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1570 }
1571 }
1572
1573 case Primitive::kPrimLong: {
1574 uint32_t index = gp_index_;
1575 stack_index_ += 2;
1576 if (index < calling_convention.GetNumberOfRegisters()) {
1577 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001578 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001579 } else {
1580 gp_index_ += 2;
1581 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1582 }
1583 }
1584
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001585 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001586 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001587 stack_index_++;
1588 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001589 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001590 } else {
1591 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1592 }
1593 }
1594
1595 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001596 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001597 stack_index_ += 2;
1598 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001599 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001600 } else {
1601 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1602 }
1603 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001604
1605 case Primitive::kPrimVoid:
1606 LOG(FATAL) << "Unexpected parameter type " << type;
1607 break;
1608 }
1609 return Location();
1610}
1611
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001612void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001613 // When we do not run baseline, explicit clinit checks triggered by static
1614 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1615 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001616
Mark Mendellfb8d2792015-03-31 22:16:59 -04001617 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001618 if (intrinsic.TryDispatch(invoke)) {
1619 return;
1620 }
1621
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001622 HandleInvoke(invoke);
1623}
1624
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001625static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1626 if (invoke->GetLocations()->Intrinsified()) {
1627 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1628 intrinsic.Dispatch(invoke);
1629 return true;
1630 }
1631 return false;
1632}
1633
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001634void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001635 // When we do not run baseline, explicit clinit checks triggered by static
1636 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1637 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001638
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001639 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1640 return;
1641 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001642
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001643 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001644 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001645 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001646 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001647}
1648
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001649void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001650 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001651 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001652}
1653
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001654void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001655 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001656 if (intrinsic.TryDispatch(invoke)) {
1657 return;
1658 }
1659
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001660 HandleInvoke(invoke);
1661}
1662
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001663void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001664 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1665 return;
1666 }
1667
Roland Levillain271ab9c2014-11-27 15:23:57 +00001668 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001669 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1670 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001671 LocationSummary* locations = invoke->GetLocations();
1672 Location receiver = locations->InAt(0);
1673 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1674 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001675 DCHECK(receiver.IsRegister());
1676 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001677 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001678 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001679 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001680 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001681 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001682 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001683 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001684
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001685 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001686 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001687}
1688
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001689void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1690 HandleInvoke(invoke);
1691 // Add the hidden argument.
1692 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1693}
1694
1695void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1696 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001697 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001698 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1699 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001700 LocationSummary* locations = invoke->GetLocations();
1701 Location receiver = locations->InAt(0);
1702 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1703
1704 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001705 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1706 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001707
1708 // temp = object->GetClass();
1709 if (receiver.IsStackSlot()) {
1710 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1711 __ movl(temp, Address(temp, class_offset));
1712 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001713 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001714 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001715 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001716 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001717 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001718 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001719 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001720 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001721 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001722
1723 DCHECK(!codegen_->IsLeafMethod());
1724 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1725}
1726
Roland Levillain88cb1752014-10-20 16:36:47 +01001727void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1728 LocationSummary* locations =
1729 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1730 switch (neg->GetResultType()) {
1731 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001732 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001733 locations->SetInAt(0, Location::RequiresRegister());
1734 locations->SetOut(Location::SameAsFirstInput());
1735 break;
1736
Roland Levillain88cb1752014-10-20 16:36:47 +01001737 case Primitive::kPrimFloat:
1738 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001739 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001740 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001741 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001742 break;
1743
1744 default:
1745 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1746 }
1747}
1748
1749void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1750 LocationSummary* locations = neg->GetLocations();
1751 Location out = locations->Out();
1752 Location in = locations->InAt(0);
1753 switch (neg->GetResultType()) {
1754 case Primitive::kPrimInt:
1755 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001756 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001757 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001758 break;
1759
1760 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001761 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001762 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001763 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001764 break;
1765
Roland Levillain5368c212014-11-27 15:03:41 +00001766 case Primitive::kPrimFloat: {
1767 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001768 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001769 // Implement float negation with an exclusive or with value
1770 // 0x80000000 (mask for bit 31, representing the sign of a
1771 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001772 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001773 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001774 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001775 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001776
Roland Levillain5368c212014-11-27 15:03:41 +00001777 case Primitive::kPrimDouble: {
1778 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001779 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001780 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001781 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001782 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001783 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001784 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001785 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001786 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001787
1788 default:
1789 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1790 }
1791}
1792
Roland Levillaindff1f282014-11-05 14:15:05 +00001793void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1794 LocationSummary* locations =
1795 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1796 Primitive::Type result_type = conversion->GetResultType();
1797 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001798 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001799
David Brazdilb2bd1c52015-03-25 11:17:37 +00001800 // The Java language does not allow treating boolean as an integral type but
1801 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001802
Roland Levillaindff1f282014-11-05 14:15:05 +00001803 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001804 case Primitive::kPrimByte:
1805 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001806 case Primitive::kPrimBoolean:
1807 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001808 case Primitive::kPrimShort:
1809 case Primitive::kPrimInt:
1810 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001811 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001812 locations->SetInAt(0, Location::Any());
1813 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1814 break;
1815
1816 default:
1817 LOG(FATAL) << "Unexpected type conversion from " << input_type
1818 << " to " << result_type;
1819 }
1820 break;
1821
Roland Levillain01a8d712014-11-14 16:27:39 +00001822 case Primitive::kPrimShort:
1823 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001824 case Primitive::kPrimBoolean:
1825 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001826 case Primitive::kPrimByte:
1827 case Primitive::kPrimInt:
1828 case Primitive::kPrimChar:
1829 // Processing a Dex `int-to-short' instruction.
1830 locations->SetInAt(0, Location::Any());
1831 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1832 break;
1833
1834 default:
1835 LOG(FATAL) << "Unexpected type conversion from " << input_type
1836 << " to " << result_type;
1837 }
1838 break;
1839
Roland Levillain946e1432014-11-11 17:35:19 +00001840 case Primitive::kPrimInt:
1841 switch (input_type) {
1842 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001843 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001844 locations->SetInAt(0, Location::Any());
1845 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1846 break;
1847
1848 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001849 // Processing a Dex `float-to-int' instruction.
1850 locations->SetInAt(0, Location::RequiresFpuRegister());
1851 locations->SetOut(Location::RequiresRegister());
1852 locations->AddTemp(Location::RequiresFpuRegister());
1853 break;
1854
Roland Levillain946e1432014-11-11 17:35:19 +00001855 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001856 // Processing a Dex `double-to-int' instruction.
1857 locations->SetInAt(0, Location::RequiresFpuRegister());
1858 locations->SetOut(Location::RequiresRegister());
1859 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001860 break;
1861
1862 default:
1863 LOG(FATAL) << "Unexpected type conversion from " << input_type
1864 << " to " << result_type;
1865 }
1866 break;
1867
Roland Levillaindff1f282014-11-05 14:15:05 +00001868 case Primitive::kPrimLong:
1869 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001870 case Primitive::kPrimBoolean:
1871 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001872 case Primitive::kPrimByte:
1873 case Primitive::kPrimShort:
1874 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001875 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001876 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001877 // TODO: We would benefit from a (to-be-implemented)
1878 // Location::RegisterOrStackSlot requirement for this input.
1879 locations->SetInAt(0, Location::RequiresRegister());
1880 locations->SetOut(Location::RequiresRegister());
1881 break;
1882
1883 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001884 // Processing a Dex `float-to-long' instruction.
1885 locations->SetInAt(0, Location::RequiresFpuRegister());
1886 locations->SetOut(Location::RequiresRegister());
1887 locations->AddTemp(Location::RequiresFpuRegister());
1888 break;
1889
Roland Levillaindff1f282014-11-05 14:15:05 +00001890 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001891 // Processing a Dex `double-to-long' instruction.
1892 locations->SetInAt(0, Location::RequiresFpuRegister());
1893 locations->SetOut(Location::RequiresRegister());
1894 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001895 break;
1896
1897 default:
1898 LOG(FATAL) << "Unexpected type conversion from " << input_type
1899 << " to " << result_type;
1900 }
1901 break;
1902
Roland Levillain981e4542014-11-14 11:47:14 +00001903 case Primitive::kPrimChar:
1904 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001905 case Primitive::kPrimBoolean:
1906 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001907 case Primitive::kPrimByte:
1908 case Primitive::kPrimShort:
1909 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001910 // Processing a Dex `int-to-char' instruction.
1911 locations->SetInAt(0, Location::Any());
1912 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1913 break;
1914
1915 default:
1916 LOG(FATAL) << "Unexpected type conversion from " << input_type
1917 << " to " << result_type;
1918 }
1919 break;
1920
Roland Levillaindff1f282014-11-05 14:15:05 +00001921 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001922 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001923 case Primitive::kPrimBoolean:
1924 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001925 case Primitive::kPrimByte:
1926 case Primitive::kPrimShort:
1927 case Primitive::kPrimInt:
1928 case Primitive::kPrimChar:
1929 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001930 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001931 locations->SetOut(Location::RequiresFpuRegister());
1932 break;
1933
1934 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001935 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001936 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001937 locations->SetOut(Location::RequiresFpuRegister());
1938 break;
1939
Roland Levillaincff13742014-11-17 14:32:17 +00001940 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001941 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001942 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001943 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001944 break;
1945
1946 default:
1947 LOG(FATAL) << "Unexpected type conversion from " << input_type
1948 << " to " << result_type;
1949 };
1950 break;
1951
Roland Levillaindff1f282014-11-05 14:15:05 +00001952 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001953 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001954 case Primitive::kPrimBoolean:
1955 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001956 case Primitive::kPrimByte:
1957 case Primitive::kPrimShort:
1958 case Primitive::kPrimInt:
1959 case Primitive::kPrimChar:
1960 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001961 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001962 locations->SetOut(Location::RequiresFpuRegister());
1963 break;
1964
1965 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001966 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001967 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001968 locations->SetOut(Location::RequiresFpuRegister());
1969 break;
1970
Roland Levillaincff13742014-11-17 14:32:17 +00001971 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001972 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001973 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001974 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001975 break;
1976
1977 default:
1978 LOG(FATAL) << "Unexpected type conversion from " << input_type
1979 << " to " << result_type;
1980 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001981 break;
1982
1983 default:
1984 LOG(FATAL) << "Unexpected type conversion from " << input_type
1985 << " to " << result_type;
1986 }
1987}
1988
1989void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1990 LocationSummary* locations = conversion->GetLocations();
1991 Location out = locations->Out();
1992 Location in = locations->InAt(0);
1993 Primitive::Type result_type = conversion->GetResultType();
1994 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001995 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001996 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001997 case Primitive::kPrimByte:
1998 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001999 case Primitive::kPrimBoolean:
2000 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002001 case Primitive::kPrimShort:
2002 case Primitive::kPrimInt:
2003 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002004 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002005 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002006 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002007 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002008 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002009 Address(CpuRegister(RSP), in.GetStackIndex()));
2010 } else {
2011 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002012 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002013 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2014 }
2015 break;
2016
2017 default:
2018 LOG(FATAL) << "Unexpected type conversion from " << input_type
2019 << " to " << result_type;
2020 }
2021 break;
2022
Roland Levillain01a8d712014-11-14 16:27:39 +00002023 case Primitive::kPrimShort:
2024 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002025 case Primitive::kPrimBoolean:
2026 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002027 case Primitive::kPrimByte:
2028 case Primitive::kPrimInt:
2029 case Primitive::kPrimChar:
2030 // Processing a Dex `int-to-short' instruction.
2031 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002032 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002033 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002034 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002035 Address(CpuRegister(RSP), in.GetStackIndex()));
2036 } else {
2037 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002038 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002039 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2040 }
2041 break;
2042
2043 default:
2044 LOG(FATAL) << "Unexpected type conversion from " << input_type
2045 << " to " << result_type;
2046 }
2047 break;
2048
Roland Levillain946e1432014-11-11 17:35:19 +00002049 case Primitive::kPrimInt:
2050 switch (input_type) {
2051 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002052 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002053 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002054 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002055 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002056 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002057 Address(CpuRegister(RSP), in.GetStackIndex()));
2058 } else {
2059 DCHECK(in.IsConstant());
2060 DCHECK(in.GetConstant()->IsLongConstant());
2061 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002062 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002063 }
2064 break;
2065
Roland Levillain3f8f9362014-12-02 17:45:01 +00002066 case Primitive::kPrimFloat: {
2067 // Processing a Dex `float-to-int' instruction.
2068 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2069 CpuRegister output = out.AsRegister<CpuRegister>();
2070 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2071 Label done, nan;
2072
2073 __ movl(output, Immediate(kPrimIntMax));
2074 // temp = int-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00002075 __ cvtsi2ss(temp, output, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002076 // if input >= temp goto done
2077 __ comiss(input, temp);
2078 __ j(kAboveEqual, &done);
2079 // if input == NaN goto nan
2080 __ j(kUnordered, &nan);
2081 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002082 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002083 __ jmp(&done);
2084 __ Bind(&nan);
2085 // output = 0
2086 __ xorl(output, output);
2087 __ Bind(&done);
2088 break;
2089 }
2090
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002091 case Primitive::kPrimDouble: {
2092 // Processing a Dex `double-to-int' instruction.
2093 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2094 CpuRegister output = out.AsRegister<CpuRegister>();
2095 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2096 Label done, nan;
2097
2098 __ movl(output, Immediate(kPrimIntMax));
2099 // temp = int-to-double(output)
2100 __ cvtsi2sd(temp, output);
2101 // if input >= temp goto done
2102 __ comisd(input, temp);
2103 __ j(kAboveEqual, &done);
2104 // if input == NaN goto nan
2105 __ j(kUnordered, &nan);
2106 // output = double-to-int-truncate(input)
2107 __ cvttsd2si(output, input);
2108 __ jmp(&done);
2109 __ Bind(&nan);
2110 // output = 0
2111 __ xorl(output, output);
2112 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002113 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002114 }
Roland Levillain946e1432014-11-11 17:35:19 +00002115
2116 default:
2117 LOG(FATAL) << "Unexpected type conversion from " << input_type
2118 << " to " << result_type;
2119 }
2120 break;
2121
Roland Levillaindff1f282014-11-05 14:15:05 +00002122 case Primitive::kPrimLong:
2123 switch (input_type) {
2124 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002125 case Primitive::kPrimBoolean:
2126 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002127 case Primitive::kPrimByte:
2128 case Primitive::kPrimShort:
2129 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002130 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002131 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002132 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002133 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002134 break;
2135
Roland Levillain624279f2014-12-04 11:54:28 +00002136 case Primitive::kPrimFloat: {
2137 // Processing a Dex `float-to-long' instruction.
2138 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2139 CpuRegister output = out.AsRegister<CpuRegister>();
2140 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2141 Label done, nan;
2142
Mark Mendell92e83bf2015-05-07 11:25:03 -04002143 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002144 // temp = long-to-float(output)
Roland Levillain624279f2014-12-04 11:54:28 +00002145 __ cvtsi2ss(temp, output, true);
2146 // if input >= temp goto done
2147 __ comiss(input, temp);
2148 __ j(kAboveEqual, &done);
2149 // if input == NaN goto nan
2150 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002151 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002152 __ cvttss2si(output, input, true);
2153 __ jmp(&done);
2154 __ Bind(&nan);
2155 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002156 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002157 __ Bind(&done);
2158 break;
2159 }
2160
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002161 case Primitive::kPrimDouble: {
2162 // Processing a Dex `double-to-long' instruction.
2163 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2164 CpuRegister output = out.AsRegister<CpuRegister>();
2165 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2166 Label done, nan;
2167
Mark Mendell92e83bf2015-05-07 11:25:03 -04002168 codegen_->Load64BitValue(output, kPrimLongMax);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002169 // temp = long-to-double(output)
2170 __ cvtsi2sd(temp, output, true);
2171 // if input >= temp goto done
2172 __ comisd(input, temp);
2173 __ j(kAboveEqual, &done);
2174 // if input == NaN goto nan
2175 __ j(kUnordered, &nan);
2176 // output = double-to-long-truncate(input)
2177 __ cvttsd2si(output, input, true);
2178 __ jmp(&done);
2179 __ Bind(&nan);
2180 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002181 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002182 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002183 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002184 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002185
2186 default:
2187 LOG(FATAL) << "Unexpected type conversion from " << input_type
2188 << " to " << result_type;
2189 }
2190 break;
2191
Roland Levillain981e4542014-11-14 11:47:14 +00002192 case Primitive::kPrimChar:
2193 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002194 case Primitive::kPrimBoolean:
2195 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002196 case Primitive::kPrimByte:
2197 case Primitive::kPrimShort:
2198 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002199 // Processing a Dex `int-to-char' instruction.
2200 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002201 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002202 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002203 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002204 Address(CpuRegister(RSP), in.GetStackIndex()));
2205 } else {
2206 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002207 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002208 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2209 }
2210 break;
2211
2212 default:
2213 LOG(FATAL) << "Unexpected type conversion from " << input_type
2214 << " to " << result_type;
2215 }
2216 break;
2217
Roland Levillaindff1f282014-11-05 14:15:05 +00002218 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002219 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002220 case Primitive::kPrimBoolean:
2221 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002222 case Primitive::kPrimByte:
2223 case Primitive::kPrimShort:
2224 case Primitive::kPrimInt:
2225 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002226 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002227 if (in.IsRegister()) {
2228 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2229 } else if (in.IsConstant()) {
2230 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2231 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2232 if (v == 0) {
2233 __ xorps(dest, dest);
2234 } else {
2235 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2236 }
2237 } else {
2238 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2239 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2240 }
Roland Levillaincff13742014-11-17 14:32:17 +00002241 break;
2242
2243 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002244 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002245 if (in.IsRegister()) {
2246 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2247 } else if (in.IsConstant()) {
2248 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2249 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2250 if (v == 0) {
2251 __ xorps(dest, dest);
2252 } else {
2253 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2254 }
2255 } else {
2256 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2257 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2258 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002259 break;
2260
Roland Levillaincff13742014-11-17 14:32:17 +00002261 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002262 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002263 if (in.IsFpuRegister()) {
2264 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2265 } else if (in.IsConstant()) {
2266 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2267 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2268 if (bit_cast<int64_t, double>(v) == 0) {
2269 __ xorps(dest, dest);
2270 } else {
2271 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2272 }
2273 } else {
2274 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2275 Address(CpuRegister(RSP), in.GetStackIndex()));
2276 }
Roland Levillaincff13742014-11-17 14:32:17 +00002277 break;
2278
2279 default:
2280 LOG(FATAL) << "Unexpected type conversion from " << input_type
2281 << " to " << result_type;
2282 };
2283 break;
2284
Roland Levillaindff1f282014-11-05 14:15:05 +00002285 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002286 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002287 case Primitive::kPrimBoolean:
2288 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002289 case Primitive::kPrimByte:
2290 case Primitive::kPrimShort:
2291 case Primitive::kPrimInt:
2292 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002293 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002294 if (in.IsRegister()) {
2295 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2296 } else if (in.IsConstant()) {
2297 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2298 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2299 if (v == 0) {
2300 __ xorpd(dest, dest);
2301 } else {
2302 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2303 }
2304 } else {
2305 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2306 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2307 }
Roland Levillaincff13742014-11-17 14:32:17 +00002308 break;
2309
2310 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002311 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002312 if (in.IsRegister()) {
2313 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2314 } else if (in.IsConstant()) {
2315 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2316 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2317 if (v == 0) {
2318 __ xorpd(dest, dest);
2319 } else {
2320 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2321 }
2322 } else {
2323 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2324 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2325 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002326 break;
2327
Roland Levillaincff13742014-11-17 14:32:17 +00002328 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002329 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002330 if (in.IsFpuRegister()) {
2331 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2332 } else if (in.IsConstant()) {
2333 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2334 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2335 if (bit_cast<int32_t, float>(v) == 0) {
2336 __ xorpd(dest, dest);
2337 } else {
2338 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2339 }
2340 } else {
2341 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2342 Address(CpuRegister(RSP), in.GetStackIndex()));
2343 }
Roland Levillaincff13742014-11-17 14:32:17 +00002344 break;
2345
2346 default:
2347 LOG(FATAL) << "Unexpected type conversion from " << input_type
2348 << " to " << result_type;
2349 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002350 break;
2351
2352 default:
2353 LOG(FATAL) << "Unexpected type conversion from " << input_type
2354 << " to " << result_type;
2355 }
2356}
2357
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002358void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002359 LocationSummary* locations =
2360 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002361 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002362 case Primitive::kPrimInt: {
2363 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002364 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2365 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002366 break;
2367 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002368
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002369 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002370 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002371 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002372 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002373 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002374 break;
2375 }
2376
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002377 case Primitive::kPrimDouble:
2378 case Primitive::kPrimFloat: {
2379 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002380 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002381 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002382 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002383 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002384
2385 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002386 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002387 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002388}
2389
2390void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2391 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002392 Location first = locations->InAt(0);
2393 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002394 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002395
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002396 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002397 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002398 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002399 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2400 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002401 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2402 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002403 } else {
2404 __ leal(out.AsRegister<CpuRegister>(), Address(
2405 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2406 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002407 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002408 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2409 __ addl(out.AsRegister<CpuRegister>(),
2410 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2411 } else {
2412 __ leal(out.AsRegister<CpuRegister>(), Address(
2413 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2414 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002415 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002416 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002417 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002418 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002419 break;
2420 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002421
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002422 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002423 if (second.IsRegister()) {
2424 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2425 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002426 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2427 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002428 } else {
2429 __ leaq(out.AsRegister<CpuRegister>(), Address(
2430 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2431 }
2432 } else {
2433 DCHECK(second.IsConstant());
2434 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2435 int32_t int32_value = Low32Bits(value);
2436 DCHECK_EQ(int32_value, value);
2437 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2438 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2439 } else {
2440 __ leaq(out.AsRegister<CpuRegister>(), Address(
2441 first.AsRegister<CpuRegister>(), int32_value));
2442 }
2443 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002444 break;
2445 }
2446
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002447 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002448 if (second.IsFpuRegister()) {
2449 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2450 } else if (second.IsConstant()) {
2451 __ addss(first.AsFpuRegister<XmmRegister>(),
2452 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2453 } else {
2454 DCHECK(second.IsStackSlot());
2455 __ addss(first.AsFpuRegister<XmmRegister>(),
2456 Address(CpuRegister(RSP), second.GetStackIndex()));
2457 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002458 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002459 }
2460
2461 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002462 if (second.IsFpuRegister()) {
2463 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2464 } else if (second.IsConstant()) {
2465 __ addsd(first.AsFpuRegister<XmmRegister>(),
2466 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2467 } else {
2468 DCHECK(second.IsDoubleStackSlot());
2469 __ addsd(first.AsFpuRegister<XmmRegister>(),
2470 Address(CpuRegister(RSP), second.GetStackIndex()));
2471 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002472 break;
2473 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002474
2475 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002476 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002477 }
2478}
2479
2480void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002481 LocationSummary* locations =
2482 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002483 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002484 case Primitive::kPrimInt: {
2485 locations->SetInAt(0, Location::RequiresRegister());
2486 locations->SetInAt(1, Location::Any());
2487 locations->SetOut(Location::SameAsFirstInput());
2488 break;
2489 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002490 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002491 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002492 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002493 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002494 break;
2495 }
Calin Juravle11351682014-10-23 15:38:15 +01002496 case Primitive::kPrimFloat:
2497 case Primitive::kPrimDouble: {
2498 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002499 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002500 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002501 break;
Calin Juravle11351682014-10-23 15:38:15 +01002502 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002503 default:
Calin Juravle11351682014-10-23 15:38:15 +01002504 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002505 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002506}
2507
2508void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2509 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002510 Location first = locations->InAt(0);
2511 Location second = locations->InAt(1);
2512 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002513 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002514 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002515 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002516 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002517 } else if (second.IsConstant()) {
2518 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002519 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002520 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002521 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002522 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002523 break;
2524 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002525 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002526 if (second.IsConstant()) {
2527 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2528 DCHECK(IsInt<32>(value));
2529 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2530 } else {
2531 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2532 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002533 break;
2534 }
2535
Calin Juravle11351682014-10-23 15:38:15 +01002536 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002537 if (second.IsFpuRegister()) {
2538 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2539 } else if (second.IsConstant()) {
2540 __ subss(first.AsFpuRegister<XmmRegister>(),
2541 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2542 } else {
2543 DCHECK(second.IsStackSlot());
2544 __ subss(first.AsFpuRegister<XmmRegister>(),
2545 Address(CpuRegister(RSP), second.GetStackIndex()));
2546 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002547 break;
Calin Juravle11351682014-10-23 15:38:15 +01002548 }
2549
2550 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002551 if (second.IsFpuRegister()) {
2552 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2553 } else if (second.IsConstant()) {
2554 __ subsd(first.AsFpuRegister<XmmRegister>(),
2555 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2556 } else {
2557 DCHECK(second.IsDoubleStackSlot());
2558 __ subsd(first.AsFpuRegister<XmmRegister>(),
2559 Address(CpuRegister(RSP), second.GetStackIndex()));
2560 }
Calin Juravle11351682014-10-23 15:38:15 +01002561 break;
2562 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002563
2564 default:
Calin Juravle11351682014-10-23 15:38:15 +01002565 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002566 }
2567}
2568
Calin Juravle34bacdf2014-10-07 20:23:36 +01002569void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2570 LocationSummary* locations =
2571 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2572 switch (mul->GetResultType()) {
2573 case Primitive::kPrimInt: {
2574 locations->SetInAt(0, Location::RequiresRegister());
2575 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002576 if (mul->InputAt(1)->IsIntConstant()) {
2577 // Can use 3 operand multiply.
2578 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2579 } else {
2580 locations->SetOut(Location::SameAsFirstInput());
2581 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002582 break;
2583 }
2584 case Primitive::kPrimLong: {
2585 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002586 locations->SetInAt(1, Location::Any());
2587 if (mul->InputAt(1)->IsLongConstant() &&
2588 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002589 // Can use 3 operand multiply.
2590 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2591 } else {
2592 locations->SetOut(Location::SameAsFirstInput());
2593 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002594 break;
2595 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002596 case Primitive::kPrimFloat:
2597 case Primitive::kPrimDouble: {
2598 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002599 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002600 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002601 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002602 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002603
2604 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002605 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002606 }
2607}
2608
2609void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2610 LocationSummary* locations = mul->GetLocations();
2611 Location first = locations->InAt(0);
2612 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002613 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002614 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002615 case Primitive::kPrimInt:
2616 // The constant may have ended up in a register, so test explicitly to avoid
2617 // problems where the output may not be the same as the first operand.
2618 if (mul->InputAt(1)->IsIntConstant()) {
2619 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2620 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2621 } else if (second.IsRegister()) {
2622 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002623 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002624 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002625 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002626 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002627 __ imull(first.AsRegister<CpuRegister>(),
2628 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002629 }
2630 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002631 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002632 // The constant may have ended up in a register, so test explicitly to avoid
2633 // problems where the output may not be the same as the first operand.
2634 if (mul->InputAt(1)->IsLongConstant()) {
2635 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2636 if (IsInt<32>(value)) {
2637 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2638 Immediate(static_cast<int32_t>(value)));
2639 } else {
2640 // Have to use the constant area.
2641 DCHECK(first.Equals(out));
2642 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2643 }
2644 } else if (second.IsRegister()) {
2645 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002646 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002647 } else {
2648 DCHECK(second.IsDoubleStackSlot());
2649 DCHECK(first.Equals(out));
2650 __ imulq(first.AsRegister<CpuRegister>(),
2651 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002652 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002653 break;
2654 }
2655
Calin Juravleb5bfa962014-10-21 18:02:24 +01002656 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002657 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002658 if (second.IsFpuRegister()) {
2659 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2660 } else if (second.IsConstant()) {
2661 __ mulss(first.AsFpuRegister<XmmRegister>(),
2662 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2663 } else {
2664 DCHECK(second.IsStackSlot());
2665 __ mulss(first.AsFpuRegister<XmmRegister>(),
2666 Address(CpuRegister(RSP), second.GetStackIndex()));
2667 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002668 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002669 }
2670
2671 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002672 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002673 if (second.IsFpuRegister()) {
2674 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2675 } else if (second.IsConstant()) {
2676 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2677 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2678 } else {
2679 DCHECK(second.IsDoubleStackSlot());
2680 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2681 Address(CpuRegister(RSP), second.GetStackIndex()));
2682 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002683 break;
2684 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002685
2686 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002687 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002688 }
2689}
2690
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002691void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2692 uint32_t stack_adjustment, bool is_float) {
2693 if (source.IsStackSlot()) {
2694 DCHECK(is_float);
2695 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2696 } else if (source.IsDoubleStackSlot()) {
2697 DCHECK(!is_float);
2698 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2699 } else {
2700 // Write the value to the temporary location on the stack and load to FP stack.
2701 if (is_float) {
2702 Location stack_temp = Location::StackSlot(temp_offset);
2703 codegen_->Move(stack_temp, source);
2704 __ flds(Address(CpuRegister(RSP), temp_offset));
2705 } else {
2706 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2707 codegen_->Move(stack_temp, source);
2708 __ fldl(Address(CpuRegister(RSP), temp_offset));
2709 }
2710 }
2711}
2712
2713void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2714 Primitive::Type type = rem->GetResultType();
2715 bool is_float = type == Primitive::kPrimFloat;
2716 size_t elem_size = Primitive::ComponentSize(type);
2717 LocationSummary* locations = rem->GetLocations();
2718 Location first = locations->InAt(0);
2719 Location second = locations->InAt(1);
2720 Location out = locations->Out();
2721
2722 // Create stack space for 2 elements.
2723 // TODO: enhance register allocator to ask for stack temporaries.
2724 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2725
2726 // Load the values to the FP stack in reverse order, using temporaries if needed.
2727 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2728 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2729
2730 // Loop doing FPREM until we stabilize.
2731 Label retry;
2732 __ Bind(&retry);
2733 __ fprem();
2734
2735 // Move FP status to AX.
2736 __ fstsw();
2737
2738 // And see if the argument reduction is complete. This is signaled by the
2739 // C2 FPU flag bit set to 0.
2740 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2741 __ j(kNotEqual, &retry);
2742
2743 // We have settled on the final value. Retrieve it into an XMM register.
2744 // Store FP top of stack to real stack.
2745 if (is_float) {
2746 __ fsts(Address(CpuRegister(RSP), 0));
2747 } else {
2748 __ fstl(Address(CpuRegister(RSP), 0));
2749 }
2750
2751 // Pop the 2 items from the FP stack.
2752 __ fucompp();
2753
2754 // Load the value from the stack into an XMM register.
2755 DCHECK(out.IsFpuRegister()) << out;
2756 if (is_float) {
2757 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2758 } else {
2759 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2760 }
2761
2762 // And remove the temporary stack space we allocated.
2763 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2764}
2765
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002766void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2767 DCHECK(instruction->IsDiv() || instruction->IsRem());
2768
2769 LocationSummary* locations = instruction->GetLocations();
2770 Location second = locations->InAt(1);
2771 DCHECK(second.IsConstant());
2772
2773 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2774 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002775 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002776
2777 DCHECK(imm == 1 || imm == -1);
2778
2779 switch (instruction->GetResultType()) {
2780 case Primitive::kPrimInt: {
2781 if (instruction->IsRem()) {
2782 __ xorl(output_register, output_register);
2783 } else {
2784 __ movl(output_register, input_register);
2785 if (imm == -1) {
2786 __ negl(output_register);
2787 }
2788 }
2789 break;
2790 }
2791
2792 case Primitive::kPrimLong: {
2793 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002794 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002795 } else {
2796 __ movq(output_register, input_register);
2797 if (imm == -1) {
2798 __ negq(output_register);
2799 }
2800 }
2801 break;
2802 }
2803
2804 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002805 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002806 }
2807}
2808
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002809void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002810 LocationSummary* locations = instruction->GetLocations();
2811 Location second = locations->InAt(1);
2812
2813 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2814 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2815
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002816 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002817
2818 DCHECK(IsPowerOfTwo(std::abs(imm)));
2819
2820 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2821
2822 if (instruction->GetResultType() == Primitive::kPrimInt) {
2823 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2824 __ testl(numerator, numerator);
2825 __ cmov(kGreaterEqual, tmp, numerator);
2826 int shift = CTZ(imm);
2827 __ sarl(tmp, Immediate(shift));
2828
2829 if (imm < 0) {
2830 __ negl(tmp);
2831 }
2832
2833 __ movl(output_register, tmp);
2834 } else {
2835 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2836 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2837
Mark Mendell92e83bf2015-05-07 11:25:03 -04002838 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002839 __ addq(rdx, numerator);
2840 __ testq(numerator, numerator);
2841 __ cmov(kGreaterEqual, rdx, numerator);
2842 int shift = CTZ(imm);
2843 __ sarq(rdx, Immediate(shift));
2844
2845 if (imm < 0) {
2846 __ negq(rdx);
2847 }
2848
2849 __ movq(output_register, rdx);
2850 }
2851}
2852
2853void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2854 DCHECK(instruction->IsDiv() || instruction->IsRem());
2855
2856 LocationSummary* locations = instruction->GetLocations();
2857 Location second = locations->InAt(1);
2858
2859 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2860 : locations->GetTemp(0).AsRegister<CpuRegister>();
2861 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2862 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2863 : locations->Out().AsRegister<CpuRegister>();
2864 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2865
2866 DCHECK_EQ(RAX, eax.AsRegister());
2867 DCHECK_EQ(RDX, edx.AsRegister());
2868 if (instruction->IsDiv()) {
2869 DCHECK_EQ(RAX, out.AsRegister());
2870 } else {
2871 DCHECK_EQ(RDX, out.AsRegister());
2872 }
2873
2874 int64_t magic;
2875 int shift;
2876
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002877 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002878 if (instruction->GetResultType() == Primitive::kPrimInt) {
2879 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2880
2881 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2882
2883 __ movl(numerator, eax);
2884
2885 Label no_div;
2886 Label end;
2887 __ testl(eax, eax);
2888 __ j(kNotEqual, &no_div);
2889
2890 __ xorl(out, out);
2891 __ jmp(&end);
2892
2893 __ Bind(&no_div);
2894
2895 __ movl(eax, Immediate(magic));
2896 __ imull(numerator);
2897
2898 if (imm > 0 && magic < 0) {
2899 __ addl(edx, numerator);
2900 } else if (imm < 0 && magic > 0) {
2901 __ subl(edx, numerator);
2902 }
2903
2904 if (shift != 0) {
2905 __ sarl(edx, Immediate(shift));
2906 }
2907
2908 __ movl(eax, edx);
2909 __ shrl(edx, Immediate(31));
2910 __ addl(edx, eax);
2911
2912 if (instruction->IsRem()) {
2913 __ movl(eax, numerator);
2914 __ imull(edx, Immediate(imm));
2915 __ subl(eax, edx);
2916 __ movl(edx, eax);
2917 } else {
2918 __ movl(eax, edx);
2919 }
2920 __ Bind(&end);
2921 } else {
2922 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2923
2924 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2925
2926 CpuRegister rax = eax;
2927 CpuRegister rdx = edx;
2928
2929 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2930
2931 // Save the numerator.
2932 __ movq(numerator, rax);
2933
2934 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002935 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002936
2937 // RDX:RAX = magic * numerator
2938 __ imulq(numerator);
2939
2940 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002941 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002942 __ addq(rdx, numerator);
2943 } else if (imm < 0 && magic > 0) {
2944 // RDX -= numerator
2945 __ subq(rdx, numerator);
2946 }
2947
2948 // Shift if needed.
2949 if (shift != 0) {
2950 __ sarq(rdx, Immediate(shift));
2951 }
2952
2953 // RDX += 1 if RDX < 0
2954 __ movq(rax, rdx);
2955 __ shrq(rdx, Immediate(63));
2956 __ addq(rdx, rax);
2957
2958 if (instruction->IsRem()) {
2959 __ movq(rax, numerator);
2960
2961 if (IsInt<32>(imm)) {
2962 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
2963 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002964 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002965 }
2966
2967 __ subq(rax, rdx);
2968 __ movq(rdx, rax);
2969 } else {
2970 __ movq(rax, rdx);
2971 }
2972 }
2973}
2974
Calin Juravlebacfec32014-11-14 15:54:36 +00002975void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2976 DCHECK(instruction->IsDiv() || instruction->IsRem());
2977 Primitive::Type type = instruction->GetResultType();
2978 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
2979
2980 bool is_div = instruction->IsDiv();
2981 LocationSummary* locations = instruction->GetLocations();
2982
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002983 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2984 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00002985
Roland Levillain271ab9c2014-11-27 15:23:57 +00002986 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002987 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00002988
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002989 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002990 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00002991
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002992 if (imm == 0) {
2993 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2994 } else if (imm == 1 || imm == -1) {
2995 DivRemOneOrMinusOne(instruction);
2996 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002997 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002998 } else {
2999 DCHECK(imm <= -2 || imm >= 2);
3000 GenerateDivRemWithAnyConstant(instruction);
3001 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003002 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003003 SlowPathCodeX86_64* slow_path =
3004 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3005 out.AsRegister(), type, is_div);
3006 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003007
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003008 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3009 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3010 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3011 // so it's safe to just use negl instead of more complex comparisons.
3012 if (type == Primitive::kPrimInt) {
3013 __ cmpl(second_reg, Immediate(-1));
3014 __ j(kEqual, slow_path->GetEntryLabel());
3015 // edx:eax <- sign-extended of eax
3016 __ cdq();
3017 // eax = quotient, edx = remainder
3018 __ idivl(second_reg);
3019 } else {
3020 __ cmpq(second_reg, Immediate(-1));
3021 __ j(kEqual, slow_path->GetEntryLabel());
3022 // rdx:rax <- sign-extended of rax
3023 __ cqo();
3024 // rax = quotient, rdx = remainder
3025 __ idivq(second_reg);
3026 }
3027 __ Bind(slow_path->GetExitLabel());
3028 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003029}
3030
Calin Juravle7c4954d2014-10-28 16:57:40 +00003031void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3032 LocationSummary* locations =
3033 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3034 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003035 case Primitive::kPrimInt:
3036 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003037 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003038 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003039 locations->SetOut(Location::SameAsFirstInput());
3040 // Intel uses edx:eax as the dividend.
3041 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003042 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3043 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3044 // output and request another temp.
3045 if (div->InputAt(1)->IsConstant()) {
3046 locations->AddTemp(Location::RequiresRegister());
3047 }
Calin Juravled0d48522014-11-04 16:40:20 +00003048 break;
3049 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003050
Calin Juravle7c4954d2014-10-28 16:57:40 +00003051 case Primitive::kPrimFloat:
3052 case Primitive::kPrimDouble: {
3053 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003054 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003055 locations->SetOut(Location::SameAsFirstInput());
3056 break;
3057 }
3058
3059 default:
3060 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3061 }
3062}
3063
3064void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3065 LocationSummary* locations = div->GetLocations();
3066 Location first = locations->InAt(0);
3067 Location second = locations->InAt(1);
3068 DCHECK(first.Equals(locations->Out()));
3069
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003070 Primitive::Type type = div->GetResultType();
3071 switch (type) {
3072 case Primitive::kPrimInt:
3073 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003074 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003075 break;
3076 }
3077
Calin Juravle7c4954d2014-10-28 16:57:40 +00003078 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003079 if (second.IsFpuRegister()) {
3080 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3081 } else if (second.IsConstant()) {
3082 __ divss(first.AsFpuRegister<XmmRegister>(),
3083 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3084 } else {
3085 DCHECK(second.IsStackSlot());
3086 __ divss(first.AsFpuRegister<XmmRegister>(),
3087 Address(CpuRegister(RSP), second.GetStackIndex()));
3088 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003089 break;
3090 }
3091
3092 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003093 if (second.IsFpuRegister()) {
3094 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3095 } else if (second.IsConstant()) {
3096 __ divsd(first.AsFpuRegister<XmmRegister>(),
3097 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3098 } else {
3099 DCHECK(second.IsDoubleStackSlot());
3100 __ divsd(first.AsFpuRegister<XmmRegister>(),
3101 Address(CpuRegister(RSP), second.GetStackIndex()));
3102 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003103 break;
3104 }
3105
3106 default:
3107 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3108 }
3109}
3110
Calin Juravlebacfec32014-11-14 15:54:36 +00003111void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003112 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003113 LocationSummary* locations =
3114 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003115
3116 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003117 case Primitive::kPrimInt:
3118 case Primitive::kPrimLong: {
3119 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003120 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003121 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3122 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003123 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3124 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3125 // output and request another temp.
3126 if (rem->InputAt(1)->IsConstant()) {
3127 locations->AddTemp(Location::RequiresRegister());
3128 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003129 break;
3130 }
3131
3132 case Primitive::kPrimFloat:
3133 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003134 locations->SetInAt(0, Location::Any());
3135 locations->SetInAt(1, Location::Any());
3136 locations->SetOut(Location::RequiresFpuRegister());
3137 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003138 break;
3139 }
3140
3141 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003142 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003143 }
3144}
3145
3146void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3147 Primitive::Type type = rem->GetResultType();
3148 switch (type) {
3149 case Primitive::kPrimInt:
3150 case Primitive::kPrimLong: {
3151 GenerateDivRemIntegral(rem);
3152 break;
3153 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003154 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003155 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003156 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003157 break;
3158 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003159 default:
3160 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3161 }
3162}
3163
Calin Juravled0d48522014-11-04 16:40:20 +00003164void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3165 LocationSummary* locations =
3166 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3167 locations->SetInAt(0, Location::Any());
3168 if (instruction->HasUses()) {
3169 locations->SetOut(Location::SameAsFirstInput());
3170 }
3171}
3172
3173void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3174 SlowPathCodeX86_64* slow_path =
3175 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3176 codegen_->AddSlowPath(slow_path);
3177
3178 LocationSummary* locations = instruction->GetLocations();
3179 Location value = locations->InAt(0);
3180
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003181 switch (instruction->GetType()) {
3182 case Primitive::kPrimInt: {
3183 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003184 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003185 __ j(kEqual, slow_path->GetEntryLabel());
3186 } else if (value.IsStackSlot()) {
3187 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3188 __ j(kEqual, slow_path->GetEntryLabel());
3189 } else {
3190 DCHECK(value.IsConstant()) << value;
3191 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3192 __ jmp(slow_path->GetEntryLabel());
3193 }
3194 }
3195 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003196 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003197 case Primitive::kPrimLong: {
3198 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003199 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003200 __ j(kEqual, slow_path->GetEntryLabel());
3201 } else if (value.IsDoubleStackSlot()) {
3202 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3203 __ j(kEqual, slow_path->GetEntryLabel());
3204 } else {
3205 DCHECK(value.IsConstant()) << value;
3206 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3207 __ jmp(slow_path->GetEntryLabel());
3208 }
3209 }
3210 break;
3211 }
3212 default:
3213 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003214 }
Calin Juravled0d48522014-11-04 16:40:20 +00003215}
3216
Calin Juravle9aec02f2014-11-18 23:06:35 +00003217void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3218 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3219
3220 LocationSummary* locations =
3221 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3222
3223 switch (op->GetResultType()) {
3224 case Primitive::kPrimInt:
3225 case Primitive::kPrimLong: {
3226 locations->SetInAt(0, Location::RequiresRegister());
3227 // The shift count needs to be in CL.
3228 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3229 locations->SetOut(Location::SameAsFirstInput());
3230 break;
3231 }
3232 default:
3233 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3234 }
3235}
3236
3237void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3238 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3239
3240 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003241 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003242 Location second = locations->InAt(1);
3243
3244 switch (op->GetResultType()) {
3245 case Primitive::kPrimInt: {
3246 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003247 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003248 if (op->IsShl()) {
3249 __ shll(first_reg, second_reg);
3250 } else if (op->IsShr()) {
3251 __ sarl(first_reg, second_reg);
3252 } else {
3253 __ shrl(first_reg, second_reg);
3254 }
3255 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003256 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003257 if (op->IsShl()) {
3258 __ shll(first_reg, imm);
3259 } else if (op->IsShr()) {
3260 __ sarl(first_reg, imm);
3261 } else {
3262 __ shrl(first_reg, imm);
3263 }
3264 }
3265 break;
3266 }
3267 case Primitive::kPrimLong: {
3268 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003269 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003270 if (op->IsShl()) {
3271 __ shlq(first_reg, second_reg);
3272 } else if (op->IsShr()) {
3273 __ sarq(first_reg, second_reg);
3274 } else {
3275 __ shrq(first_reg, second_reg);
3276 }
3277 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003278 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003279 if (op->IsShl()) {
3280 __ shlq(first_reg, imm);
3281 } else if (op->IsShr()) {
3282 __ sarq(first_reg, imm);
3283 } else {
3284 __ shrq(first_reg, imm);
3285 }
3286 }
3287 break;
3288 }
3289 default:
3290 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3291 }
3292}
3293
3294void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3295 HandleShift(shl);
3296}
3297
3298void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3299 HandleShift(shl);
3300}
3301
3302void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3303 HandleShift(shr);
3304}
3305
3306void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3307 HandleShift(shr);
3308}
3309
3310void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3311 HandleShift(ushr);
3312}
3313
3314void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3315 HandleShift(ushr);
3316}
3317
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003318void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003319 LocationSummary* locations =
3320 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003321 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003322 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003323 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003324 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003325}
3326
3327void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3328 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003329 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3330 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003331 // Note: if heap poisoning is enabled, the entry point takes cares
3332 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003333
3334 codegen_->InvokeRuntime(
3335 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3336 instruction,
3337 instruction->GetDexPc(),
3338 nullptr);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003339
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003340 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003341}
3342
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003343void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3344 LocationSummary* locations =
3345 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3346 InvokeRuntimeCallingConvention calling_convention;
3347 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003348 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003349 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003350 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003351}
3352
3353void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3354 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003355 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3356 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003357
Roland Levillain4d027112015-07-01 15:41:14 +01003358 // Note: if heap poisoning is enabled, the entry point takes cares
3359 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003360 codegen_->InvokeRuntime(
3361 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3362 instruction,
3363 instruction->GetDexPc(),
3364 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003365
3366 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003367}
3368
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003369void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003370 LocationSummary* locations =
3371 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003372 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3373 if (location.IsStackSlot()) {
3374 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3375 } else if (location.IsDoubleStackSlot()) {
3376 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3377 }
3378 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003379}
3380
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003381void InstructionCodeGeneratorX86_64::VisitParameterValue(
3382 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003383 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003384}
3385
3386void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3387 LocationSummary* locations =
3388 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3389 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3390}
3391
3392void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3393 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3394 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003395}
3396
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003397void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003398 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003399 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003400 locations->SetInAt(0, Location::RequiresRegister());
3401 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003402}
3403
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003404void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3405 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003406 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3407 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003408 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003409 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003410 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003411 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003412 break;
3413
3414 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003415 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003416 break;
3417
3418 default:
3419 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3420 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003421}
3422
David Brazdil66d126e2015-04-03 16:02:44 +01003423void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3424 LocationSummary* locations =
3425 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3426 locations->SetInAt(0, Location::RequiresRegister());
3427 locations->SetOut(Location::SameAsFirstInput());
3428}
3429
3430void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003431 LocationSummary* locations = bool_not->GetLocations();
3432 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3433 locations->Out().AsRegister<CpuRegister>().AsRegister());
3434 Location out = locations->Out();
3435 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3436}
3437
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003438void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003439 LocationSummary* locations =
3440 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003441 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3442 locations->SetInAt(i, Location::Any());
3443 }
3444 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003445}
3446
3447void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003448 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003449 LOG(FATAL) << "Unimplemented";
3450}
3451
Calin Juravle52c48962014-12-16 17:02:57 +00003452void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3453 /*
3454 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3455 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3456 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3457 */
3458 switch (kind) {
3459 case MemBarrierKind::kAnyAny: {
3460 __ mfence();
3461 break;
3462 }
3463 case MemBarrierKind::kAnyStore:
3464 case MemBarrierKind::kLoadAny:
3465 case MemBarrierKind::kStoreStore: {
3466 // nop
3467 break;
3468 }
3469 default:
3470 LOG(FATAL) << "Unexpected memory barier " << kind;
3471 }
3472}
3473
3474void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3475 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3476
Nicolas Geoffray39468442014-09-02 15:17:15 +01003477 LocationSummary* locations =
3478 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003479 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003480 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3481 locations->SetOut(Location::RequiresFpuRegister());
3482 } else {
3483 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3484 }
Calin Juravle52c48962014-12-16 17:02:57 +00003485}
3486
3487void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3488 const FieldInfo& field_info) {
3489 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3490
3491 LocationSummary* locations = instruction->GetLocations();
3492 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3493 Location out = locations->Out();
3494 bool is_volatile = field_info.IsVolatile();
3495 Primitive::Type field_type = field_info.GetFieldType();
3496 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3497
3498 switch (field_type) {
3499 case Primitive::kPrimBoolean: {
3500 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3501 break;
3502 }
3503
3504 case Primitive::kPrimByte: {
3505 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3506 break;
3507 }
3508
3509 case Primitive::kPrimShort: {
3510 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3511 break;
3512 }
3513
3514 case Primitive::kPrimChar: {
3515 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3516 break;
3517 }
3518
3519 case Primitive::kPrimInt:
3520 case Primitive::kPrimNot: {
3521 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3522 break;
3523 }
3524
3525 case Primitive::kPrimLong: {
3526 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3527 break;
3528 }
3529
3530 case Primitive::kPrimFloat: {
3531 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3532 break;
3533 }
3534
3535 case Primitive::kPrimDouble: {
3536 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3537 break;
3538 }
3539
3540 case Primitive::kPrimVoid:
3541 LOG(FATAL) << "Unreachable type " << field_type;
3542 UNREACHABLE();
3543 }
3544
Calin Juravle77520bc2015-01-12 18:45:46 +00003545 codegen_->MaybeRecordImplicitNullCheck(instruction);
3546
Calin Juravle52c48962014-12-16 17:02:57 +00003547 if (is_volatile) {
3548 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3549 }
Roland Levillain4d027112015-07-01 15:41:14 +01003550
3551 if (field_type == Primitive::kPrimNot) {
3552 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3553 }
Calin Juravle52c48962014-12-16 17:02:57 +00003554}
3555
3556void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3557 const FieldInfo& field_info) {
3558 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3559
3560 LocationSummary* locations =
3561 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003562 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003563 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003564 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003565
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003566 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003567 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3568 locations->SetInAt(1, Location::RequiresFpuRegister());
3569 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003570 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003571 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003572 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003573 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003574 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003575 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003576 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3577 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003578 locations->AddTemp(Location::RequiresRegister());
3579 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003580}
3581
Calin Juravle52c48962014-12-16 17:02:57 +00003582void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003583 const FieldInfo& field_info,
3584 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003585 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3586
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003587 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003588 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3589 Location value = locations->InAt(1);
3590 bool is_volatile = field_info.IsVolatile();
3591 Primitive::Type field_type = field_info.GetFieldType();
3592 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3593
3594 if (is_volatile) {
3595 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3596 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003597
3598 switch (field_type) {
3599 case Primitive::kPrimBoolean:
3600 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003601 if (value.IsConstant()) {
3602 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3603 __ movb(Address(base, offset), Immediate(v));
3604 } else {
3605 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3606 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003607 break;
3608 }
3609
3610 case Primitive::kPrimShort:
3611 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003612 if (value.IsConstant()) {
3613 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3614 __ movw(Address(base, offset), Immediate(v));
3615 } else {
3616 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3617 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003618 break;
3619 }
3620
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003621 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003622 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003623 if (value.IsConstant()) {
3624 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003625 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3626 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3627 // Note: if heap poisoning is enabled, no need to poison
3628 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003629 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003630 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003631 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3632 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3633 __ movl(temp, value.AsRegister<CpuRegister>());
3634 __ PoisonHeapReference(temp);
3635 __ movl(Address(base, offset), temp);
3636 } else {
3637 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3638 }
Mark Mendell40741f32015-04-20 22:10:34 -04003639 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003640 break;
3641 }
3642
3643 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003644 if (value.IsConstant()) {
3645 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3646 DCHECK(IsInt<32>(v));
3647 int32_t v_32 = v;
3648 __ movq(Address(base, offset), Immediate(v_32));
3649 } else {
3650 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3651 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003652 break;
3653 }
3654
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003655 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003656 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003657 break;
3658 }
3659
3660 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003661 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003662 break;
3663 }
3664
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003665 case Primitive::kPrimVoid:
3666 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003667 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003668 }
Calin Juravle52c48962014-12-16 17:02:57 +00003669
Calin Juravle77520bc2015-01-12 18:45:46 +00003670 codegen_->MaybeRecordImplicitNullCheck(instruction);
3671
3672 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3673 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3674 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003675 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003676 }
3677
Calin Juravle52c48962014-12-16 17:02:57 +00003678 if (is_volatile) {
3679 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3680 }
3681}
3682
3683void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3684 HandleFieldSet(instruction, instruction->GetFieldInfo());
3685}
3686
3687void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003688 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003689}
3690
3691void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003692 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003693}
3694
3695void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003696 HandleFieldGet(instruction, instruction->GetFieldInfo());
3697}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003698
Calin Juravle52c48962014-12-16 17:02:57 +00003699void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3700 HandleFieldGet(instruction);
3701}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003702
Calin Juravle52c48962014-12-16 17:02:57 +00003703void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3704 HandleFieldGet(instruction, instruction->GetFieldInfo());
3705}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003706
Calin Juravle52c48962014-12-16 17:02:57 +00003707void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3708 HandleFieldSet(instruction, instruction->GetFieldInfo());
3709}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003710
Calin Juravle52c48962014-12-16 17:02:57 +00003711void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003712 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003713}
3714
3715void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003716 LocationSummary* locations =
3717 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003718 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3719 ? Location::RequiresRegister()
3720 : Location::Any();
3721 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003722 if (instruction->HasUses()) {
3723 locations->SetOut(Location::SameAsFirstInput());
3724 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003725}
3726
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003727void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003728 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3729 return;
3730 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003731 LocationSummary* locations = instruction->GetLocations();
3732 Location obj = locations->InAt(0);
3733
3734 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3735 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3736}
3737
3738void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003739 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003740 codegen_->AddSlowPath(slow_path);
3741
3742 LocationSummary* locations = instruction->GetLocations();
3743 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003744
3745 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003746 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003747 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003748 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003749 } else {
3750 DCHECK(obj.IsConstant()) << obj;
3751 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3752 __ jmp(slow_path->GetEntryLabel());
3753 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003754 }
3755 __ j(kEqual, slow_path->GetEntryLabel());
3756}
3757
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003758void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3759 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3760 GenerateImplicitNullCheck(instruction);
3761 } else {
3762 GenerateExplicitNullCheck(instruction);
3763 }
3764}
3765
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003766void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003767 LocationSummary* locations =
3768 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003769 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003770 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003771 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3772 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3773 } else {
3774 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3775 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003776}
3777
3778void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3779 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003780 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003781 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003782 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003783
Roland Levillain4d027112015-07-01 15:41:14 +01003784 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003785 case Primitive::kPrimBoolean: {
3786 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003787 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003788 if (index.IsConstant()) {
3789 __ movzxb(out, Address(obj,
3790 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3791 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003792 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003793 }
3794 break;
3795 }
3796
3797 case Primitive::kPrimByte: {
3798 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003799 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003800 if (index.IsConstant()) {
3801 __ movsxb(out, Address(obj,
3802 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3803 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003804 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003805 }
3806 break;
3807 }
3808
3809 case Primitive::kPrimShort: {
3810 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003812 if (index.IsConstant()) {
3813 __ movsxw(out, Address(obj,
3814 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3815 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003816 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003817 }
3818 break;
3819 }
3820
3821 case Primitive::kPrimChar: {
3822 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003823 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003824 if (index.IsConstant()) {
3825 __ movzxw(out, Address(obj,
3826 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3827 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003828 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003829 }
3830 break;
3831 }
3832
3833 case Primitive::kPrimInt:
3834 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003835 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3836 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003837 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003838 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003839 if (index.IsConstant()) {
3840 __ movl(out, Address(obj,
3841 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3842 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003843 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003844 }
3845 break;
3846 }
3847
3848 case Primitive::kPrimLong: {
3849 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003850 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003851 if (index.IsConstant()) {
3852 __ movq(out, Address(obj,
3853 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3854 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003855 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003856 }
3857 break;
3858 }
3859
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003860 case Primitive::kPrimFloat: {
3861 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003862 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003863 if (index.IsConstant()) {
3864 __ movss(out, Address(obj,
3865 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3866 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003867 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003868 }
3869 break;
3870 }
3871
3872 case Primitive::kPrimDouble: {
3873 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003874 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003875 if (index.IsConstant()) {
3876 __ movsd(out, Address(obj,
3877 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3878 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003879 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003880 }
3881 break;
3882 }
3883
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003884 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003885 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003886 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003887 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003888 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003889
3890 if (type == Primitive::kPrimNot) {
3891 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3892 __ MaybeUnpoisonHeapReference(out);
3893 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003894}
3895
3896void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003897 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003898
3899 bool needs_write_barrier =
3900 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3901 bool needs_runtime_call = instruction->NeedsTypeCheck();
3902
Nicolas Geoffray39468442014-09-02 15:17:15 +01003903 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003904 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3905 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003906 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003907 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3908 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3909 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003910 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003911 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003912 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003913 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3914 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003915 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003916 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003917 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3918 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003919 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003920 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003921 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003922
3923 if (needs_write_barrier) {
3924 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003925 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003926 locations->AddTemp(Location::RequiresRegister());
3927 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003928 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929}
3930
3931void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3932 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003933 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003934 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003935 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003936 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003937 bool needs_runtime_call = locations->WillCall();
3938 bool needs_write_barrier =
3939 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003940
3941 switch (value_type) {
3942 case Primitive::kPrimBoolean:
3943 case Primitive::kPrimByte: {
3944 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003945 if (index.IsConstant()) {
3946 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003947 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003948 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003949 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003950 __ movb(Address(obj, offset),
3951 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003952 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003953 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003954 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003955 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3956 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003957 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003958 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003959 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3960 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003961 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003962 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003963 break;
3964 }
3965
3966 case Primitive::kPrimShort:
3967 case Primitive::kPrimChar: {
3968 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003969 if (index.IsConstant()) {
3970 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003971 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003972 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003973 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003974 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00003975 __ movw(Address(obj, offset),
3976 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003977 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003978 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003979 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003980 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003981 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
3982 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003983 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003984 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003985 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003986 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3987 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003988 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003989 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003990 break;
3991 }
3992
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003993 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003994 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003995 if (!needs_runtime_call) {
3996 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3997 if (index.IsConstant()) {
3998 size_t offset =
3999 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4000 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004001 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4002 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4003 __ movl(temp, value.AsRegister<CpuRegister>());
4004 __ PoisonHeapReference(temp);
4005 __ movl(Address(obj, offset), temp);
4006 } else {
4007 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
4008 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004009 } else {
4010 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004011 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004012 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4013 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4014 // Note: if heap poisoning is enabled, no need to poison
4015 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04004016 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004017 }
4018 } else {
4019 DCHECK(index.IsRegister()) << index;
4020 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004021 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4022 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4023 __ movl(temp, value.AsRegister<CpuRegister>());
4024 __ PoisonHeapReference(temp);
4025 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
4026 } else {
4027 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4028 value.AsRegister<CpuRegister>());
4029 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004030 } else {
4031 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004032 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004033 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4034 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4035 // Note: if heap poisoning is enabled, no need to poison
4036 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004037 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04004038 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004039 }
4040 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004041 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004042 if (needs_write_barrier) {
4043 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004044 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4045 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004046 codegen_->MarkGCCard(
4047 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004048 }
4049 } else {
4050 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01004051 // Note: if heap poisoning is enabled, pAputObject takes cares
4052 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01004053 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
4054 instruction,
4055 instruction->GetDexPc(),
4056 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004057 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004058 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004059 break;
4060 }
4061
4062 case Primitive::kPrimLong: {
4063 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004064 if (index.IsConstant()) {
4065 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004066 if (value.IsRegister()) {
4067 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4068 } else {
4069 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4070 DCHECK(IsInt<32>(v));
4071 int32_t v_32 = v;
4072 __ movq(Address(obj, offset), Immediate(v_32));
4073 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004074 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004075 if (value.IsRegister()) {
4076 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4077 value.AsRegister<CpuRegister>());
4078 } else {
4079 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4080 DCHECK(IsInt<32>(v));
4081 int32_t v_32 = v;
4082 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4083 Immediate(v_32));
4084 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004085 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004086 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004087 break;
4088 }
4089
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004090 case Primitive::kPrimFloat: {
4091 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4092 if (index.IsConstant()) {
4093 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4094 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004096 } else {
4097 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004098 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4099 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004100 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004101 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004102 break;
4103 }
4104
4105 case Primitive::kPrimDouble: {
4106 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4107 if (index.IsConstant()) {
4108 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4109 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004110 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004111 } else {
4112 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004113 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4114 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004115 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004116 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004117 break;
4118 }
4119
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004120 case Primitive::kPrimVoid:
4121 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004122 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004123 }
4124}
4125
4126void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004127 LocationSummary* locations =
4128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004129 locations->SetInAt(0, Location::RequiresRegister());
4130 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004131}
4132
4133void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4134 LocationSummary* locations = instruction->GetLocations();
4135 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004136 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4137 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004138 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004139 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004140}
4141
4142void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004143 LocationSummary* locations =
4144 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004145 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004146 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004147 if (instruction->HasUses()) {
4148 locations->SetOut(Location::SameAsFirstInput());
4149 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004150}
4151
4152void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4153 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004154 Location index_loc = locations->InAt(0);
4155 Location length_loc = locations->InAt(1);
4156 SlowPathCodeX86_64* slow_path =
4157 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004158
Mark Mendell99dbd682015-04-22 16:18:52 -04004159 if (length_loc.IsConstant()) {
4160 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4161 if (index_loc.IsConstant()) {
4162 // BCE will remove the bounds check if we are guarenteed to pass.
4163 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4164 if (index < 0 || index >= length) {
4165 codegen_->AddSlowPath(slow_path);
4166 __ jmp(slow_path->GetEntryLabel());
4167 } else {
4168 // Some optimization after BCE may have generated this, and we should not
4169 // generate a bounds check if it is a valid range.
4170 }
4171 return;
4172 }
4173
4174 // We have to reverse the jump condition because the length is the constant.
4175 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4176 __ cmpl(index_reg, Immediate(length));
4177 codegen_->AddSlowPath(slow_path);
4178 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004179 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004180 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4181 if (index_loc.IsConstant()) {
4182 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4183 __ cmpl(length, Immediate(value));
4184 } else {
4185 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4186 }
4187 codegen_->AddSlowPath(slow_path);
4188 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004189 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004190}
4191
4192void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4193 CpuRegister card,
4194 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004195 CpuRegister value,
4196 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004197 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004198 if (value_can_be_null) {
4199 __ testl(value, value);
4200 __ j(kEqual, &is_null);
4201 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004202 __ gs()->movq(card, Address::Absolute(
4203 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4204 __ movq(temp, object);
4205 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004206 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004207 if (value_can_be_null) {
4208 __ Bind(&is_null);
4209 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004210}
4211
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004212void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4213 temp->SetLocations(nullptr);
4214}
4215
4216void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4217 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004218 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004219}
4220
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004221void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004222 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004223 LOG(FATAL) << "Unimplemented";
4224}
4225
4226void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004227 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4228}
4229
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004230void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4231 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4232}
4233
4234void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004235 HBasicBlock* block = instruction->GetBlock();
4236 if (block->GetLoopInformation() != nullptr) {
4237 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4238 // The back edge will generate the suspend check.
4239 return;
4240 }
4241 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4242 // The goto will generate the suspend check.
4243 return;
4244 }
4245 GenerateSuspendCheck(instruction, nullptr);
4246}
4247
4248void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4249 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004250 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004251 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4252 if (slow_path == nullptr) {
4253 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4254 instruction->SetSlowPath(slow_path);
4255 codegen_->AddSlowPath(slow_path);
4256 if (successor != nullptr) {
4257 DCHECK(successor->IsLoopHeader());
4258 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4259 }
4260 } else {
4261 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4262 }
4263
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004264 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004265 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004266 if (successor == nullptr) {
4267 __ j(kNotEqual, slow_path->GetEntryLabel());
4268 __ Bind(slow_path->GetReturnLabel());
4269 } else {
4270 __ j(kEqual, codegen_->GetLabelOf(successor));
4271 __ jmp(slow_path->GetEntryLabel());
4272 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004273}
4274
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004275X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4276 return codegen_->GetAssembler();
4277}
4278
4279void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4280 MoveOperands* move = moves_.Get(index);
4281 Location source = move->GetSource();
4282 Location destination = move->GetDestination();
4283
4284 if (source.IsRegister()) {
4285 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004286 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004287 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004288 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004289 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004290 } else {
4291 DCHECK(destination.IsDoubleStackSlot());
4292 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004293 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004294 }
4295 } else if (source.IsStackSlot()) {
4296 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004297 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004298 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004299 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004300 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004301 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004302 } else {
4303 DCHECK(destination.IsStackSlot());
4304 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4305 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4306 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004307 } else if (source.IsDoubleStackSlot()) {
4308 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004309 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004310 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004311 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004312 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4313 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004314 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004315 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004316 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4317 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4318 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004319 } else if (source.IsConstant()) {
4320 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004321 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4322 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004323 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004324 if (value == 0) {
4325 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4326 } else {
4327 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4328 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004329 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004330 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004331 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004332 }
4333 } else if (constant->IsLongConstant()) {
4334 int64_t value = constant->AsLongConstant()->GetValue();
4335 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004336 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004337 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004338 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004339 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004340 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4341 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004342 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004343 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004344 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004345 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004346 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4347 if (value == 0) {
4348 // easy FP 0.0.
4349 __ xorps(dest, dest);
4350 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004351 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004352 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004353 } else {
4354 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004355 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004356 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4357 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004358 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004359 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004360 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004361 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004362 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004363 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4364 if (value == 0) {
4365 __ xorpd(dest, dest);
4366 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004367 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004368 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004369 } else {
4370 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004371 codegen_->Load64BitValue(CpuRegister(TMP), value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004372 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4373 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004374 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004375 } else if (source.IsFpuRegister()) {
4376 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004377 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004378 } else if (destination.IsStackSlot()) {
4379 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004380 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004381 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004382 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004383 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004384 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004385 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004386 }
4387}
4388
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004389void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004390 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004391 __ movl(Address(CpuRegister(RSP), mem), reg);
4392 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004393}
4394
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004395void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004396 ScratchRegisterScope ensure_scratch(
4397 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4398
4399 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4400 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4401 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4402 Address(CpuRegister(RSP), mem2 + stack_offset));
4403 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4404 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4405 CpuRegister(ensure_scratch.GetRegister()));
4406}
4407
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004408void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4409 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4410 __ movq(Address(CpuRegister(RSP), mem), reg);
4411 __ movq(reg, CpuRegister(TMP));
4412}
4413
4414void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4415 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004416 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004417
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004418 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4419 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4420 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4421 Address(CpuRegister(RSP), mem2 + stack_offset));
4422 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4423 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4424 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004425}
4426
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004427void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4428 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4429 __ movss(Address(CpuRegister(RSP), mem), reg);
4430 __ movd(reg, CpuRegister(TMP));
4431}
4432
4433void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4434 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4435 __ movsd(Address(CpuRegister(RSP), mem), reg);
4436 __ movd(reg, CpuRegister(TMP));
4437}
4438
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004439void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4440 MoveOperands* move = moves_.Get(index);
4441 Location source = move->GetSource();
4442 Location destination = move->GetDestination();
4443
4444 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004445 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004446 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004447 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004448 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004449 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004450 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004451 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4452 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004453 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004454 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004455 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004456 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4457 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004458 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004459 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4460 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4461 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004462 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004463 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004464 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004465 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004466 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004467 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004468 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004469 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004470 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004471 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004472 }
4473}
4474
4475
4476void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4477 __ pushq(CpuRegister(reg));
4478}
4479
4480
4481void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4482 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004483}
4484
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004485void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4486 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4487 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4488 Immediate(mirror::Class::kStatusInitialized));
4489 __ j(kLess, slow_path->GetEntryLabel());
4490 __ Bind(slow_path->GetExitLabel());
4491 // No need for memory fence, thanks to the X86_64 memory model.
4492}
4493
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004494void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004495 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4496 ? LocationSummary::kCallOnSlowPath
4497 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004498 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004499 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004500 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004501 locations->SetOut(Location::RequiresRegister());
4502}
4503
4504void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004505 LocationSummary* locations = cls->GetLocations();
4506 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4507 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004508 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004509 DCHECK(!cls->CanCallRuntime());
4510 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004511 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004512 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004513 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004514 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004515 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004516 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004517 __ MaybeUnpoisonHeapReference(out);
4518
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004519 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4520 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4521 codegen_->AddSlowPath(slow_path);
4522 __ testl(out, out);
4523 __ j(kEqual, slow_path->GetEntryLabel());
4524 if (cls->MustGenerateClinitCheck()) {
4525 GenerateClassInitializationCheck(slow_path, out);
4526 } else {
4527 __ Bind(slow_path->GetExitLabel());
4528 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004529 }
4530}
4531
4532void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4533 LocationSummary* locations =
4534 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4535 locations->SetInAt(0, Location::RequiresRegister());
4536 if (check->HasUses()) {
4537 locations->SetOut(Location::SameAsFirstInput());
4538 }
4539}
4540
4541void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004542 // We assume the class to not be null.
4543 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4544 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004545 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004546 GenerateClassInitializationCheck(slow_path,
4547 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004548}
4549
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004550void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4551 LocationSummary* locations =
4552 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004553 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004554 locations->SetOut(Location::RequiresRegister());
4555}
4556
4557void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4558 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4559 codegen_->AddSlowPath(slow_path);
4560
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004561 LocationSummary* locations = load->GetLocations();
4562 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4563 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004564 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004565 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004566 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004567 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004568 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004569 __ testl(out, out);
4570 __ j(kEqual, slow_path->GetEntryLabel());
4571 __ Bind(slow_path->GetExitLabel());
4572}
4573
David Brazdilcb1c0552015-08-04 16:22:25 +01004574static Address GetExceptionTlsAddress() {
4575 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4576}
4577
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004578void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4579 LocationSummary* locations =
4580 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4581 locations->SetOut(Location::RequiresRegister());
4582}
4583
4584void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004585 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4586}
4587
4588void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4589 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4590}
4591
4592void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4593 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004594}
4595
4596void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4597 LocationSummary* locations =
4598 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4599 InvokeRuntimeCallingConvention calling_convention;
4600 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4601}
4602
4603void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004604 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4605 instruction,
4606 instruction->GetDexPc(),
4607 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004608}
4609
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004610void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004611 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4612 ? LocationSummary::kNoCall
4613 : LocationSummary::kCallOnSlowPath;
4614 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4615 locations->SetInAt(0, Location::RequiresRegister());
4616 locations->SetInAt(1, Location::Any());
4617 locations->SetOut(Location::RequiresRegister());
4618}
4619
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004620void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004621 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004622 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004623 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004624 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004625 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4626 Label done, zero;
4627 SlowPathCodeX86_64* slow_path = nullptr;
4628
4629 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004630 // Avoid null check if we know obj is not null.
4631 if (instruction->MustDoNullCheck()) {
4632 __ testl(obj, obj);
4633 __ j(kEqual, &zero);
4634 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004635 // Compare the class of `obj` with `cls`.
4636 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004637 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004638 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004639 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004640 } else {
4641 DCHECK(cls.IsStackSlot()) << cls;
4642 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4643 }
4644 if (instruction->IsClassFinal()) {
4645 // Classes must be equal for the instanceof to succeed.
4646 __ j(kNotEqual, &zero);
4647 __ movl(out, Immediate(1));
4648 __ jmp(&done);
4649 } else {
4650 // If the classes are not equal, we go into a slow path.
4651 DCHECK(locations->OnlyCallsOnSlowPath());
4652 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004653 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004654 codegen_->AddSlowPath(slow_path);
4655 __ j(kNotEqual, slow_path->GetEntryLabel());
4656 __ movl(out, Immediate(1));
4657 __ jmp(&done);
4658 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004659
4660 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4661 __ Bind(&zero);
4662 __ movl(out, Immediate(0));
4663 }
4664
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004665 if (slow_path != nullptr) {
4666 __ Bind(slow_path->GetExitLabel());
4667 }
4668 __ Bind(&done);
4669}
4670
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004671void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4672 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4673 instruction, LocationSummary::kCallOnSlowPath);
4674 locations->SetInAt(0, Location::RequiresRegister());
4675 locations->SetInAt(1, Location::Any());
4676 locations->AddTemp(Location::RequiresRegister());
4677}
4678
4679void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4680 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004681 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004682 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004683 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004684 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4685 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4686 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4687 codegen_->AddSlowPath(slow_path);
4688
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004689 // Avoid null check if we know obj is not null.
4690 if (instruction->MustDoNullCheck()) {
4691 __ testl(obj, obj);
4692 __ j(kEqual, slow_path->GetExitLabel());
4693 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004694 // Compare the class of `obj` with `cls`.
4695 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004696 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004697 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004698 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004699 } else {
4700 DCHECK(cls.IsStackSlot()) << cls;
4701 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4702 }
Roland Levillain4d027112015-07-01 15:41:14 +01004703 // The checkcast succeeds if the classes are equal (fast path).
4704 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004705 __ j(kNotEqual, slow_path->GetEntryLabel());
4706 __ Bind(slow_path->GetExitLabel());
4707}
4708
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004709void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4710 LocationSummary* locations =
4711 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4712 InvokeRuntimeCallingConvention calling_convention;
4713 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4714}
4715
4716void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004717 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
4718 : QUICK_ENTRY_POINT(pUnlockObject),
4719 instruction,
4720 instruction->GetDexPc(),
4721 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004722}
4723
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004724void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4725void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4726void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4727
4728void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4729 LocationSummary* locations =
4730 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4731 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4732 || instruction->GetResultType() == Primitive::kPrimLong);
4733 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004734 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004735 locations->SetOut(Location::SameAsFirstInput());
4736}
4737
4738void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4739 HandleBitwiseOperation(instruction);
4740}
4741
4742void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4743 HandleBitwiseOperation(instruction);
4744}
4745
4746void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4747 HandleBitwiseOperation(instruction);
4748}
4749
4750void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4751 LocationSummary* locations = instruction->GetLocations();
4752 Location first = locations->InAt(0);
4753 Location second = locations->InAt(1);
4754 DCHECK(first.Equals(locations->Out()));
4755
4756 if (instruction->GetResultType() == Primitive::kPrimInt) {
4757 if (second.IsRegister()) {
4758 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004759 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004760 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004761 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004762 } else {
4763 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004764 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004765 }
4766 } else if (second.IsConstant()) {
4767 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4768 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004769 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004770 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004771 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004772 } else {
4773 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004774 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004775 }
4776 } else {
4777 Address address(CpuRegister(RSP), second.GetStackIndex());
4778 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004779 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004780 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004781 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004782 } else {
4783 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004784 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004785 }
4786 }
4787 } else {
4788 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004789 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4790 bool second_is_constant = false;
4791 int64_t value = 0;
4792 if (second.IsConstant()) {
4793 second_is_constant = true;
4794 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004795 }
Mark Mendell40741f32015-04-20 22:10:34 -04004796 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004797
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004798 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004799 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004800 if (is_int32_value) {
4801 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4802 } else {
4803 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4804 }
4805 } else if (second.IsDoubleStackSlot()) {
4806 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004807 } else {
4808 __ andq(first_reg, second.AsRegister<CpuRegister>());
4809 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004810 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004811 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004812 if (is_int32_value) {
4813 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4814 } else {
4815 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4816 }
4817 } else if (second.IsDoubleStackSlot()) {
4818 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004819 } else {
4820 __ orq(first_reg, second.AsRegister<CpuRegister>());
4821 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004822 } else {
4823 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004824 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004825 if (is_int32_value) {
4826 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4827 } else {
4828 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4829 }
4830 } else if (second.IsDoubleStackSlot()) {
4831 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004832 } else {
4833 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4834 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004835 }
4836 }
4837}
4838
Calin Juravleb1498f62015-02-16 13:13:29 +00004839void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4840 // Nothing to do, this should be removed during prepare for register allocator.
4841 UNUSED(instruction);
4842 LOG(FATAL) << "Unreachable";
4843}
4844
4845void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4846 // Nothing to do, this should be removed during prepare for register allocator.
4847 UNUSED(instruction);
4848 LOG(FATAL) << "Unreachable";
4849}
4850
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004851void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
4852 DCHECK(codegen_->IsBaseline());
4853 LocationSummary* locations =
4854 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4855 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4856}
4857
4858void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4859 DCHECK(codegen_->IsBaseline());
4860 // Will be generated at use site.
4861}
4862
Mark Mendell92e83bf2015-05-07 11:25:03 -04004863void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4864 if (value == 0) {
4865 __ xorl(dest, dest);
4866 } else if (value > 0 && IsInt<32>(value)) {
4867 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4868 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4869 } else {
4870 __ movq(dest, Immediate(value));
4871 }
4872}
4873
Mark Mendellf55c3e02015-03-26 21:07:46 -04004874void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4875 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004876 X86_64Assembler* assembler = GetAssembler();
4877 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004878 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4879 // byte values. If used for vectors at a later time, this will need to be
4880 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004881 assembler->Align(4, 0);
4882 constant_area_start_ = assembler->CodeSize();
4883 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004884 }
4885
4886 // And finish up.
4887 CodeGenerator::Finalize(allocator);
4888}
4889
4890/**
4891 * Class to handle late fixup of offsets into constant area.
4892 */
4893class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4894 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004895 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004896 : codegen_(codegen), offset_into_constant_area_(offset) {}
4897
4898 private:
4899 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4900 // Patch the correct offset for the instruction. We use the address of the
4901 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4902 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4903 int relative_position = constant_offset - pos;
4904
4905 // Patch in the right value.
4906 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4907 }
4908
Mark Mendell39dcf552015-04-09 20:42:42 -04004909 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004910
4911 // Location in constant area that the fixup refers to.
4912 int offset_into_constant_area_;
4913};
4914
4915Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4916 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4917 return Address::RIP(fixup);
4918}
4919
4920Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4921 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4922 return Address::RIP(fixup);
4923}
4924
4925Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4926 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4927 return Address::RIP(fixup);
4928}
4929
4930Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4931 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4932 return Address::RIP(fixup);
4933}
4934
Roland Levillain4d027112015-07-01 15:41:14 +01004935#undef __
4936
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004937} // namespace x86_64
4938} // namespace art