blob: 29bad125f9197b5aa8bbdd9ceb1421d0a604dbd6 [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"
Vladimir Marko58155012015-08-19 12:49:41 +000021#include "compiled_method.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010022#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010023#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080024#include "intrinsics.h"
25#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070026#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070027#include "mirror/class-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "mirror/object_reference.h"
29#include "thread.h"
30#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010031#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010032#include "utils/x86_64/assembler_x86_64.h"
33#include "utils/x86_64/managed_register_x86_64.h"
34
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010035namespace art {
36
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010037namespace x86_64 {
38
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010039// Some x86_64 instructions require a register to be available as temp.
40static constexpr Register TMP = R11;
41
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010042static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010043static constexpr Register kMethodRegisterArgument = RDI;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010044
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000045static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000046static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010047
Mark Mendell24f2dfa2015-01-14 19:51:45 -050048static constexpr int kC2ConditionMask = 0x400;
49
Roland Levillain62a46b22015-06-01 18:24:13 +010050#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
Alexandre Rames8158f282015-08-07 10:26:17 +010051#define QUICK_ENTRY_POINT(x) Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x), true)
Nicolas Geoffraye5038322014-07-04 09:41:32 +010052
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010053class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010054 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010055 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056
Alexandre Rames2ed20af2015-03-06 13:55:35 +000057 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010058 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059 __ Bind(GetEntryLabel());
Alexandre Rames8158f282015-08-07 10:26:17 +010060 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
61 instruction_,
62 instruction_->GetDexPc(),
63 this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064 }
65
Alexandre Rames8158f282015-08-07 10:26:17 +010066 bool IsFatal() const OVERRIDE { return true; }
67
Alexandre Rames9931f312015-06-19 14:47:01 +010068 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
69
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
73};
74
Calin Juravled0d48522014-11-04 16:40:20 +000075class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
76 public:
77 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
78
Alexandre Rames2ed20af2015-03-06 13:55:35 +000079 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010080 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000081 __ Bind(GetEntryLabel());
Alexandre Rames8158f282015-08-07 10:26:17 +010082 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
83 instruction_,
84 instruction_->GetDexPc(),
85 this);
Calin Juravled0d48522014-11-04 16:40:20 +000086 }
87
Alexandre Rames8158f282015-08-07 10:26:17 +010088 bool IsFatal() const OVERRIDE { return true; }
89
Alexandre Rames9931f312015-06-19 14:47:01 +010090 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
91
Calin Juravled0d48522014-11-04 16:40:20 +000092 private:
93 HDivZeroCheck* const instruction_;
94 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
95};
96
Calin Juravlebacfec32014-11-14 15:54:36 +000097class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
Calin Juravled0d48522014-11-04 16:40:20 +000098 public:
Roland Levillain3887c462015-08-12 18:15:42 +010099 DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
Calin Juravlebacfec32014-11-14 15:54:36 +0000100 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000101
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000102 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000103 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000104 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000105 if (is_div_) {
106 __ negl(cpu_reg_);
107 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400108 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000109 }
110
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000111 } else {
112 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000113 if (is_div_) {
114 __ negq(cpu_reg_);
115 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400116 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000117 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000118 }
Calin Juravled0d48522014-11-04 16:40:20 +0000119 __ jmp(GetExitLabel());
120 }
121
Alexandre Rames9931f312015-06-19 14:47:01 +0100122 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
123
Calin Juravled0d48522014-11-04 16:40:20 +0000124 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000127 const bool is_div_;
128 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000129};
130
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100131class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100133 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000136 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100137 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000139 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100140 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
141 instruction_,
142 instruction_->GetDexPc(),
143 this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000144 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 if (successor_ == nullptr) {
146 __ jmp(GetReturnLabel());
147 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100148 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100149 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000150 }
151
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100152 Label* GetReturnLabel() {
153 DCHECK(successor_ == nullptr);
154 return &return_label_;
155 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100157 HBasicBlock* GetSuccessor() const {
158 return successor_;
159 }
160
Alexandre Rames9931f312015-06-19 14:47:01 +0100161 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
162
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000163 private:
164 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100165 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000166 Label return_label_;
167
168 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
169};
170
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100171class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100172 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100173 BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
174 Location index_location,
175 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100176 : instruction_(instruction),
177 index_location_(index_location),
178 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100179
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000180 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100181 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100182 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000183 // We're moving two locations to locations that could overlap, so we need a parallel
184 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000186 codegen->EmitParallelMoves(
187 index_location_,
188 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100189 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000190 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100191 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
192 Primitive::kPrimInt);
Alexandre Rames8158f282015-08-07 10:26:17 +0100193 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
194 instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100195 }
196
Alexandre Rames8158f282015-08-07 10:26:17 +0100197 bool IsFatal() const OVERRIDE { return true; }
198
Alexandre Rames9931f312015-06-19 14:47:01 +0100199 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
200
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100201 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100202 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100203 const Location index_location_;
204 const Location length_location_;
205
206 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
207};
208
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100210 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211 LoadClassSlowPathX86_64(HLoadClass* cls,
212 HInstruction* at,
213 uint32_t dex_pc,
214 bool do_clinit)
215 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
216 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
217 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100218
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000219 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000220 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100221 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
222 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100223
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000224 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100226 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000227 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100228 x64_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
229 : QUICK_ENTRY_POINT(pInitializeType),
230 at_, dex_pc_, this);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100231
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000232 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000233 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000234 if (out.IsValid()) {
235 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
236 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 }
238
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000239 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100240 __ jmp(GetExitLabel());
241 }
242
Alexandre Rames9931f312015-06-19 14:47:01 +0100243 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
244
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100245 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000246 // The class this slow path will load.
247 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100248
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000249 // The instruction where this slow path is happening.
250 // (Might be the load class or an initialization check).
251 HInstruction* const at_;
252
253 // The dex PC of `at_`.
254 const uint32_t dex_pc_;
255
256 // Whether to initialize the class.
257 const bool do_clinit_;
258
259 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100260};
261
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000262class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
263 public:
264 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
265
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000266 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267 LocationSummary* locations = instruction_->GetLocations();
268 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
269
270 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
271 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000272 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000273
274 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800275 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000276 Immediate(instruction_->GetStringIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100277 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
278 instruction_,
279 instruction_->GetDexPc(),
280 this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000281 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000282 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000283 __ jmp(GetExitLabel());
284 }
285
Alexandre Rames9931f312015-06-19 14:47:01 +0100286 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
287
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000288 private:
289 HLoadString* const instruction_;
290
291 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
292};
293
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
295 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000296 TypeCheckSlowPathX86_64(HInstruction* instruction,
297 Location class_to_check,
298 Location object_class,
299 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000300 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000301 class_to_check_(class_to_check),
302 object_class_(object_class),
303 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000304
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000305 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000306 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000307 DCHECK(instruction_->IsCheckCast()
308 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000309
310 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
311 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000312 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313
314 // We're moving two locations to locations that could overlap, so we need a parallel
315 // move resolver.
316 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000317 codegen->EmitParallelMoves(
318 class_to_check_,
319 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100320 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000321 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100322 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
323 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000324
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000325 if (instruction_->IsInstanceOf()) {
Alexandre Rames8158f282015-08-07 10:26:17 +0100326 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
327 instruction_,
328 dex_pc_,
329 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000330 } else {
331 DCHECK(instruction_->IsCheckCast());
Alexandre Rames8158f282015-08-07 10:26:17 +0100332 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
333 instruction_,
334 dex_pc_,
335 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000336 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000337
338 if (instruction_->IsInstanceOf()) {
339 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
340 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000341
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000342 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000343 __ jmp(GetExitLabel());
344 }
345
Alexandre Rames9931f312015-06-19 14:47:01 +0100346 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
347
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000348 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000349 HInstruction* const instruction_;
350 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000351 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000352 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000353
354 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
355};
356
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700357class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 {
358 public:
359 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
360 : instruction_(instruction) {}
361
362 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100363 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700364 __ Bind(GetEntryLabel());
365 SaveLiveRegisters(codegen, instruction_->GetLocations());
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700366 DCHECK(instruction_->IsDeoptimize());
367 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
Alexandre Rames8158f282015-08-07 10:26:17 +0100368 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
369 deoptimize,
370 deoptimize->GetDexPc(),
371 this);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700372 }
373
Alexandre Rames9931f312015-06-19 14:47:01 +0100374 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
375
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700376 private:
377 HInstruction* const instruction_;
378 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
379};
380
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100381#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100382#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100383
Roland Levillain4fa13f62015-07-06 18:11:54 +0100384inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700385 switch (cond) {
386 case kCondEQ: return kEqual;
387 case kCondNE: return kNotEqual;
388 case kCondLT: return kLess;
389 case kCondLE: return kLessEqual;
390 case kCondGT: return kGreater;
391 case kCondGE: return kGreaterEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700392 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100393 LOG(FATAL) << "Unreachable";
394 UNREACHABLE();
395}
396
397inline Condition X86_64FPCondition(IfCondition cond) {
398 switch (cond) {
399 case kCondEQ: return kEqual;
400 case kCondNE: return kNotEqual;
401 case kCondLT: return kBelow;
402 case kCondLE: return kBelowEqual;
403 case kCondGT: return kAbove;
404 case kCondGE: return kAboveEqual;
405 };
406 LOG(FATAL) << "Unreachable";
407 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700408}
409
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800410void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100411 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800412 // All registers are assumed to be correctly set up.
413
Vladimir Marko58155012015-08-19 12:49:41 +0000414 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
415 switch (invoke->GetMethodLoadKind()) {
416 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
417 // temp = thread->string_init_entrypoint
418 __ gs()->movl(temp.AsRegister<CpuRegister>(),
419 Address::Absolute(invoke->GetStringInitOffset(), true));
420 break;
421 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
422 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
423 break;
424 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
425 __ movq(temp.AsRegister<CpuRegister>(), Immediate(invoke->GetMethodAddress()));
426 break;
427 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
428 __ movl(temp.AsRegister<CpuRegister>(), Immediate(0)); // Placeholder.
429 method_patches_.emplace_back(invoke->GetTargetMethod());
430 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
431 break;
432 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
433 pc_rel_dex_cache_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
434 invoke->GetDexCacheArrayOffset());
435 __ movq(temp.AsRegister<CpuRegister>(),
436 Address::Absolute(kDummy32BitOffset, false /* no_rip */));
437 // Bind the label at the end of the "movl" insn.
438 __ Bind(&pc_rel_dex_cache_patches_.back().label);
439 break;
440 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
441 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
442 Register method_reg;
443 CpuRegister reg = temp.AsRegister<CpuRegister>();
444 if (current_method.IsRegister()) {
445 method_reg = current_method.AsRegister<Register>();
446 } else {
447 DCHECK(invoke->GetLocations()->Intrinsified());
448 DCHECK(!current_method.IsValid());
449 method_reg = reg.AsRegister();
450 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
451 }
452 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +0100453 __ movq(reg,
454 Address(CpuRegister(method_reg),
455 ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +0000456 // temp = temp[index_in_cache]
457 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
458 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
459 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +0100460 }
Vladimir Marko58155012015-08-19 12:49:41 +0000461 }
462
463 switch (invoke->GetCodePtrLocation()) {
464 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
465 __ call(&frame_entry_label_);
466 break;
467 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
468 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
469 Label* label = &relative_call_patches_.back().label;
470 __ call(label); // Bind to the patch label, override at link time.
471 __ Bind(label); // Bind the label at the end of the "call" insn.
472 break;
473 }
474 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
475 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
476 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
477 FALLTHROUGH_INTENDED;
478 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
479 // (callee_method + offset_of_quick_compiled_code)()
480 __ call(Address(callee_method.AsRegister<CpuRegister>(),
481 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
482 kX86_64WordSize).SizeValue()));
483 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000484 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800485
486 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800487}
488
Vladimir Marko58155012015-08-19 12:49:41 +0000489void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
490 DCHECK(linker_patches->empty());
491 size_t size =
492 method_patches_.size() + relative_call_patches_.size() + pc_rel_dex_cache_patches_.size();
493 linker_patches->reserve(size);
494 for (const MethodPatchInfo<Label>& info : method_patches_) {
495 // The label points to the end of the "movl" instruction but the literal offset for method
496 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
497 uint32_t literal_offset = info.label.Position() - 4;
498 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
499 info.target_method.dex_file,
500 info.target_method.dex_method_index));
501 }
502 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
503 // The label points to the end of the "call" instruction but the literal offset for method
504 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
505 uint32_t literal_offset = info.label.Position() - 4;
506 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
507 info.target_method.dex_file,
508 info.target_method.dex_method_index));
509 }
510 for (const PcRelativeDexCacheAccessInfo& info : pc_rel_dex_cache_patches_) {
511 // The label points to the end of the "mov" instruction but the literal offset for method
512 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
513 uint32_t literal_offset = info.label.Position() - 4;
514 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
515 &info.target_dex_file,
516 info.label.Position(),
517 info.element_offset));
518 }
519}
520
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100521void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100522 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100523}
524
525void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100526 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100527}
528
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100529size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
530 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
531 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100532}
533
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100534size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
535 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
536 return kX86_64WordSize;
537}
538
539size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
540 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
541 return kX86_64WordSize;
542}
543
544size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
545 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
546 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100547}
548
Alexandre Rames8158f282015-08-07 10:26:17 +0100549void CodeGeneratorX86_64::InvokeRuntime(Address entry_point,
550 HInstruction* instruction,
551 uint32_t dex_pc,
552 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100553 ValidateInvokeRuntime(instruction, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100554 __ gs()->call(entry_point);
555 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100556}
557
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000558static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000559// Use a fake return address register to mimic Quick.
560static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400561CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
562 const X86_64InstructionSetFeatures& isa_features,
563 const CompilerOptions& compiler_options)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000564 : CodeGenerator(graph,
565 kNumberOfCpuRegisters,
566 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000567 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000568 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
569 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000570 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000571 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
572 arraysize(kFpuCalleeSaves)),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000573 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100574 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100575 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000576 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400577 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400578 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000579 constant_area_start_(0),
580 method_patches_(graph->GetArena()->Adapter()),
581 relative_call_patches_(graph->GetArena()->Adapter()),
582 pc_rel_dex_cache_patches_(graph->GetArena()->Adapter()) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000583 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
584}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100585
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100586InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
587 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100588 : HGraphVisitor(graph),
589 assembler_(codegen->GetAssembler()),
590 codegen_(codegen) {}
591
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100592Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100593 switch (type) {
594 case Primitive::kPrimLong:
595 case Primitive::kPrimByte:
596 case Primitive::kPrimBoolean:
597 case Primitive::kPrimChar:
598 case Primitive::kPrimShort:
599 case Primitive::kPrimInt:
600 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100601 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100602 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100603 }
604
605 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100606 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100607 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100608 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100609 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100610
611 case Primitive::kPrimVoid:
612 LOG(FATAL) << "Unreachable type " << type;
613 }
614
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100615 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100616}
617
Nicolas Geoffray98893962015-01-21 12:32:32 +0000618void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100619 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100620 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100621
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000622 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100623 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000624
Nicolas Geoffray98893962015-01-21 12:32:32 +0000625 if (is_baseline) {
626 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
627 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
628 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000629 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
630 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
631 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000632 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100633}
634
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100635static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100636 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100637}
David Srbecky9d8606d2015-04-12 09:35:32 +0100638
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100639static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100640 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100641}
642
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100643void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100644 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000645 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100646 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700647 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000648 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100649
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000650 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100651 __ testq(CpuRegister(RAX), Address(
652 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100653 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100654 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000655
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000656 if (HasEmptyFrame()) {
657 return;
658 }
659
Nicolas Geoffray98893962015-01-21 12:32:32 +0000660 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000661 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000662 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000663 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100664 __ cfi().AdjustCFAOffset(kX86_64WordSize);
665 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000666 }
667 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100668
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100669 int adjust = GetFrameSize() - GetCoreSpillSize();
670 __ subq(CpuRegister(RSP), Immediate(adjust));
671 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000672 uint32_t xmm_spill_location = GetFpuSpillStart();
673 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100674
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000675 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
676 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100677 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
678 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
679 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000680 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100681 }
682
Mathieu Chartiere401d142015-04-22 13:56:20 -0700683 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100684 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100685}
686
687void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100688 __ cfi().RememberState();
689 if (!HasEmptyFrame()) {
690 uint32_t xmm_spill_location = GetFpuSpillStart();
691 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
692 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
693 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
694 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
695 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
696 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
697 }
698 }
699
700 int adjust = GetFrameSize() - GetCoreSpillSize();
701 __ addq(CpuRegister(RSP), Immediate(adjust));
702 __ cfi().AdjustCFAOffset(-adjust);
703
704 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
705 Register reg = kCoreCalleeSaves[i];
706 if (allocated_registers_.ContainsCoreRegister(reg)) {
707 __ popq(CpuRegister(reg));
708 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
709 __ cfi().Restore(DWARFReg(reg));
710 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000711 }
712 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100713 __ ret();
714 __ cfi().RestoreState();
715 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100716}
717
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100718void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
719 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100720}
721
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100722Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
723 switch (load->GetType()) {
724 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100725 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100726 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100727
728 case Primitive::kPrimInt:
729 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100730 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100731 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100732
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimChar:
736 case Primitive::kPrimShort:
737 case Primitive::kPrimVoid:
738 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700739 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100740 }
741
742 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700743 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100744}
745
746void CodeGeneratorX86_64::Move(Location destination, Location source) {
747 if (source.Equals(destination)) {
748 return;
749 }
750 if (destination.IsRegister()) {
751 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000752 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100753 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000754 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100755 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000756 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100757 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100758 } else {
759 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000760 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100761 Address(CpuRegister(RSP), source.GetStackIndex()));
762 }
763 } else if (destination.IsFpuRegister()) {
764 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000765 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100766 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000767 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100768 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000769 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100770 Address(CpuRegister(RSP), source.GetStackIndex()));
771 } else {
772 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000773 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100774 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100775 }
776 } else if (destination.IsStackSlot()) {
777 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100778 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000779 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100780 } else if (source.IsFpuRegister()) {
781 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000782 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500783 } else if (source.IsConstant()) {
784 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000785 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500786 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100787 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500788 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000789 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
790 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100791 }
792 } else {
793 DCHECK(destination.IsDoubleStackSlot());
794 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100795 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000796 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100797 } else if (source.IsFpuRegister()) {
798 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000799 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500800 } else if (source.IsConstant()) {
801 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800802 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500803 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000804 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500805 } else {
806 DCHECK(constant->IsLongConstant());
807 value = constant->AsLongConstant()->GetValue();
808 }
Mark Mendellcfa410b2015-05-25 16:02:44 -0400809 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100810 } else {
811 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000812 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
813 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100814 }
815 }
816}
817
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100818void CodeGeneratorX86_64::Move(HInstruction* instruction,
819 Location location,
820 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000821 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100822 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700823 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100824 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000825 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100826 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000827 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000828 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
829 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000830 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000831 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000832 } else if (location.IsStackSlot()) {
833 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
834 } else {
835 DCHECK(location.IsConstant());
836 DCHECK_EQ(location.GetConstant(), const_to_move);
837 }
838 } else if (const_to_move->IsLongConstant()) {
839 int64_t value = const_to_move->AsLongConstant()->GetValue();
840 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400841 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000842 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400843 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000844 } else {
845 DCHECK(location.IsConstant());
846 DCHECK_EQ(location.GetConstant(), const_to_move);
847 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100848 }
Roland Levillain476df552014-10-09 17:51:36 +0100849 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100850 switch (instruction->GetType()) {
851 case Primitive::kPrimBoolean:
852 case Primitive::kPrimByte:
853 case Primitive::kPrimChar:
854 case Primitive::kPrimShort:
855 case Primitive::kPrimInt:
856 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100857 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100858 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
859 break;
860
861 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100862 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000863 Move(location,
864 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865 break;
866
867 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100868 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100869 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000870 } else if (instruction->IsTemporary()) {
871 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
872 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100873 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100874 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100875 switch (instruction->GetType()) {
876 case Primitive::kPrimBoolean:
877 case Primitive::kPrimByte:
878 case Primitive::kPrimChar:
879 case Primitive::kPrimShort:
880 case Primitive::kPrimInt:
881 case Primitive::kPrimNot:
882 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100883 case Primitive::kPrimFloat:
884 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000885 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100886 break;
887
888 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100889 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100890 }
891 }
892}
893
David Brazdilfc6a86a2015-06-26 10:33:45 +0000894void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100895 DCHECK(!successor->IsExitBlock());
896
897 HBasicBlock* block = got->GetBlock();
898 HInstruction* previous = got->GetPrevious();
899
900 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000901 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100902 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
903 return;
904 }
905
906 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
907 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
908 }
909 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100910 __ jmp(codegen_->GetLabelOf(successor));
911 }
912}
913
David Brazdilfc6a86a2015-06-26 10:33:45 +0000914void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
915 got->SetLocations(nullptr);
916}
917
918void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
919 HandleGoto(got, got->GetSuccessor());
920}
921
922void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
923 try_boundary->SetLocations(nullptr);
924}
925
926void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
927 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
928 if (!successor->IsExitBlock()) {
929 HandleGoto(try_boundary, successor);
930 }
931}
932
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100933void LocationsBuilderX86_64::VisitExit(HExit* exit) {
934 exit->SetLocations(nullptr);
935}
936
937void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700938 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100939}
940
Mark Mendellc4701932015-04-10 13:18:51 -0400941void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
942 Label* true_label,
943 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100944 if (cond->IsFPConditionTrueIfNaN()) {
945 __ j(kUnordered, true_label);
946 } else if (cond->IsFPConditionFalseIfNaN()) {
947 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400948 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100949 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400950}
951
952void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
953 HCondition* condition,
954 Label* true_target,
955 Label* false_target,
956 Label* always_true_target) {
957 LocationSummary* locations = condition->GetLocations();
958 Location left = locations->InAt(0);
959 Location right = locations->InAt(1);
960
961 // We don't want true_target as a nullptr.
962 if (true_target == nullptr) {
963 true_target = always_true_target;
964 }
965 bool falls_through = (false_target == nullptr);
966
967 // FP compares don't like null false_targets.
968 if (false_target == nullptr) {
969 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
970 }
971
972 Primitive::Type type = condition->InputAt(0)->GetType();
973 switch (type) {
974 case Primitive::kPrimLong: {
975 CpuRegister left_reg = left.AsRegister<CpuRegister>();
976 if (right.IsConstant()) {
977 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
978 if (IsInt<32>(value)) {
979 if (value == 0) {
980 __ testq(left_reg, left_reg);
981 } else {
982 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
983 }
984 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100985 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -0400986 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
987 }
988 } else if (right.IsDoubleStackSlot()) {
989 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
990 } else {
991 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
992 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100993 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -0400994 break;
995 }
996 case Primitive::kPrimFloat: {
997 if (right.IsFpuRegister()) {
998 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
999 } else if (right.IsConstant()) {
1000 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1001 codegen_->LiteralFloatAddress(
1002 right.GetConstant()->AsFloatConstant()->GetValue()));
1003 } else {
1004 DCHECK(right.IsStackSlot());
1005 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1006 Address(CpuRegister(RSP), right.GetStackIndex()));
1007 }
1008 GenerateFPJumps(condition, true_target, false_target);
1009 break;
1010 }
1011 case Primitive::kPrimDouble: {
1012 if (right.IsFpuRegister()) {
1013 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1014 } else if (right.IsConstant()) {
1015 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1016 codegen_->LiteralDoubleAddress(
1017 right.GetConstant()->AsDoubleConstant()->GetValue()));
1018 } else {
1019 DCHECK(right.IsDoubleStackSlot());
1020 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1021 Address(CpuRegister(RSP), right.GetStackIndex()));
1022 }
1023 GenerateFPJumps(condition, true_target, false_target);
1024 break;
1025 }
1026 default:
1027 LOG(FATAL) << "Unexpected condition type " << type;
1028 }
1029
1030 if (!falls_through) {
1031 __ jmp(false_target);
1032 }
1033}
1034
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001035void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
1036 Label* true_target,
1037 Label* false_target,
1038 Label* always_true_target) {
1039 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001040 if (cond->IsIntConstant()) {
1041 // Constant condition, statically compared against 1.
1042 int32_t cond_value = cond->AsIntConstant()->GetValue();
1043 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001044 if (always_true_target != nullptr) {
1045 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001046 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001047 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001048 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001049 DCHECK_EQ(cond_value, 0);
1050 }
1051 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001052 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001053 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1054 // Moves do not affect the eflags register, so if the condition is
1055 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001056 // again. We can't use the eflags on FP conditions if they are
1057 // materialized due to the complex branching.
1058 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001059 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001060 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
1061 && !Primitive::IsFloatingPointType(type);
1062
Roland Levillain4fa13f62015-07-06 18:11:54 +01001063 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001064 if (!eflags_set) {
1065 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001066 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001067 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001068 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001069 } else {
1070 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
1071 Immediate(0));
1072 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001073 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001074 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001075 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001076 }
1077 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001078 // Condition has not been materialized, use its inputs as the
1079 // comparison and its condition as the branch condition.
1080
Mark Mendellc4701932015-04-10 13:18:51 -04001081 // Is this a long or FP comparison that has been folded into the HCondition?
1082 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001083 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -04001084 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1085 true_target, false_target, always_true_target);
1086 return;
1087 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001088
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001089 Location lhs = cond->GetLocations()->InAt(0);
1090 Location rhs = cond->GetLocations()->InAt(1);
1091 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001092 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001093 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001094 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001095 if (constant == 0) {
1096 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1097 } else {
1098 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1099 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001100 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001101 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001102 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1103 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001104 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001105 }
Dave Allison20dfc792014-06-16 20:44:29 -07001106 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001107 if (false_target != nullptr) {
1108 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001109 }
1110}
1111
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001112void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1113 LocationSummary* locations =
1114 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1115 HInstruction* cond = if_instr->InputAt(0);
1116 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1117 locations->SetInAt(0, Location::Any());
1118 }
1119}
1120
1121void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1122 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1123 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1124 Label* always_true_target = true_target;
1125 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1126 if_instr->IfTrueSuccessor())) {
1127 always_true_target = nullptr;
1128 }
1129 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1130 if_instr->IfFalseSuccessor())) {
1131 false_target = nullptr;
1132 }
1133 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1134}
1135
1136void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1137 LocationSummary* locations = new (GetGraph()->GetArena())
1138 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1139 HInstruction* cond = deoptimize->InputAt(0);
1140 DCHECK(cond->IsCondition());
1141 if (cond->AsCondition()->NeedsMaterialization()) {
1142 locations->SetInAt(0, Location::Any());
1143 }
1144}
1145
1146void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1147 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
1148 DeoptimizationSlowPathX86_64(deoptimize);
1149 codegen_->AddSlowPath(slow_path);
1150 Label* slow_path_entry = slow_path->GetEntryLabel();
1151 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1152}
1153
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001154void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1155 local->SetLocations(nullptr);
1156}
1157
1158void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1159 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1160}
1161
1162void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1163 local->SetLocations(nullptr);
1164}
1165
1166void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
1167 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001168 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001169}
1170
1171void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001172 LocationSummary* locations =
1173 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001174 switch (store->InputAt(1)->GetType()) {
1175 case Primitive::kPrimBoolean:
1176 case Primitive::kPrimByte:
1177 case Primitive::kPrimChar:
1178 case Primitive::kPrimShort:
1179 case Primitive::kPrimInt:
1180 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001181 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001182 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1183 break;
1184
1185 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001186 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001187 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1188 break;
1189
1190 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001191 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001192 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001193}
1194
1195void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001196 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001197}
1198
Roland Levillain0d37cd02015-05-27 16:39:19 +01001199void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001200 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001201 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001202 // Handle the long/FP comparisons made in instruction simplification.
1203 switch (cond->InputAt(0)->GetType()) {
1204 case Primitive::kPrimLong:
1205 locations->SetInAt(0, Location::RequiresRegister());
1206 locations->SetInAt(1, Location::Any());
1207 break;
1208 case Primitive::kPrimFloat:
1209 case Primitive::kPrimDouble:
1210 locations->SetInAt(0, Location::RequiresFpuRegister());
1211 locations->SetInAt(1, Location::Any());
1212 break;
1213 default:
1214 locations->SetInAt(0, Location::RequiresRegister());
1215 locations->SetInAt(1, Location::Any());
1216 break;
1217 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001218 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001219 locations->SetOut(Location::RequiresRegister());
1220 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001221}
1222
Roland Levillain0d37cd02015-05-27 16:39:19 +01001223void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001224 if (!cond->NeedsMaterialization()) {
1225 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001226 }
Mark Mendellc4701932015-04-10 13:18:51 -04001227
1228 LocationSummary* locations = cond->GetLocations();
1229 Location lhs = locations->InAt(0);
1230 Location rhs = locations->InAt(1);
1231 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1232 Label true_label, false_label;
1233
1234 switch (cond->InputAt(0)->GetType()) {
1235 default:
1236 // Integer case.
1237
1238 // Clear output register: setcc only sets the low byte.
1239 __ xorl(reg, reg);
1240
1241 if (rhs.IsRegister()) {
1242 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1243 } else if (rhs.IsConstant()) {
1244 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1245 if (constant == 0) {
1246 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1247 } else {
1248 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1249 }
1250 } else {
1251 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1252 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001253 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001254 return;
1255 case Primitive::kPrimLong:
1256 // Clear output register: setcc only sets the low byte.
1257 __ xorl(reg, reg);
1258
1259 if (rhs.IsRegister()) {
1260 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1261 } else if (rhs.IsConstant()) {
1262 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1263 if (IsInt<32>(value)) {
1264 if (value == 0) {
1265 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1266 } else {
1267 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1268 }
1269 } else {
1270 // Value won't fit in an int.
1271 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1272 }
1273 } else {
1274 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1275 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001276 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001277 return;
1278 case Primitive::kPrimFloat: {
1279 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1280 if (rhs.IsConstant()) {
1281 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1282 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1283 } else if (rhs.IsStackSlot()) {
1284 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1285 } else {
1286 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1287 }
1288 GenerateFPJumps(cond, &true_label, &false_label);
1289 break;
1290 }
1291 case Primitive::kPrimDouble: {
1292 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1293 if (rhs.IsConstant()) {
1294 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1295 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1296 } else if (rhs.IsDoubleStackSlot()) {
1297 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1298 } else {
1299 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1300 }
1301 GenerateFPJumps(cond, &true_label, &false_label);
1302 break;
1303 }
1304 }
1305
1306 // Convert the jumps into the result.
1307 Label done_label;
1308
Roland Levillain4fa13f62015-07-06 18:11:54 +01001309 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001310 __ Bind(&false_label);
1311 __ xorl(reg, reg);
1312 __ jmp(&done_label);
1313
Roland Levillain4fa13f62015-07-06 18:11:54 +01001314 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001315 __ Bind(&true_label);
1316 __ movl(reg, Immediate(1));
1317 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001318}
1319
1320void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1321 VisitCondition(comp);
1322}
1323
1324void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1325 VisitCondition(comp);
1326}
1327
1328void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1329 VisitCondition(comp);
1330}
1331
1332void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1333 VisitCondition(comp);
1334}
1335
1336void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1337 VisitCondition(comp);
1338}
1339
1340void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1341 VisitCondition(comp);
1342}
1343
1344void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1345 VisitCondition(comp);
1346}
1347
1348void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1349 VisitCondition(comp);
1350}
1351
1352void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1353 VisitCondition(comp);
1354}
1355
1356void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1357 VisitCondition(comp);
1358}
1359
1360void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1361 VisitCondition(comp);
1362}
1363
1364void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1365 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001366}
1367
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001368void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001369 LocationSummary* locations =
1370 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001371 switch (compare->InputAt(0)->GetType()) {
1372 case Primitive::kPrimLong: {
1373 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001374 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001375 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1376 break;
1377 }
1378 case Primitive::kPrimFloat:
1379 case Primitive::kPrimDouble: {
1380 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001381 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001382 locations->SetOut(Location::RequiresRegister());
1383 break;
1384 }
1385 default:
1386 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1387 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001388}
1389
1390void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001391 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001392 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001393 Location left = locations->InAt(0);
1394 Location right = locations->InAt(1);
1395
1396 Label less, greater, done;
1397 Primitive::Type type = compare->InputAt(0)->GetType();
1398 switch (type) {
1399 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001400 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1401 if (right.IsConstant()) {
1402 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001403 if (IsInt<32>(value)) {
1404 if (value == 0) {
1405 __ testq(left_reg, left_reg);
1406 } else {
1407 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1408 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001409 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001410 // Value won't fit in an int.
1411 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001412 }
Mark Mendell40741f32015-04-20 22:10:34 -04001413 } else if (right.IsDoubleStackSlot()) {
1414 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001415 } else {
1416 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1417 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001418 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001419 }
1420 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001421 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1422 if (right.IsConstant()) {
1423 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1424 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1425 } else if (right.IsStackSlot()) {
1426 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1427 } else {
1428 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1429 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001430 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1431 break;
1432 }
1433 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001434 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1435 if (right.IsConstant()) {
1436 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1437 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1438 } else if (right.IsDoubleStackSlot()) {
1439 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1440 } else {
1441 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1442 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001443 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1444 break;
1445 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001446 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001447 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001448 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001449 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001450 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001451 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001452
Calin Juravle91debbc2014-11-26 19:01:09 +00001453 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001454 __ movl(out, Immediate(1));
1455 __ jmp(&done);
1456
1457 __ Bind(&less);
1458 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001459
1460 __ Bind(&done);
1461}
1462
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001463void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001464 LocationSummary* locations =
1465 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001466 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001467}
1468
1469void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001470 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001471 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001472}
1473
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001474void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1475 LocationSummary* locations =
1476 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1477 locations->SetOut(Location::ConstantLocation(constant));
1478}
1479
1480void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1481 // Will be generated at use site.
1482 UNUSED(constant);
1483}
1484
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001485void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001486 LocationSummary* locations =
1487 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001488 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001489}
1490
1491void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001492 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001493 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001494}
1495
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001496void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1497 LocationSummary* locations =
1498 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1499 locations->SetOut(Location::ConstantLocation(constant));
1500}
1501
1502void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1503 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001504 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001505}
1506
1507void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1508 LocationSummary* locations =
1509 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1510 locations->SetOut(Location::ConstantLocation(constant));
1511}
1512
1513void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1514 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001515 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001516}
1517
Calin Juravle27df7582015-04-17 19:12:31 +01001518void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1519 memory_barrier->SetLocations(nullptr);
1520}
1521
1522void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1523 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1524}
1525
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001526void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1527 ret->SetLocations(nullptr);
1528}
1529
1530void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001531 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001532 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001533}
1534
1535void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001536 LocationSummary* locations =
1537 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001538 switch (ret->InputAt(0)->GetType()) {
1539 case Primitive::kPrimBoolean:
1540 case Primitive::kPrimByte:
1541 case Primitive::kPrimChar:
1542 case Primitive::kPrimShort:
1543 case Primitive::kPrimInt:
1544 case Primitive::kPrimNot:
1545 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001546 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001547 break;
1548
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001549 case Primitive::kPrimFloat:
1550 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001551 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001552 break;
1553
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001554 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001555 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001556 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001557}
1558
1559void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1560 if (kIsDebugBuild) {
1561 switch (ret->InputAt(0)->GetType()) {
1562 case Primitive::kPrimBoolean:
1563 case Primitive::kPrimByte:
1564 case Primitive::kPrimChar:
1565 case Primitive::kPrimShort:
1566 case Primitive::kPrimInt:
1567 case Primitive::kPrimNot:
1568 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001569 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001570 break;
1571
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001572 case Primitive::kPrimFloat:
1573 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001574 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001575 XMM0);
1576 break;
1577
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001578 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001579 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001580 }
1581 }
1582 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001583}
1584
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001585Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1586 switch (type) {
1587 case Primitive::kPrimBoolean:
1588 case Primitive::kPrimByte:
1589 case Primitive::kPrimChar:
1590 case Primitive::kPrimShort:
1591 case Primitive::kPrimInt:
1592 case Primitive::kPrimNot:
1593 case Primitive::kPrimLong:
1594 return Location::RegisterLocation(RAX);
1595
1596 case Primitive::kPrimVoid:
1597 return Location::NoLocation();
1598
1599 case Primitive::kPrimDouble:
1600 case Primitive::kPrimFloat:
1601 return Location::FpuRegisterLocation(XMM0);
1602 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001603
1604 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001605}
1606
1607Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1608 return Location::RegisterLocation(kMethodRegisterArgument);
1609}
1610
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001611Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001612 switch (type) {
1613 case Primitive::kPrimBoolean:
1614 case Primitive::kPrimByte:
1615 case Primitive::kPrimChar:
1616 case Primitive::kPrimShort:
1617 case Primitive::kPrimInt:
1618 case Primitive::kPrimNot: {
1619 uint32_t index = gp_index_++;
1620 stack_index_++;
1621 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001622 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001623 } else {
1624 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1625 }
1626 }
1627
1628 case Primitive::kPrimLong: {
1629 uint32_t index = gp_index_;
1630 stack_index_ += 2;
1631 if (index < calling_convention.GetNumberOfRegisters()) {
1632 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001633 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001634 } else {
1635 gp_index_ += 2;
1636 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1637 }
1638 }
1639
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001640 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001641 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001642 stack_index_++;
1643 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001644 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001645 } else {
1646 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1647 }
1648 }
1649
1650 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001651 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001652 stack_index_ += 2;
1653 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001654 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001655 } else {
1656 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1657 }
1658 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001659
1660 case Primitive::kPrimVoid:
1661 LOG(FATAL) << "Unexpected parameter type " << type;
1662 break;
1663 }
1664 return Location();
1665}
1666
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001667void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001668 // When we do not run baseline, explicit clinit checks triggered by static
1669 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1670 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001671
Mark Mendellfb8d2792015-03-31 22:16:59 -04001672 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001673 if (intrinsic.TryDispatch(invoke)) {
1674 return;
1675 }
1676
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001677 HandleInvoke(invoke);
1678}
1679
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001680static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1681 if (invoke->GetLocations()->Intrinsified()) {
1682 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1683 intrinsic.Dispatch(invoke);
1684 return true;
1685 }
1686 return false;
1687}
1688
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001689void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001690 // When we do not run baseline, explicit clinit checks triggered by static
1691 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1692 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001693
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001694 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1695 return;
1696 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001697
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001698 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001699 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001700 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001701 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001702}
1703
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001704void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001705 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001706 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001707}
1708
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001709void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001710 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001711 if (intrinsic.TryDispatch(invoke)) {
1712 return;
1713 }
1714
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001715 HandleInvoke(invoke);
1716}
1717
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001718void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001719 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1720 return;
1721 }
1722
Roland Levillain271ab9c2014-11-27 15:23:57 +00001723 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001724 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1725 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001726 LocationSummary* locations = invoke->GetLocations();
1727 Location receiver = locations->InAt(0);
1728 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1729 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001730 DCHECK(receiver.IsRegister());
1731 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001732 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001733 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001734 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001735 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001736 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001737 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001738 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001739
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001740 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001741 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001742}
1743
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001744void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1745 HandleInvoke(invoke);
1746 // Add the hidden argument.
1747 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1748}
1749
1750void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1751 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001752 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001753 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1754 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001755 LocationSummary* locations = invoke->GetLocations();
1756 Location receiver = locations->InAt(0);
1757 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1758
1759 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001760 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1761 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001762
1763 // temp = object->GetClass();
1764 if (receiver.IsStackSlot()) {
1765 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1766 __ movl(temp, Address(temp, class_offset));
1767 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001768 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001769 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001770 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001771 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001772 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001773 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001774 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001775 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001776 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001777
1778 DCHECK(!codegen_->IsLeafMethod());
1779 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1780}
1781
Roland Levillain88cb1752014-10-20 16:36:47 +01001782void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1783 LocationSummary* locations =
1784 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1785 switch (neg->GetResultType()) {
1786 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001787 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001788 locations->SetInAt(0, Location::RequiresRegister());
1789 locations->SetOut(Location::SameAsFirstInput());
1790 break;
1791
Roland Levillain88cb1752014-10-20 16:36:47 +01001792 case Primitive::kPrimFloat:
1793 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001794 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001795 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001796 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001797 break;
1798
1799 default:
1800 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1801 }
1802}
1803
1804void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1805 LocationSummary* locations = neg->GetLocations();
1806 Location out = locations->Out();
1807 Location in = locations->InAt(0);
1808 switch (neg->GetResultType()) {
1809 case Primitive::kPrimInt:
1810 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001811 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001812 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001813 break;
1814
1815 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001816 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001817 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001818 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001819 break;
1820
Roland Levillain5368c212014-11-27 15:03:41 +00001821 case Primitive::kPrimFloat: {
1822 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001823 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001824 // Implement float negation with an exclusive or with value
1825 // 0x80000000 (mask for bit 31, representing the sign of a
1826 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001827 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001828 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001829 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001830 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001831
Roland Levillain5368c212014-11-27 15:03:41 +00001832 case Primitive::kPrimDouble: {
1833 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001834 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001835 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001836 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001837 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001838 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001839 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001840 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001841 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001842
1843 default:
1844 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1845 }
1846}
1847
Roland Levillaindff1f282014-11-05 14:15:05 +00001848void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1849 LocationSummary* locations =
1850 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1851 Primitive::Type result_type = conversion->GetResultType();
1852 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001853 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001854
David Brazdilb2bd1c52015-03-25 11:17:37 +00001855 // The Java language does not allow treating boolean as an integral type but
1856 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001857
Roland Levillaindff1f282014-11-05 14:15:05 +00001858 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001859 case Primitive::kPrimByte:
1860 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001861 case Primitive::kPrimBoolean:
1862 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001863 case Primitive::kPrimShort:
1864 case Primitive::kPrimInt:
1865 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001866 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001867 locations->SetInAt(0, Location::Any());
1868 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1869 break;
1870
1871 default:
1872 LOG(FATAL) << "Unexpected type conversion from " << input_type
1873 << " to " << result_type;
1874 }
1875 break;
1876
Roland Levillain01a8d712014-11-14 16:27:39 +00001877 case Primitive::kPrimShort:
1878 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001879 case Primitive::kPrimBoolean:
1880 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001881 case Primitive::kPrimByte:
1882 case Primitive::kPrimInt:
1883 case Primitive::kPrimChar:
1884 // Processing a Dex `int-to-short' instruction.
1885 locations->SetInAt(0, Location::Any());
1886 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1887 break;
1888
1889 default:
1890 LOG(FATAL) << "Unexpected type conversion from " << input_type
1891 << " to " << result_type;
1892 }
1893 break;
1894
Roland Levillain946e1432014-11-11 17:35:19 +00001895 case Primitive::kPrimInt:
1896 switch (input_type) {
1897 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001898 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001899 locations->SetInAt(0, Location::Any());
1900 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1901 break;
1902
1903 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001904 // Processing a Dex `float-to-int' instruction.
1905 locations->SetInAt(0, Location::RequiresFpuRegister());
1906 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00001907 break;
1908
Roland Levillain946e1432014-11-11 17:35:19 +00001909 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001910 // Processing a Dex `double-to-int' instruction.
1911 locations->SetInAt(0, Location::RequiresFpuRegister());
1912 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001913 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::kPrimLong:
1922 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001923 case Primitive::kPrimBoolean:
1924 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001925 case Primitive::kPrimByte:
1926 case Primitive::kPrimShort:
1927 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001928 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001929 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001930 // TODO: We would benefit from a (to-be-implemented)
1931 // Location::RegisterOrStackSlot requirement for this input.
1932 locations->SetInAt(0, Location::RequiresRegister());
1933 locations->SetOut(Location::RequiresRegister());
1934 break;
1935
1936 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001937 // Processing a Dex `float-to-long' instruction.
1938 locations->SetInAt(0, Location::RequiresFpuRegister());
1939 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00001940 break;
1941
Roland Levillaindff1f282014-11-05 14:15:05 +00001942 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001943 // Processing a Dex `double-to-long' instruction.
1944 locations->SetInAt(0, Location::RequiresFpuRegister());
1945 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001946 break;
1947
1948 default:
1949 LOG(FATAL) << "Unexpected type conversion from " << input_type
1950 << " to " << result_type;
1951 }
1952 break;
1953
Roland Levillain981e4542014-11-14 11:47:14 +00001954 case Primitive::kPrimChar:
1955 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001956 case Primitive::kPrimBoolean:
1957 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001958 case Primitive::kPrimByte:
1959 case Primitive::kPrimShort:
1960 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001961 // Processing a Dex `int-to-char' instruction.
1962 locations->SetInAt(0, Location::Any());
1963 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1964 break;
1965
1966 default:
1967 LOG(FATAL) << "Unexpected type conversion from " << input_type
1968 << " to " << result_type;
1969 }
1970 break;
1971
Roland Levillaindff1f282014-11-05 14:15:05 +00001972 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001973 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001974 case Primitive::kPrimBoolean:
1975 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001976 case Primitive::kPrimByte:
1977 case Primitive::kPrimShort:
1978 case Primitive::kPrimInt:
1979 case Primitive::kPrimChar:
1980 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001981 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001982 locations->SetOut(Location::RequiresFpuRegister());
1983 break;
1984
1985 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001986 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001987 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001988 locations->SetOut(Location::RequiresFpuRegister());
1989 break;
1990
Roland Levillaincff13742014-11-17 14:32:17 +00001991 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001992 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001993 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001994 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001995 break;
1996
1997 default:
1998 LOG(FATAL) << "Unexpected type conversion from " << input_type
1999 << " to " << result_type;
2000 };
2001 break;
2002
Roland Levillaindff1f282014-11-05 14:15:05 +00002003 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002004 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002005 case Primitive::kPrimBoolean:
2006 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002007 case Primitive::kPrimByte:
2008 case Primitive::kPrimShort:
2009 case Primitive::kPrimInt:
2010 case Primitive::kPrimChar:
2011 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002012 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002013 locations->SetOut(Location::RequiresFpuRegister());
2014 break;
2015
2016 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002017 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002018 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002019 locations->SetOut(Location::RequiresFpuRegister());
2020 break;
2021
Roland Levillaincff13742014-11-17 14:32:17 +00002022 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002023 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002024 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002025 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002026 break;
2027
2028 default:
2029 LOG(FATAL) << "Unexpected type conversion from " << input_type
2030 << " to " << result_type;
2031 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002032 break;
2033
2034 default:
2035 LOG(FATAL) << "Unexpected type conversion from " << input_type
2036 << " to " << result_type;
2037 }
2038}
2039
2040void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2041 LocationSummary* locations = conversion->GetLocations();
2042 Location out = locations->Out();
2043 Location in = locations->InAt(0);
2044 Primitive::Type result_type = conversion->GetResultType();
2045 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002046 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002047 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002048 case Primitive::kPrimByte:
2049 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002050 case Primitive::kPrimBoolean:
2051 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002052 case Primitive::kPrimShort:
2053 case Primitive::kPrimInt:
2054 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002055 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002056 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002057 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002058 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002059 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002060 Address(CpuRegister(RSP), in.GetStackIndex()));
2061 } else {
2062 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002063 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002064 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2065 }
2066 break;
2067
2068 default:
2069 LOG(FATAL) << "Unexpected type conversion from " << input_type
2070 << " to " << result_type;
2071 }
2072 break;
2073
Roland Levillain01a8d712014-11-14 16:27:39 +00002074 case Primitive::kPrimShort:
2075 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002076 case Primitive::kPrimBoolean:
2077 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002078 case Primitive::kPrimByte:
2079 case Primitive::kPrimInt:
2080 case Primitive::kPrimChar:
2081 // Processing a Dex `int-to-short' instruction.
2082 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002083 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002084 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002085 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002086 Address(CpuRegister(RSP), in.GetStackIndex()));
2087 } else {
2088 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002089 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002090 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2091 }
2092 break;
2093
2094 default:
2095 LOG(FATAL) << "Unexpected type conversion from " << input_type
2096 << " to " << result_type;
2097 }
2098 break;
2099
Roland Levillain946e1432014-11-11 17:35:19 +00002100 case Primitive::kPrimInt:
2101 switch (input_type) {
2102 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002103 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002104 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002105 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002106 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002107 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002108 Address(CpuRegister(RSP), in.GetStackIndex()));
2109 } else {
2110 DCHECK(in.IsConstant());
2111 DCHECK(in.GetConstant()->IsLongConstant());
2112 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002113 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002114 }
2115 break;
2116
Roland Levillain3f8f9362014-12-02 17:45:01 +00002117 case Primitive::kPrimFloat: {
2118 // Processing a Dex `float-to-int' instruction.
2119 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2120 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain3f8f9362014-12-02 17:45:01 +00002121 Label done, nan;
2122
2123 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002124 // if input >= (float)INT_MAX goto done
2125 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002126 __ j(kAboveEqual, &done);
2127 // if input == NaN goto nan
2128 __ j(kUnordered, &nan);
2129 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002130 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002131 __ jmp(&done);
2132 __ Bind(&nan);
2133 // output = 0
2134 __ xorl(output, output);
2135 __ Bind(&done);
2136 break;
2137 }
2138
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002139 case Primitive::kPrimDouble: {
2140 // Processing a Dex `double-to-int' instruction.
2141 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2142 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002143 Label done, nan;
2144
2145 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002146 // if input >= (double)INT_MAX goto done
2147 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002148 __ j(kAboveEqual, &done);
2149 // if input == NaN goto nan
2150 __ j(kUnordered, &nan);
2151 // output = double-to-int-truncate(input)
2152 __ cvttsd2si(output, input);
2153 __ jmp(&done);
2154 __ Bind(&nan);
2155 // output = 0
2156 __ xorl(output, output);
2157 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002158 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002159 }
Roland Levillain946e1432014-11-11 17:35:19 +00002160
2161 default:
2162 LOG(FATAL) << "Unexpected type conversion from " << input_type
2163 << " to " << result_type;
2164 }
2165 break;
2166
Roland Levillaindff1f282014-11-05 14:15:05 +00002167 case Primitive::kPrimLong:
2168 switch (input_type) {
2169 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002170 case Primitive::kPrimBoolean:
2171 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002172 case Primitive::kPrimByte:
2173 case Primitive::kPrimShort:
2174 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002175 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002176 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002177 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002178 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002179 break;
2180
Roland Levillain624279f2014-12-04 11:54:28 +00002181 case Primitive::kPrimFloat: {
2182 // Processing a Dex `float-to-long' instruction.
2183 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2184 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain624279f2014-12-04 11:54:28 +00002185 Label done, nan;
2186
Mark Mendell92e83bf2015-05-07 11:25:03 -04002187 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002188 // if input >= (float)LONG_MAX goto done
2189 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002190 __ j(kAboveEqual, &done);
2191 // if input == NaN goto nan
2192 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002193 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002194 __ cvttss2si(output, input, true);
2195 __ jmp(&done);
2196 __ Bind(&nan);
2197 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002198 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002199 __ Bind(&done);
2200 break;
2201 }
2202
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002203 case Primitive::kPrimDouble: {
2204 // Processing a Dex `double-to-long' instruction.
2205 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2206 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002207 Label done, nan;
2208
Mark Mendell92e83bf2015-05-07 11:25:03 -04002209 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002210 // if input >= (double)LONG_MAX goto done
2211 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002212 __ j(kAboveEqual, &done);
2213 // if input == NaN goto nan
2214 __ j(kUnordered, &nan);
2215 // output = double-to-long-truncate(input)
2216 __ cvttsd2si(output, input, true);
2217 __ jmp(&done);
2218 __ Bind(&nan);
2219 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002220 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002221 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002222 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002223 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002224
2225 default:
2226 LOG(FATAL) << "Unexpected type conversion from " << input_type
2227 << " to " << result_type;
2228 }
2229 break;
2230
Roland Levillain981e4542014-11-14 11:47:14 +00002231 case Primitive::kPrimChar:
2232 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002233 case Primitive::kPrimBoolean:
2234 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002235 case Primitive::kPrimByte:
2236 case Primitive::kPrimShort:
2237 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002238 // Processing a Dex `int-to-char' instruction.
2239 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002240 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002241 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002242 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002243 Address(CpuRegister(RSP), in.GetStackIndex()));
2244 } else {
2245 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002246 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002247 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2248 }
2249 break;
2250
2251 default:
2252 LOG(FATAL) << "Unexpected type conversion from " << input_type
2253 << " to " << result_type;
2254 }
2255 break;
2256
Roland Levillaindff1f282014-11-05 14:15:05 +00002257 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002258 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002259 case Primitive::kPrimBoolean:
2260 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002261 case Primitive::kPrimByte:
2262 case Primitive::kPrimShort:
2263 case Primitive::kPrimInt:
2264 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002265 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002266 if (in.IsRegister()) {
2267 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2268 } else if (in.IsConstant()) {
2269 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2270 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2271 if (v == 0) {
2272 __ xorps(dest, dest);
2273 } else {
2274 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2275 }
2276 } else {
2277 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2278 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2279 }
Roland Levillaincff13742014-11-17 14:32:17 +00002280 break;
2281
2282 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002283 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002284 if (in.IsRegister()) {
2285 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2286 } else if (in.IsConstant()) {
2287 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2288 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2289 if (v == 0) {
2290 __ xorps(dest, dest);
2291 } else {
2292 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2293 }
2294 } else {
2295 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2296 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2297 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002298 break;
2299
Roland Levillaincff13742014-11-17 14:32:17 +00002300 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002301 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002302 if (in.IsFpuRegister()) {
2303 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2304 } else if (in.IsConstant()) {
2305 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2306 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2307 if (bit_cast<int64_t, double>(v) == 0) {
2308 __ xorps(dest, dest);
2309 } else {
2310 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2311 }
2312 } else {
2313 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2314 Address(CpuRegister(RSP), in.GetStackIndex()));
2315 }
Roland Levillaincff13742014-11-17 14:32:17 +00002316 break;
2317
2318 default:
2319 LOG(FATAL) << "Unexpected type conversion from " << input_type
2320 << " to " << result_type;
2321 };
2322 break;
2323
Roland Levillaindff1f282014-11-05 14:15:05 +00002324 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002325 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002326 case Primitive::kPrimBoolean:
2327 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002328 case Primitive::kPrimByte:
2329 case Primitive::kPrimShort:
2330 case Primitive::kPrimInt:
2331 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002332 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002333 if (in.IsRegister()) {
2334 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2335 } else if (in.IsConstant()) {
2336 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2337 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2338 if (v == 0) {
2339 __ xorpd(dest, dest);
2340 } else {
2341 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2342 }
2343 } else {
2344 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2345 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2346 }
Roland Levillaincff13742014-11-17 14:32:17 +00002347 break;
2348
2349 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002350 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002351 if (in.IsRegister()) {
2352 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2353 } else if (in.IsConstant()) {
2354 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2355 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2356 if (v == 0) {
2357 __ xorpd(dest, dest);
2358 } else {
2359 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2360 }
2361 } else {
2362 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2363 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2364 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002365 break;
2366
Roland Levillaincff13742014-11-17 14:32:17 +00002367 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002368 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002369 if (in.IsFpuRegister()) {
2370 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2371 } else if (in.IsConstant()) {
2372 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2373 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2374 if (bit_cast<int32_t, float>(v) == 0) {
2375 __ xorpd(dest, dest);
2376 } else {
2377 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2378 }
2379 } else {
2380 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2381 Address(CpuRegister(RSP), in.GetStackIndex()));
2382 }
Roland Levillaincff13742014-11-17 14:32:17 +00002383 break;
2384
2385 default:
2386 LOG(FATAL) << "Unexpected type conversion from " << input_type
2387 << " to " << result_type;
2388 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002389 break;
2390
2391 default:
2392 LOG(FATAL) << "Unexpected type conversion from " << input_type
2393 << " to " << result_type;
2394 }
2395}
2396
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002397void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002398 LocationSummary* locations =
2399 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002400 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002401 case Primitive::kPrimInt: {
2402 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002403 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2404 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002405 break;
2406 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002407
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002408 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002409 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002410 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002411 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002412 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002413 break;
2414 }
2415
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002416 case Primitive::kPrimDouble:
2417 case Primitive::kPrimFloat: {
2418 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002419 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002420 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002421 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002422 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002423
2424 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002425 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002426 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002427}
2428
2429void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2430 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002431 Location first = locations->InAt(0);
2432 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002433 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002434
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002435 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002436 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002437 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002438 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2439 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002440 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2441 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002442 } else {
2443 __ leal(out.AsRegister<CpuRegister>(), Address(
2444 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2445 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002446 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002447 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2448 __ addl(out.AsRegister<CpuRegister>(),
2449 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2450 } else {
2451 __ leal(out.AsRegister<CpuRegister>(), Address(
2452 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2453 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002454 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002455 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002456 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002457 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002458 break;
2459 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002460
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002461 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002462 if (second.IsRegister()) {
2463 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2464 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002465 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2466 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002467 } else {
2468 __ leaq(out.AsRegister<CpuRegister>(), Address(
2469 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2470 }
2471 } else {
2472 DCHECK(second.IsConstant());
2473 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2474 int32_t int32_value = Low32Bits(value);
2475 DCHECK_EQ(int32_value, value);
2476 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2477 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2478 } else {
2479 __ leaq(out.AsRegister<CpuRegister>(), Address(
2480 first.AsRegister<CpuRegister>(), int32_value));
2481 }
2482 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002483 break;
2484 }
2485
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002486 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002487 if (second.IsFpuRegister()) {
2488 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2489 } else if (second.IsConstant()) {
2490 __ addss(first.AsFpuRegister<XmmRegister>(),
2491 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2492 } else {
2493 DCHECK(second.IsStackSlot());
2494 __ addss(first.AsFpuRegister<XmmRegister>(),
2495 Address(CpuRegister(RSP), second.GetStackIndex()));
2496 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002497 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002498 }
2499
2500 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002501 if (second.IsFpuRegister()) {
2502 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2503 } else if (second.IsConstant()) {
2504 __ addsd(first.AsFpuRegister<XmmRegister>(),
2505 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2506 } else {
2507 DCHECK(second.IsDoubleStackSlot());
2508 __ addsd(first.AsFpuRegister<XmmRegister>(),
2509 Address(CpuRegister(RSP), second.GetStackIndex()));
2510 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002511 break;
2512 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002513
2514 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002515 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002516 }
2517}
2518
2519void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002520 LocationSummary* locations =
2521 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002522 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002523 case Primitive::kPrimInt: {
2524 locations->SetInAt(0, Location::RequiresRegister());
2525 locations->SetInAt(1, Location::Any());
2526 locations->SetOut(Location::SameAsFirstInput());
2527 break;
2528 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002529 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002530 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002531 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002532 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002533 break;
2534 }
Calin Juravle11351682014-10-23 15:38:15 +01002535 case Primitive::kPrimFloat:
2536 case Primitive::kPrimDouble: {
2537 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002538 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002539 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002540 break;
Calin Juravle11351682014-10-23 15:38:15 +01002541 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002542 default:
Calin Juravle11351682014-10-23 15:38:15 +01002543 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002544 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002545}
2546
2547void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2548 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002549 Location first = locations->InAt(0);
2550 Location second = locations->InAt(1);
2551 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002552 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002553 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002554 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002555 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002556 } else if (second.IsConstant()) {
2557 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002558 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002559 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002560 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002561 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002562 break;
2563 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002564 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002565 if (second.IsConstant()) {
2566 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2567 DCHECK(IsInt<32>(value));
2568 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2569 } else {
2570 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2571 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002572 break;
2573 }
2574
Calin Juravle11351682014-10-23 15:38:15 +01002575 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002576 if (second.IsFpuRegister()) {
2577 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2578 } else if (second.IsConstant()) {
2579 __ subss(first.AsFpuRegister<XmmRegister>(),
2580 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2581 } else {
2582 DCHECK(second.IsStackSlot());
2583 __ subss(first.AsFpuRegister<XmmRegister>(),
2584 Address(CpuRegister(RSP), second.GetStackIndex()));
2585 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002586 break;
Calin Juravle11351682014-10-23 15:38:15 +01002587 }
2588
2589 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002590 if (second.IsFpuRegister()) {
2591 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2592 } else if (second.IsConstant()) {
2593 __ subsd(first.AsFpuRegister<XmmRegister>(),
2594 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2595 } else {
2596 DCHECK(second.IsDoubleStackSlot());
2597 __ subsd(first.AsFpuRegister<XmmRegister>(),
2598 Address(CpuRegister(RSP), second.GetStackIndex()));
2599 }
Calin Juravle11351682014-10-23 15:38:15 +01002600 break;
2601 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002602
2603 default:
Calin Juravle11351682014-10-23 15:38:15 +01002604 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002605 }
2606}
2607
Calin Juravle34bacdf2014-10-07 20:23:36 +01002608void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2609 LocationSummary* locations =
2610 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2611 switch (mul->GetResultType()) {
2612 case Primitive::kPrimInt: {
2613 locations->SetInAt(0, Location::RequiresRegister());
2614 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002615 if (mul->InputAt(1)->IsIntConstant()) {
2616 // Can use 3 operand multiply.
2617 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2618 } else {
2619 locations->SetOut(Location::SameAsFirstInput());
2620 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002621 break;
2622 }
2623 case Primitive::kPrimLong: {
2624 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002625 locations->SetInAt(1, Location::Any());
2626 if (mul->InputAt(1)->IsLongConstant() &&
2627 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002628 // Can use 3 operand multiply.
2629 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2630 } else {
2631 locations->SetOut(Location::SameAsFirstInput());
2632 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002633 break;
2634 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002635 case Primitive::kPrimFloat:
2636 case Primitive::kPrimDouble: {
2637 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002638 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002639 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002640 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002641 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002642
2643 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002644 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002645 }
2646}
2647
2648void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2649 LocationSummary* locations = mul->GetLocations();
2650 Location first = locations->InAt(0);
2651 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002652 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002653 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002654 case Primitive::kPrimInt:
2655 // The constant may have ended up in a register, so test explicitly to avoid
2656 // problems where the output may not be the same as the first operand.
2657 if (mul->InputAt(1)->IsIntConstant()) {
2658 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2659 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2660 } else if (second.IsRegister()) {
2661 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002662 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002663 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002664 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002665 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002666 __ imull(first.AsRegister<CpuRegister>(),
2667 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002668 }
2669 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002670 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002671 // The constant may have ended up in a register, so test explicitly to avoid
2672 // problems where the output may not be the same as the first operand.
2673 if (mul->InputAt(1)->IsLongConstant()) {
2674 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2675 if (IsInt<32>(value)) {
2676 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2677 Immediate(static_cast<int32_t>(value)));
2678 } else {
2679 // Have to use the constant area.
2680 DCHECK(first.Equals(out));
2681 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2682 }
2683 } else if (second.IsRegister()) {
2684 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002685 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002686 } else {
2687 DCHECK(second.IsDoubleStackSlot());
2688 DCHECK(first.Equals(out));
2689 __ imulq(first.AsRegister<CpuRegister>(),
2690 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002691 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002692 break;
2693 }
2694
Calin Juravleb5bfa962014-10-21 18:02:24 +01002695 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002696 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002697 if (second.IsFpuRegister()) {
2698 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2699 } else if (second.IsConstant()) {
2700 __ mulss(first.AsFpuRegister<XmmRegister>(),
2701 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2702 } else {
2703 DCHECK(second.IsStackSlot());
2704 __ mulss(first.AsFpuRegister<XmmRegister>(),
2705 Address(CpuRegister(RSP), second.GetStackIndex()));
2706 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002707 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002708 }
2709
2710 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002711 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002712 if (second.IsFpuRegister()) {
2713 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2714 } else if (second.IsConstant()) {
2715 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2716 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2717 } else {
2718 DCHECK(second.IsDoubleStackSlot());
2719 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2720 Address(CpuRegister(RSP), second.GetStackIndex()));
2721 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002722 break;
2723 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002724
2725 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002726 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002727 }
2728}
2729
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002730void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2731 uint32_t stack_adjustment, bool is_float) {
2732 if (source.IsStackSlot()) {
2733 DCHECK(is_float);
2734 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2735 } else if (source.IsDoubleStackSlot()) {
2736 DCHECK(!is_float);
2737 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2738 } else {
2739 // Write the value to the temporary location on the stack and load to FP stack.
2740 if (is_float) {
2741 Location stack_temp = Location::StackSlot(temp_offset);
2742 codegen_->Move(stack_temp, source);
2743 __ flds(Address(CpuRegister(RSP), temp_offset));
2744 } else {
2745 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2746 codegen_->Move(stack_temp, source);
2747 __ fldl(Address(CpuRegister(RSP), temp_offset));
2748 }
2749 }
2750}
2751
2752void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2753 Primitive::Type type = rem->GetResultType();
2754 bool is_float = type == Primitive::kPrimFloat;
2755 size_t elem_size = Primitive::ComponentSize(type);
2756 LocationSummary* locations = rem->GetLocations();
2757 Location first = locations->InAt(0);
2758 Location second = locations->InAt(1);
2759 Location out = locations->Out();
2760
2761 // Create stack space for 2 elements.
2762 // TODO: enhance register allocator to ask for stack temporaries.
2763 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2764
2765 // Load the values to the FP stack in reverse order, using temporaries if needed.
2766 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2767 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2768
2769 // Loop doing FPREM until we stabilize.
2770 Label retry;
2771 __ Bind(&retry);
2772 __ fprem();
2773
2774 // Move FP status to AX.
2775 __ fstsw();
2776
2777 // And see if the argument reduction is complete. This is signaled by the
2778 // C2 FPU flag bit set to 0.
2779 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2780 __ j(kNotEqual, &retry);
2781
2782 // We have settled on the final value. Retrieve it into an XMM register.
2783 // Store FP top of stack to real stack.
2784 if (is_float) {
2785 __ fsts(Address(CpuRegister(RSP), 0));
2786 } else {
2787 __ fstl(Address(CpuRegister(RSP), 0));
2788 }
2789
2790 // Pop the 2 items from the FP stack.
2791 __ fucompp();
2792
2793 // Load the value from the stack into an XMM register.
2794 DCHECK(out.IsFpuRegister()) << out;
2795 if (is_float) {
2796 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2797 } else {
2798 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2799 }
2800
2801 // And remove the temporary stack space we allocated.
2802 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2803}
2804
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002805void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2806 DCHECK(instruction->IsDiv() || instruction->IsRem());
2807
2808 LocationSummary* locations = instruction->GetLocations();
2809 Location second = locations->InAt(1);
2810 DCHECK(second.IsConstant());
2811
2812 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2813 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002814 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002815
2816 DCHECK(imm == 1 || imm == -1);
2817
2818 switch (instruction->GetResultType()) {
2819 case Primitive::kPrimInt: {
2820 if (instruction->IsRem()) {
2821 __ xorl(output_register, output_register);
2822 } else {
2823 __ movl(output_register, input_register);
2824 if (imm == -1) {
2825 __ negl(output_register);
2826 }
2827 }
2828 break;
2829 }
2830
2831 case Primitive::kPrimLong: {
2832 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002833 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002834 } else {
2835 __ movq(output_register, input_register);
2836 if (imm == -1) {
2837 __ negq(output_register);
2838 }
2839 }
2840 break;
2841 }
2842
2843 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002844 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002845 }
2846}
2847
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002848void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002849 LocationSummary* locations = instruction->GetLocations();
2850 Location second = locations->InAt(1);
2851
2852 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2853 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2854
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002855 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002856
2857 DCHECK(IsPowerOfTwo(std::abs(imm)));
2858
2859 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2860
2861 if (instruction->GetResultType() == Primitive::kPrimInt) {
2862 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2863 __ testl(numerator, numerator);
2864 __ cmov(kGreaterEqual, tmp, numerator);
2865 int shift = CTZ(imm);
2866 __ sarl(tmp, Immediate(shift));
2867
2868 if (imm < 0) {
2869 __ negl(tmp);
2870 }
2871
2872 __ movl(output_register, tmp);
2873 } else {
2874 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2875 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2876
Mark Mendell92e83bf2015-05-07 11:25:03 -04002877 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002878 __ addq(rdx, numerator);
2879 __ testq(numerator, numerator);
2880 __ cmov(kGreaterEqual, rdx, numerator);
2881 int shift = CTZ(imm);
2882 __ sarq(rdx, Immediate(shift));
2883
2884 if (imm < 0) {
2885 __ negq(rdx);
2886 }
2887
2888 __ movq(output_register, rdx);
2889 }
2890}
2891
2892void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2893 DCHECK(instruction->IsDiv() || instruction->IsRem());
2894
2895 LocationSummary* locations = instruction->GetLocations();
2896 Location second = locations->InAt(1);
2897
2898 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2899 : locations->GetTemp(0).AsRegister<CpuRegister>();
2900 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2901 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2902 : locations->Out().AsRegister<CpuRegister>();
2903 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2904
2905 DCHECK_EQ(RAX, eax.AsRegister());
2906 DCHECK_EQ(RDX, edx.AsRegister());
2907 if (instruction->IsDiv()) {
2908 DCHECK_EQ(RAX, out.AsRegister());
2909 } else {
2910 DCHECK_EQ(RDX, out.AsRegister());
2911 }
2912
2913 int64_t magic;
2914 int shift;
2915
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002916 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002917 if (instruction->GetResultType() == Primitive::kPrimInt) {
2918 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2919
2920 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2921
2922 __ movl(numerator, eax);
2923
2924 Label no_div;
2925 Label end;
2926 __ testl(eax, eax);
2927 __ j(kNotEqual, &no_div);
2928
2929 __ xorl(out, out);
2930 __ jmp(&end);
2931
2932 __ Bind(&no_div);
2933
2934 __ movl(eax, Immediate(magic));
2935 __ imull(numerator);
2936
2937 if (imm > 0 && magic < 0) {
2938 __ addl(edx, numerator);
2939 } else if (imm < 0 && magic > 0) {
2940 __ subl(edx, numerator);
2941 }
2942
2943 if (shift != 0) {
2944 __ sarl(edx, Immediate(shift));
2945 }
2946
2947 __ movl(eax, edx);
2948 __ shrl(edx, Immediate(31));
2949 __ addl(edx, eax);
2950
2951 if (instruction->IsRem()) {
2952 __ movl(eax, numerator);
2953 __ imull(edx, Immediate(imm));
2954 __ subl(eax, edx);
2955 __ movl(edx, eax);
2956 } else {
2957 __ movl(eax, edx);
2958 }
2959 __ Bind(&end);
2960 } else {
2961 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2962
2963 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2964
2965 CpuRegister rax = eax;
2966 CpuRegister rdx = edx;
2967
2968 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2969
2970 // Save the numerator.
2971 __ movq(numerator, rax);
2972
2973 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002974 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002975
2976 // RDX:RAX = magic * numerator
2977 __ imulq(numerator);
2978
2979 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002980 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002981 __ addq(rdx, numerator);
2982 } else if (imm < 0 && magic > 0) {
2983 // RDX -= numerator
2984 __ subq(rdx, numerator);
2985 }
2986
2987 // Shift if needed.
2988 if (shift != 0) {
2989 __ sarq(rdx, Immediate(shift));
2990 }
2991
2992 // RDX += 1 if RDX < 0
2993 __ movq(rax, rdx);
2994 __ shrq(rdx, Immediate(63));
2995 __ addq(rdx, rax);
2996
2997 if (instruction->IsRem()) {
2998 __ movq(rax, numerator);
2999
3000 if (IsInt<32>(imm)) {
3001 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3002 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003003 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003004 }
3005
3006 __ subq(rax, rdx);
3007 __ movq(rdx, rax);
3008 } else {
3009 __ movq(rax, rdx);
3010 }
3011 }
3012}
3013
Calin Juravlebacfec32014-11-14 15:54:36 +00003014void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3015 DCHECK(instruction->IsDiv() || instruction->IsRem());
3016 Primitive::Type type = instruction->GetResultType();
3017 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3018
3019 bool is_div = instruction->IsDiv();
3020 LocationSummary* locations = instruction->GetLocations();
3021
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003022 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3023 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003024
Roland Levillain271ab9c2014-11-27 15:23:57 +00003025 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003026 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003027
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003028 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003029 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003030
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003031 if (imm == 0) {
3032 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3033 } else if (imm == 1 || imm == -1) {
3034 DivRemOneOrMinusOne(instruction);
3035 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003036 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003037 } else {
3038 DCHECK(imm <= -2 || imm >= 2);
3039 GenerateDivRemWithAnyConstant(instruction);
3040 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003041 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003042 SlowPathCodeX86_64* slow_path =
3043 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3044 out.AsRegister(), type, is_div);
3045 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003046
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003047 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3048 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3049 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3050 // so it's safe to just use negl instead of more complex comparisons.
3051 if (type == Primitive::kPrimInt) {
3052 __ cmpl(second_reg, Immediate(-1));
3053 __ j(kEqual, slow_path->GetEntryLabel());
3054 // edx:eax <- sign-extended of eax
3055 __ cdq();
3056 // eax = quotient, edx = remainder
3057 __ idivl(second_reg);
3058 } else {
3059 __ cmpq(second_reg, Immediate(-1));
3060 __ j(kEqual, slow_path->GetEntryLabel());
3061 // rdx:rax <- sign-extended of rax
3062 __ cqo();
3063 // rax = quotient, rdx = remainder
3064 __ idivq(second_reg);
3065 }
3066 __ Bind(slow_path->GetExitLabel());
3067 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003068}
3069
Calin Juravle7c4954d2014-10-28 16:57:40 +00003070void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3071 LocationSummary* locations =
3072 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3073 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003074 case Primitive::kPrimInt:
3075 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003076 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003077 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003078 locations->SetOut(Location::SameAsFirstInput());
3079 // Intel uses edx:eax as the dividend.
3080 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003081 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3082 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3083 // output and request another temp.
3084 if (div->InputAt(1)->IsConstant()) {
3085 locations->AddTemp(Location::RequiresRegister());
3086 }
Calin Juravled0d48522014-11-04 16:40:20 +00003087 break;
3088 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003089
Calin Juravle7c4954d2014-10-28 16:57:40 +00003090 case Primitive::kPrimFloat:
3091 case Primitive::kPrimDouble: {
3092 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003093 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003094 locations->SetOut(Location::SameAsFirstInput());
3095 break;
3096 }
3097
3098 default:
3099 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3100 }
3101}
3102
3103void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3104 LocationSummary* locations = div->GetLocations();
3105 Location first = locations->InAt(0);
3106 Location second = locations->InAt(1);
3107 DCHECK(first.Equals(locations->Out()));
3108
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003109 Primitive::Type type = div->GetResultType();
3110 switch (type) {
3111 case Primitive::kPrimInt:
3112 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003113 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003114 break;
3115 }
3116
Calin Juravle7c4954d2014-10-28 16:57:40 +00003117 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003118 if (second.IsFpuRegister()) {
3119 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3120 } else if (second.IsConstant()) {
3121 __ divss(first.AsFpuRegister<XmmRegister>(),
3122 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3123 } else {
3124 DCHECK(second.IsStackSlot());
3125 __ divss(first.AsFpuRegister<XmmRegister>(),
3126 Address(CpuRegister(RSP), second.GetStackIndex()));
3127 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003128 break;
3129 }
3130
3131 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003132 if (second.IsFpuRegister()) {
3133 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3134 } else if (second.IsConstant()) {
3135 __ divsd(first.AsFpuRegister<XmmRegister>(),
3136 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3137 } else {
3138 DCHECK(second.IsDoubleStackSlot());
3139 __ divsd(first.AsFpuRegister<XmmRegister>(),
3140 Address(CpuRegister(RSP), second.GetStackIndex()));
3141 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003142 break;
3143 }
3144
3145 default:
3146 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3147 }
3148}
3149
Calin Juravlebacfec32014-11-14 15:54:36 +00003150void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003151 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003152 LocationSummary* locations =
3153 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003154
3155 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003156 case Primitive::kPrimInt:
3157 case Primitive::kPrimLong: {
3158 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003159 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003160 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3161 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003162 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3163 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3164 // output and request another temp.
3165 if (rem->InputAt(1)->IsConstant()) {
3166 locations->AddTemp(Location::RequiresRegister());
3167 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003168 break;
3169 }
3170
3171 case Primitive::kPrimFloat:
3172 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003173 locations->SetInAt(0, Location::Any());
3174 locations->SetInAt(1, Location::Any());
3175 locations->SetOut(Location::RequiresFpuRegister());
3176 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003177 break;
3178 }
3179
3180 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003181 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003182 }
3183}
3184
3185void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3186 Primitive::Type type = rem->GetResultType();
3187 switch (type) {
3188 case Primitive::kPrimInt:
3189 case Primitive::kPrimLong: {
3190 GenerateDivRemIntegral(rem);
3191 break;
3192 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003193 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003194 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003195 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003196 break;
3197 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003198 default:
3199 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3200 }
3201}
3202
Calin Juravled0d48522014-11-04 16:40:20 +00003203void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3204 LocationSummary* locations =
3205 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3206 locations->SetInAt(0, Location::Any());
3207 if (instruction->HasUses()) {
3208 locations->SetOut(Location::SameAsFirstInput());
3209 }
3210}
3211
3212void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3213 SlowPathCodeX86_64* slow_path =
3214 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3215 codegen_->AddSlowPath(slow_path);
3216
3217 LocationSummary* locations = instruction->GetLocations();
3218 Location value = locations->InAt(0);
3219
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003220 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003221 case Primitive::kPrimByte:
3222 case Primitive::kPrimChar:
3223 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003224 case Primitive::kPrimInt: {
3225 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003226 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003227 __ j(kEqual, slow_path->GetEntryLabel());
3228 } else if (value.IsStackSlot()) {
3229 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3230 __ j(kEqual, slow_path->GetEntryLabel());
3231 } else {
3232 DCHECK(value.IsConstant()) << value;
3233 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3234 __ jmp(slow_path->GetEntryLabel());
3235 }
3236 }
3237 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003238 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003239 case Primitive::kPrimLong: {
3240 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003241 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003242 __ j(kEqual, slow_path->GetEntryLabel());
3243 } else if (value.IsDoubleStackSlot()) {
3244 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3245 __ j(kEqual, slow_path->GetEntryLabel());
3246 } else {
3247 DCHECK(value.IsConstant()) << value;
3248 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3249 __ jmp(slow_path->GetEntryLabel());
3250 }
3251 }
3252 break;
3253 }
3254 default:
3255 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003256 }
Calin Juravled0d48522014-11-04 16:40:20 +00003257}
3258
Calin Juravle9aec02f2014-11-18 23:06:35 +00003259void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3260 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3261
3262 LocationSummary* locations =
3263 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3264
3265 switch (op->GetResultType()) {
3266 case Primitive::kPrimInt:
3267 case Primitive::kPrimLong: {
3268 locations->SetInAt(0, Location::RequiresRegister());
3269 // The shift count needs to be in CL.
3270 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3271 locations->SetOut(Location::SameAsFirstInput());
3272 break;
3273 }
3274 default:
3275 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3276 }
3277}
3278
3279void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3280 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3281
3282 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003283 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003284 Location second = locations->InAt(1);
3285
3286 switch (op->GetResultType()) {
3287 case Primitive::kPrimInt: {
3288 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003289 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003290 if (op->IsShl()) {
3291 __ shll(first_reg, second_reg);
3292 } else if (op->IsShr()) {
3293 __ sarl(first_reg, second_reg);
3294 } else {
3295 __ shrl(first_reg, second_reg);
3296 }
3297 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003298 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003299 if (op->IsShl()) {
3300 __ shll(first_reg, imm);
3301 } else if (op->IsShr()) {
3302 __ sarl(first_reg, imm);
3303 } else {
3304 __ shrl(first_reg, imm);
3305 }
3306 }
3307 break;
3308 }
3309 case Primitive::kPrimLong: {
3310 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003311 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003312 if (op->IsShl()) {
3313 __ shlq(first_reg, second_reg);
3314 } else if (op->IsShr()) {
3315 __ sarq(first_reg, second_reg);
3316 } else {
3317 __ shrq(first_reg, second_reg);
3318 }
3319 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003320 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003321 if (op->IsShl()) {
3322 __ shlq(first_reg, imm);
3323 } else if (op->IsShr()) {
3324 __ sarq(first_reg, imm);
3325 } else {
3326 __ shrq(first_reg, imm);
3327 }
3328 }
3329 break;
3330 }
3331 default:
3332 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3333 }
3334}
3335
3336void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3337 HandleShift(shl);
3338}
3339
3340void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3341 HandleShift(shl);
3342}
3343
3344void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3345 HandleShift(shr);
3346}
3347
3348void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3349 HandleShift(shr);
3350}
3351
3352void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3353 HandleShift(ushr);
3354}
3355
3356void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3357 HandleShift(ushr);
3358}
3359
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003360void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003361 LocationSummary* locations =
3362 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003363 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003364 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003365 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003366 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003367}
3368
3369void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3370 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003371 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3372 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003373 // Note: if heap poisoning is enabled, the entry point takes cares
3374 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003375
3376 codegen_->InvokeRuntime(
3377 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3378 instruction,
3379 instruction->GetDexPc(),
3380 nullptr);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003381
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003382 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003383}
3384
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003385void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3386 LocationSummary* locations =
3387 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3388 InvokeRuntimeCallingConvention calling_convention;
3389 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003390 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003391 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003392 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003393}
3394
3395void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3396 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003397 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3398 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003399
Roland Levillain4d027112015-07-01 15:41:14 +01003400 // Note: if heap poisoning is enabled, the entry point takes cares
3401 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003402 codegen_->InvokeRuntime(
3403 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3404 instruction,
3405 instruction->GetDexPc(),
3406 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003407
3408 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003409}
3410
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003411void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003412 LocationSummary* locations =
3413 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003414 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3415 if (location.IsStackSlot()) {
3416 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3417 } else if (location.IsDoubleStackSlot()) {
3418 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3419 }
3420 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003421}
3422
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003423void InstructionCodeGeneratorX86_64::VisitParameterValue(
3424 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003425 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003426}
3427
3428void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3429 LocationSummary* locations =
3430 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3431 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3432}
3433
3434void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3435 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3436 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003437}
3438
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003439void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003440 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003441 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003442 locations->SetInAt(0, Location::RequiresRegister());
3443 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003444}
3445
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003446void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3447 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003448 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3449 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003450 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003451 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003452 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003453 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003454 break;
3455
3456 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003457 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003458 break;
3459
3460 default:
3461 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3462 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003463}
3464
David Brazdil66d126e2015-04-03 16:02:44 +01003465void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3466 LocationSummary* locations =
3467 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3468 locations->SetInAt(0, Location::RequiresRegister());
3469 locations->SetOut(Location::SameAsFirstInput());
3470}
3471
3472void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003473 LocationSummary* locations = bool_not->GetLocations();
3474 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3475 locations->Out().AsRegister<CpuRegister>().AsRegister());
3476 Location out = locations->Out();
3477 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3478}
3479
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003480void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003481 LocationSummary* locations =
3482 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003483 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3484 locations->SetInAt(i, Location::Any());
3485 }
3486 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003487}
3488
3489void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003490 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003491 LOG(FATAL) << "Unimplemented";
3492}
3493
Calin Juravle52c48962014-12-16 17:02:57 +00003494void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3495 /*
3496 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3497 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3498 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3499 */
3500 switch (kind) {
3501 case MemBarrierKind::kAnyAny: {
3502 __ mfence();
3503 break;
3504 }
3505 case MemBarrierKind::kAnyStore:
3506 case MemBarrierKind::kLoadAny:
3507 case MemBarrierKind::kStoreStore: {
3508 // nop
3509 break;
3510 }
3511 default:
3512 LOG(FATAL) << "Unexpected memory barier " << kind;
3513 }
3514}
3515
3516void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3517 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3518
Nicolas Geoffray39468442014-09-02 15:17:15 +01003519 LocationSummary* locations =
3520 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003521 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003522 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3523 locations->SetOut(Location::RequiresFpuRegister());
3524 } else {
3525 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3526 }
Calin Juravle52c48962014-12-16 17:02:57 +00003527}
3528
3529void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3530 const FieldInfo& field_info) {
3531 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3532
3533 LocationSummary* locations = instruction->GetLocations();
3534 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3535 Location out = locations->Out();
3536 bool is_volatile = field_info.IsVolatile();
3537 Primitive::Type field_type = field_info.GetFieldType();
3538 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3539
3540 switch (field_type) {
3541 case Primitive::kPrimBoolean: {
3542 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3543 break;
3544 }
3545
3546 case Primitive::kPrimByte: {
3547 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3548 break;
3549 }
3550
3551 case Primitive::kPrimShort: {
3552 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3553 break;
3554 }
3555
3556 case Primitive::kPrimChar: {
3557 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3558 break;
3559 }
3560
3561 case Primitive::kPrimInt:
3562 case Primitive::kPrimNot: {
3563 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3564 break;
3565 }
3566
3567 case Primitive::kPrimLong: {
3568 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3569 break;
3570 }
3571
3572 case Primitive::kPrimFloat: {
3573 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3574 break;
3575 }
3576
3577 case Primitive::kPrimDouble: {
3578 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3579 break;
3580 }
3581
3582 case Primitive::kPrimVoid:
3583 LOG(FATAL) << "Unreachable type " << field_type;
3584 UNREACHABLE();
3585 }
3586
Calin Juravle77520bc2015-01-12 18:45:46 +00003587 codegen_->MaybeRecordImplicitNullCheck(instruction);
3588
Calin Juravle52c48962014-12-16 17:02:57 +00003589 if (is_volatile) {
3590 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3591 }
Roland Levillain4d027112015-07-01 15:41:14 +01003592
3593 if (field_type == Primitive::kPrimNot) {
3594 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3595 }
Calin Juravle52c48962014-12-16 17:02:57 +00003596}
3597
3598void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3599 const FieldInfo& field_info) {
3600 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3601
3602 LocationSummary* locations =
3603 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003604 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003605 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003606 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003607
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003608 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003609 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3610 locations->SetInAt(1, Location::RequiresFpuRegister());
3611 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003612 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003613 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003614 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003615 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003616 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003617 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003618 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3619 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003620 locations->AddTemp(Location::RequiresRegister());
3621 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003622}
3623
Calin Juravle52c48962014-12-16 17:02:57 +00003624void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003625 const FieldInfo& field_info,
3626 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003627 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3628
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003629 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003630 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3631 Location value = locations->InAt(1);
3632 bool is_volatile = field_info.IsVolatile();
3633 Primitive::Type field_type = field_info.GetFieldType();
3634 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3635
3636 if (is_volatile) {
3637 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3638 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003639
3640 switch (field_type) {
3641 case Primitive::kPrimBoolean:
3642 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003643 if (value.IsConstant()) {
3644 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3645 __ movb(Address(base, offset), Immediate(v));
3646 } else {
3647 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3648 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003649 break;
3650 }
3651
3652 case Primitive::kPrimShort:
3653 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003654 if (value.IsConstant()) {
3655 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3656 __ movw(Address(base, offset), Immediate(v));
3657 } else {
3658 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3659 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003660 break;
3661 }
3662
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003663 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003664 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003665 if (value.IsConstant()) {
3666 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003667 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3668 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3669 // Note: if heap poisoning is enabled, no need to poison
3670 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003671 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003672 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003673 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3674 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3675 __ movl(temp, value.AsRegister<CpuRegister>());
3676 __ PoisonHeapReference(temp);
3677 __ movl(Address(base, offset), temp);
3678 } else {
3679 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3680 }
Mark Mendell40741f32015-04-20 22:10:34 -04003681 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003682 break;
3683 }
3684
3685 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003686 if (value.IsConstant()) {
3687 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3688 DCHECK(IsInt<32>(v));
3689 int32_t v_32 = v;
3690 __ movq(Address(base, offset), Immediate(v_32));
3691 } else {
3692 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3693 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003694 break;
3695 }
3696
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003697 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003698 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003699 break;
3700 }
3701
3702 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003703 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003704 break;
3705 }
3706
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003707 case Primitive::kPrimVoid:
3708 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003709 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003710 }
Calin Juravle52c48962014-12-16 17:02:57 +00003711
Calin Juravle77520bc2015-01-12 18:45:46 +00003712 codegen_->MaybeRecordImplicitNullCheck(instruction);
3713
3714 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3715 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3716 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003717 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003718 }
3719
Calin Juravle52c48962014-12-16 17:02:57 +00003720 if (is_volatile) {
3721 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3722 }
3723}
3724
3725void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3726 HandleFieldSet(instruction, instruction->GetFieldInfo());
3727}
3728
3729void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003730 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003731}
3732
3733void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003734 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003735}
3736
3737void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003738 HandleFieldGet(instruction, instruction->GetFieldInfo());
3739}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003740
Calin Juravle52c48962014-12-16 17:02:57 +00003741void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3742 HandleFieldGet(instruction);
3743}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003744
Calin Juravle52c48962014-12-16 17:02:57 +00003745void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3746 HandleFieldGet(instruction, instruction->GetFieldInfo());
3747}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003748
Calin Juravle52c48962014-12-16 17:02:57 +00003749void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3750 HandleFieldSet(instruction, instruction->GetFieldInfo());
3751}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003752
Calin Juravle52c48962014-12-16 17:02:57 +00003753void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003754 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003755}
3756
3757void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003758 LocationSummary* locations =
3759 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003760 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3761 ? Location::RequiresRegister()
3762 : Location::Any();
3763 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003764 if (instruction->HasUses()) {
3765 locations->SetOut(Location::SameAsFirstInput());
3766 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003767}
3768
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003769void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003770 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3771 return;
3772 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003773 LocationSummary* locations = instruction->GetLocations();
3774 Location obj = locations->InAt(0);
3775
3776 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3777 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3778}
3779
3780void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003781 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003782 codegen_->AddSlowPath(slow_path);
3783
3784 LocationSummary* locations = instruction->GetLocations();
3785 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003786
3787 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003788 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003789 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003790 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003791 } else {
3792 DCHECK(obj.IsConstant()) << obj;
3793 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3794 __ jmp(slow_path->GetEntryLabel());
3795 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003796 }
3797 __ j(kEqual, slow_path->GetEntryLabel());
3798}
3799
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003800void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3801 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3802 GenerateImplicitNullCheck(instruction);
3803 } else {
3804 GenerateExplicitNullCheck(instruction);
3805 }
3806}
3807
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003808void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003809 LocationSummary* locations =
3810 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003811 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003812 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003813 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3814 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3815 } else {
3816 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3817 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003818}
3819
3820void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3821 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003822 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003823 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003824 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003825
Roland Levillain4d027112015-07-01 15:41:14 +01003826 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003827 case Primitive::kPrimBoolean: {
3828 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003829 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003830 if (index.IsConstant()) {
3831 __ movzxb(out, Address(obj,
3832 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3833 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003834 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003835 }
3836 break;
3837 }
3838
3839 case Primitive::kPrimByte: {
3840 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003841 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003842 if (index.IsConstant()) {
3843 __ movsxb(out, Address(obj,
3844 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3845 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003846 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003847 }
3848 break;
3849 }
3850
3851 case Primitive::kPrimShort: {
3852 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003853 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003854 if (index.IsConstant()) {
3855 __ movsxw(out, Address(obj,
3856 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3857 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003858 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003859 }
3860 break;
3861 }
3862
3863 case Primitive::kPrimChar: {
3864 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003865 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866 if (index.IsConstant()) {
3867 __ movzxw(out, Address(obj,
3868 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3869 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003870 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003871 }
3872 break;
3873 }
3874
3875 case Primitive::kPrimInt:
3876 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003877 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3878 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003879 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003880 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003881 if (index.IsConstant()) {
3882 __ movl(out, Address(obj,
3883 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3884 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003885 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003886 }
3887 break;
3888 }
3889
3890 case Primitive::kPrimLong: {
3891 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003892 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003893 if (index.IsConstant()) {
3894 __ movq(out, Address(obj,
3895 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3896 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003897 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003898 }
3899 break;
3900 }
3901
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003902 case Primitive::kPrimFloat: {
3903 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003904 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003905 if (index.IsConstant()) {
3906 __ movss(out, Address(obj,
3907 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3908 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003909 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003910 }
3911 break;
3912 }
3913
3914 case Primitive::kPrimDouble: {
3915 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003916 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003917 if (index.IsConstant()) {
3918 __ movsd(out, Address(obj,
3919 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3920 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003921 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003922 }
3923 break;
3924 }
3925
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003926 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003927 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003928 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003930 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003931
3932 if (type == Primitive::kPrimNot) {
3933 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3934 __ MaybeUnpoisonHeapReference(out);
3935 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003936}
3937
3938void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003939 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003940
3941 bool needs_write_barrier =
3942 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3943 bool needs_runtime_call = instruction->NeedsTypeCheck();
3944
Nicolas Geoffray39468442014-09-02 15:17:15 +01003945 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003946 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3947 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003948 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003949 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3950 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3951 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003952 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003953 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003954 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003955 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3956 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003957 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003958 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003959 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3960 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003961 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003962 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003963 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003964
3965 if (needs_write_barrier) {
3966 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003967 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003968 locations->AddTemp(Location::RequiresRegister());
3969 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003970 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003971}
3972
3973void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3974 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003975 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003976 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003977 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003978 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003979 bool needs_runtime_call = locations->WillCall();
3980 bool needs_write_barrier =
3981 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003982
3983 switch (value_type) {
3984 case Primitive::kPrimBoolean:
3985 case Primitive::kPrimByte: {
3986 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003987 if (index.IsConstant()) {
3988 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003989 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003990 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003991 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003992 __ movb(Address(obj, offset),
3993 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003994 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003995 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003996 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003997 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3998 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003999 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004000 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004001 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4002 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004003 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004004 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004005 break;
4006 }
4007
4008 case Primitive::kPrimShort:
4009 case Primitive::kPrimChar: {
4010 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004011 if (index.IsConstant()) {
4012 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004013 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004014 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004015 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004016 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00004017 __ movw(Address(obj, offset),
4018 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004019 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004020 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004021 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004022 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004023 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
4024 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004025 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004026 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00004027 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004028 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4029 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004030 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004031 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004032 break;
4033 }
4034
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004035 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004036 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004037 if (!needs_runtime_call) {
4038 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4039 if (index.IsConstant()) {
4040 size_t offset =
4041 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4042 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004043 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4044 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4045 __ movl(temp, value.AsRegister<CpuRegister>());
4046 __ PoisonHeapReference(temp);
4047 __ movl(Address(obj, offset), temp);
4048 } else {
4049 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
4050 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004051 } else {
4052 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004053 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004054 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4055 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4056 // Note: if heap poisoning is enabled, no need to poison
4057 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04004058 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004059 }
4060 } else {
4061 DCHECK(index.IsRegister()) << index;
4062 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004063 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4064 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4065 __ movl(temp, value.AsRegister<CpuRegister>());
4066 __ PoisonHeapReference(temp);
4067 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
4068 } else {
4069 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4070 value.AsRegister<CpuRegister>());
4071 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004072 } else {
4073 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004074 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004075 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4076 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4077 // Note: if heap poisoning is enabled, no need to poison
4078 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004079 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04004080 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004081 }
4082 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004083 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004084 if (needs_write_barrier) {
4085 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004086 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4087 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004088 codegen_->MarkGCCard(
4089 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004090 }
4091 } else {
4092 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01004093 // Note: if heap poisoning is enabled, pAputObject takes cares
4094 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01004095 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
4096 instruction,
4097 instruction->GetDexPc(),
4098 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004099 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004100 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004101 break;
4102 }
4103
4104 case Primitive::kPrimLong: {
4105 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004106 if (index.IsConstant()) {
4107 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004108 if (value.IsRegister()) {
4109 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4110 } else {
4111 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4112 DCHECK(IsInt<32>(v));
4113 int32_t v_32 = v;
4114 __ movq(Address(obj, offset), Immediate(v_32));
4115 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004116 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004117 if (value.IsRegister()) {
4118 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4119 value.AsRegister<CpuRegister>());
4120 } else {
4121 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4122 DCHECK(IsInt<32>(v));
4123 int32_t v_32 = v;
4124 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4125 Immediate(v_32));
4126 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004127 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004128 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004129 break;
4130 }
4131
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004132 case Primitive::kPrimFloat: {
4133 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4134 if (index.IsConstant()) {
4135 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4136 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004137 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004138 } else {
4139 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004140 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4141 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004142 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004143 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004144 break;
4145 }
4146
4147 case Primitive::kPrimDouble: {
4148 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4149 if (index.IsConstant()) {
4150 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4151 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004152 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004153 } else {
4154 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004155 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4156 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004157 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004158 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004159 break;
4160 }
4161
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004162 case Primitive::kPrimVoid:
4163 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004164 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004165 }
4166}
4167
4168void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004169 LocationSummary* locations =
4170 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004171 locations->SetInAt(0, Location::RequiresRegister());
4172 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004173}
4174
4175void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4176 LocationSummary* locations = instruction->GetLocations();
4177 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004178 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4179 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004180 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004181 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004182}
4183
4184void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004185 LocationSummary* locations =
4186 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004187 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004188 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004189 if (instruction->HasUses()) {
4190 locations->SetOut(Location::SameAsFirstInput());
4191 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004192}
4193
4194void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4195 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004196 Location index_loc = locations->InAt(0);
4197 Location length_loc = locations->InAt(1);
4198 SlowPathCodeX86_64* slow_path =
4199 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004200
Mark Mendell99dbd682015-04-22 16:18:52 -04004201 if (length_loc.IsConstant()) {
4202 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4203 if (index_loc.IsConstant()) {
4204 // BCE will remove the bounds check if we are guarenteed to pass.
4205 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4206 if (index < 0 || index >= length) {
4207 codegen_->AddSlowPath(slow_path);
4208 __ jmp(slow_path->GetEntryLabel());
4209 } else {
4210 // Some optimization after BCE may have generated this, and we should not
4211 // generate a bounds check if it is a valid range.
4212 }
4213 return;
4214 }
4215
4216 // We have to reverse the jump condition because the length is the constant.
4217 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4218 __ cmpl(index_reg, Immediate(length));
4219 codegen_->AddSlowPath(slow_path);
4220 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004221 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004222 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4223 if (index_loc.IsConstant()) {
4224 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4225 __ cmpl(length, Immediate(value));
4226 } else {
4227 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4228 }
4229 codegen_->AddSlowPath(slow_path);
4230 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004231 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004232}
4233
4234void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4235 CpuRegister card,
4236 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004237 CpuRegister value,
4238 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004239 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004240 if (value_can_be_null) {
4241 __ testl(value, value);
4242 __ j(kEqual, &is_null);
4243 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004244 __ gs()->movq(card, Address::Absolute(
4245 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4246 __ movq(temp, object);
4247 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004248 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004249 if (value_can_be_null) {
4250 __ Bind(&is_null);
4251 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004252}
4253
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004254void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4255 temp->SetLocations(nullptr);
4256}
4257
4258void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4259 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004260 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004261}
4262
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004263void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004264 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004265 LOG(FATAL) << "Unimplemented";
4266}
4267
4268void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004269 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4270}
4271
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004272void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4273 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4274}
4275
4276void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004277 HBasicBlock* block = instruction->GetBlock();
4278 if (block->GetLoopInformation() != nullptr) {
4279 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4280 // The back edge will generate the suspend check.
4281 return;
4282 }
4283 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4284 // The goto will generate the suspend check.
4285 return;
4286 }
4287 GenerateSuspendCheck(instruction, nullptr);
4288}
4289
4290void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4291 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004292 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004293 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4294 if (slow_path == nullptr) {
4295 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4296 instruction->SetSlowPath(slow_path);
4297 codegen_->AddSlowPath(slow_path);
4298 if (successor != nullptr) {
4299 DCHECK(successor->IsLoopHeader());
4300 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4301 }
4302 } else {
4303 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4304 }
4305
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004306 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004307 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004308 if (successor == nullptr) {
4309 __ j(kNotEqual, slow_path->GetEntryLabel());
4310 __ Bind(slow_path->GetReturnLabel());
4311 } else {
4312 __ j(kEqual, codegen_->GetLabelOf(successor));
4313 __ jmp(slow_path->GetEntryLabel());
4314 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004315}
4316
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004317X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4318 return codegen_->GetAssembler();
4319}
4320
4321void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4322 MoveOperands* move = moves_.Get(index);
4323 Location source = move->GetSource();
4324 Location destination = move->GetDestination();
4325
4326 if (source.IsRegister()) {
4327 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004328 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004329 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004330 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004331 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004332 } else {
4333 DCHECK(destination.IsDoubleStackSlot());
4334 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004335 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004336 }
4337 } else if (source.IsStackSlot()) {
4338 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004339 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004340 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004341 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004342 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004343 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004344 } else {
4345 DCHECK(destination.IsStackSlot());
4346 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4347 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4348 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004349 } else if (source.IsDoubleStackSlot()) {
4350 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004351 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004352 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004353 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004354 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4355 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004356 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004357 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004358 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4359 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4360 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004361 } else if (source.IsConstant()) {
4362 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004363 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4364 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004365 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004366 if (value == 0) {
4367 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4368 } else {
4369 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4370 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004371 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004372 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004373 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004374 }
4375 } else if (constant->IsLongConstant()) {
4376 int64_t value = constant->AsLongConstant()->GetValue();
4377 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004378 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004379 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004380 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004381 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004382 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004383 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004384 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004385 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004386 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004387 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4388 if (value == 0) {
4389 // easy FP 0.0.
4390 __ xorps(dest, dest);
4391 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004392 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004393 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004394 } else {
4395 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004396 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004397 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4398 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004399 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004400 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004401 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004402 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004403 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004404 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4405 if (value == 0) {
4406 __ xorpd(dest, dest);
4407 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004408 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004409 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004410 } else {
4411 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004412 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004413 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004414 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004415 } else if (source.IsFpuRegister()) {
4416 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004417 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004418 } else if (destination.IsStackSlot()) {
4419 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004420 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004421 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004422 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004423 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004424 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004425 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004426 }
4427}
4428
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004429void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004430 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004431 __ movl(Address(CpuRegister(RSP), mem), reg);
4432 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004433}
4434
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004435void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004436 ScratchRegisterScope ensure_scratch(
4437 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4438
4439 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4440 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4441 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4442 Address(CpuRegister(RSP), mem2 + stack_offset));
4443 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4444 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4445 CpuRegister(ensure_scratch.GetRegister()));
4446}
4447
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004448void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4449 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4450 __ movq(Address(CpuRegister(RSP), mem), reg);
4451 __ movq(reg, CpuRegister(TMP));
4452}
4453
4454void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4455 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004456 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004457
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004458 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4459 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4460 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4461 Address(CpuRegister(RSP), mem2 + stack_offset));
4462 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4463 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4464 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004465}
4466
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004467void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4468 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4469 __ movss(Address(CpuRegister(RSP), mem), reg);
4470 __ movd(reg, CpuRegister(TMP));
4471}
4472
4473void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4474 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4475 __ movsd(Address(CpuRegister(RSP), mem), reg);
4476 __ movd(reg, CpuRegister(TMP));
4477}
4478
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004479void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4480 MoveOperands* move = moves_.Get(index);
4481 Location source = move->GetSource();
4482 Location destination = move->GetDestination();
4483
4484 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004485 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004486 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004487 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004488 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004489 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004490 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004491 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4492 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004493 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004494 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004495 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004496 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4497 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004498 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004499 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4500 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4501 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004502 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004503 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004504 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004505 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004506 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004507 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004508 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004509 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004510 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004511 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004512 }
4513}
4514
4515
4516void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4517 __ pushq(CpuRegister(reg));
4518}
4519
4520
4521void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4522 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004523}
4524
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004525void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4526 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4527 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4528 Immediate(mirror::Class::kStatusInitialized));
4529 __ j(kLess, slow_path->GetEntryLabel());
4530 __ Bind(slow_path->GetExitLabel());
4531 // No need for memory fence, thanks to the X86_64 memory model.
4532}
4533
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004534void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004535 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4536 ? LocationSummary::kCallOnSlowPath
4537 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004538 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004539 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004540 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004541 locations->SetOut(Location::RequiresRegister());
4542}
4543
4544void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004545 LocationSummary* locations = cls->GetLocations();
4546 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4547 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004548 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004549 DCHECK(!cls->CanCallRuntime());
4550 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004551 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004552 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004553 DCHECK(cls->CanCallRuntime());
Vladimir Marko05792b92015-08-03 11:56:49 +01004554 __ movq(out, Address(
4555 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004556 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004557 // TODO: We will need a read barrier here.
Roland Levillain4d027112015-07-01 15:41:14 +01004558
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004559 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4560 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4561 codegen_->AddSlowPath(slow_path);
4562 __ testl(out, out);
4563 __ j(kEqual, slow_path->GetEntryLabel());
4564 if (cls->MustGenerateClinitCheck()) {
4565 GenerateClassInitializationCheck(slow_path, out);
4566 } else {
4567 __ Bind(slow_path->GetExitLabel());
4568 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004569 }
4570}
4571
4572void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4573 LocationSummary* locations =
4574 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4575 locations->SetInAt(0, Location::RequiresRegister());
4576 if (check->HasUses()) {
4577 locations->SetOut(Location::SameAsFirstInput());
4578 }
4579}
4580
4581void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004582 // We assume the class to not be null.
4583 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4584 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004585 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004586 GenerateClassInitializationCheck(slow_path,
4587 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004588}
4589
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004590void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4591 LocationSummary* locations =
4592 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004593 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004594 locations->SetOut(Location::RequiresRegister());
4595}
4596
4597void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4598 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4599 codegen_->AddSlowPath(slow_path);
4600
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004601 LocationSummary* locations = load->GetLocations();
4602 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4603 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004604 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004605 __ movq(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004606 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004607 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004608 __ testl(out, out);
4609 __ j(kEqual, slow_path->GetEntryLabel());
4610 __ Bind(slow_path->GetExitLabel());
4611}
4612
David Brazdilcb1c0552015-08-04 16:22:25 +01004613static Address GetExceptionTlsAddress() {
4614 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4615}
4616
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004617void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4618 LocationSummary* locations =
4619 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4620 locations->SetOut(Location::RequiresRegister());
4621}
4622
4623void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004624 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4625}
4626
4627void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4628 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4629}
4630
4631void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4632 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004633}
4634
4635void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4636 LocationSummary* locations =
4637 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4638 InvokeRuntimeCallingConvention calling_convention;
4639 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4640}
4641
4642void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004643 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4644 instruction,
4645 instruction->GetDexPc(),
4646 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004647}
4648
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004649void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004650 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4651 ? LocationSummary::kNoCall
4652 : LocationSummary::kCallOnSlowPath;
4653 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4654 locations->SetInAt(0, Location::RequiresRegister());
4655 locations->SetInAt(1, Location::Any());
4656 locations->SetOut(Location::RequiresRegister());
4657}
4658
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004659void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004660 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004661 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004662 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004663 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004664 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4665 Label done, zero;
4666 SlowPathCodeX86_64* slow_path = nullptr;
4667
4668 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004669 // Avoid null check if we know obj is not null.
4670 if (instruction->MustDoNullCheck()) {
4671 __ testl(obj, obj);
4672 __ j(kEqual, &zero);
4673 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004674 // Compare the class of `obj` with `cls`.
4675 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004676 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004677 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004678 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004679 } else {
4680 DCHECK(cls.IsStackSlot()) << cls;
4681 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4682 }
4683 if (instruction->IsClassFinal()) {
4684 // Classes must be equal for the instanceof to succeed.
4685 __ j(kNotEqual, &zero);
4686 __ movl(out, Immediate(1));
4687 __ jmp(&done);
4688 } else {
4689 // If the classes are not equal, we go into a slow path.
4690 DCHECK(locations->OnlyCallsOnSlowPath());
4691 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004692 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004693 codegen_->AddSlowPath(slow_path);
4694 __ j(kNotEqual, slow_path->GetEntryLabel());
4695 __ movl(out, Immediate(1));
4696 __ jmp(&done);
4697 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004698
4699 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4700 __ Bind(&zero);
4701 __ movl(out, Immediate(0));
4702 }
4703
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004704 if (slow_path != nullptr) {
4705 __ Bind(slow_path->GetExitLabel());
4706 }
4707 __ Bind(&done);
4708}
4709
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004710void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4711 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4712 instruction, LocationSummary::kCallOnSlowPath);
4713 locations->SetInAt(0, Location::RequiresRegister());
4714 locations->SetInAt(1, Location::Any());
4715 locations->AddTemp(Location::RequiresRegister());
4716}
4717
4718void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4719 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004720 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004721 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004722 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004723 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4724 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4725 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4726 codegen_->AddSlowPath(slow_path);
4727
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004728 // Avoid null check if we know obj is not null.
4729 if (instruction->MustDoNullCheck()) {
4730 __ testl(obj, obj);
4731 __ j(kEqual, slow_path->GetExitLabel());
4732 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004733 // Compare the class of `obj` with `cls`.
4734 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004735 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004736 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004737 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004738 } else {
4739 DCHECK(cls.IsStackSlot()) << cls;
4740 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4741 }
Roland Levillain4d027112015-07-01 15:41:14 +01004742 // The checkcast succeeds if the classes are equal (fast path).
4743 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004744 __ j(kNotEqual, slow_path->GetEntryLabel());
4745 __ Bind(slow_path->GetExitLabel());
4746}
4747
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004748void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4749 LocationSummary* locations =
4750 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4751 InvokeRuntimeCallingConvention calling_convention;
4752 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4753}
4754
4755void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004756 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
4757 : QUICK_ENTRY_POINT(pUnlockObject),
4758 instruction,
4759 instruction->GetDexPc(),
4760 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004761}
4762
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004763void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4764void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4765void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4766
4767void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4768 LocationSummary* locations =
4769 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4770 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4771 || instruction->GetResultType() == Primitive::kPrimLong);
4772 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004773 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004774 locations->SetOut(Location::SameAsFirstInput());
4775}
4776
4777void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4778 HandleBitwiseOperation(instruction);
4779}
4780
4781void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4782 HandleBitwiseOperation(instruction);
4783}
4784
4785void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4786 HandleBitwiseOperation(instruction);
4787}
4788
4789void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4790 LocationSummary* locations = instruction->GetLocations();
4791 Location first = locations->InAt(0);
4792 Location second = locations->InAt(1);
4793 DCHECK(first.Equals(locations->Out()));
4794
4795 if (instruction->GetResultType() == Primitive::kPrimInt) {
4796 if (second.IsRegister()) {
4797 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004798 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004799 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004800 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004801 } else {
4802 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004803 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004804 }
4805 } else if (second.IsConstant()) {
4806 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4807 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004808 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004809 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004810 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004811 } else {
4812 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004813 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004814 }
4815 } else {
4816 Address address(CpuRegister(RSP), second.GetStackIndex());
4817 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004818 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004819 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004820 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004821 } else {
4822 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004823 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004824 }
4825 }
4826 } else {
4827 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004828 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4829 bool second_is_constant = false;
4830 int64_t value = 0;
4831 if (second.IsConstant()) {
4832 second_is_constant = true;
4833 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004834 }
Mark Mendell40741f32015-04-20 22:10:34 -04004835 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004836
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004837 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004838 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004839 if (is_int32_value) {
4840 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4841 } else {
4842 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4843 }
4844 } else if (second.IsDoubleStackSlot()) {
4845 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004846 } else {
4847 __ andq(first_reg, second.AsRegister<CpuRegister>());
4848 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004849 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004850 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004851 if (is_int32_value) {
4852 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4853 } else {
4854 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4855 }
4856 } else if (second.IsDoubleStackSlot()) {
4857 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004858 } else {
4859 __ orq(first_reg, second.AsRegister<CpuRegister>());
4860 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004861 } else {
4862 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004863 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004864 if (is_int32_value) {
4865 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4866 } else {
4867 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4868 }
4869 } else if (second.IsDoubleStackSlot()) {
4870 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004871 } else {
4872 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4873 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004874 }
4875 }
4876}
4877
Calin Juravleb1498f62015-02-16 13:13:29 +00004878void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4879 // Nothing to do, this should be removed during prepare for register allocator.
4880 UNUSED(instruction);
4881 LOG(FATAL) << "Unreachable";
4882}
4883
4884void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4885 // Nothing to do, this should be removed during prepare for register allocator.
4886 UNUSED(instruction);
4887 LOG(FATAL) << "Unreachable";
4888}
4889
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004890void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
4891 DCHECK(codegen_->IsBaseline());
4892 LocationSummary* locations =
4893 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4894 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4895}
4896
4897void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4898 DCHECK(codegen_->IsBaseline());
4899 // Will be generated at use site.
4900}
4901
Mark Mendell92e83bf2015-05-07 11:25:03 -04004902void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4903 if (value == 0) {
4904 __ xorl(dest, dest);
4905 } else if (value > 0 && IsInt<32>(value)) {
4906 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4907 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4908 } else {
4909 __ movq(dest, Immediate(value));
4910 }
4911}
4912
Mark Mendellcfa410b2015-05-25 16:02:44 -04004913void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
4914 DCHECK(dest.IsDoubleStackSlot());
4915 if (IsInt<32>(value)) {
4916 // Can move directly as an int32 constant.
4917 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
4918 Immediate(static_cast<int32_t>(value)));
4919 } else {
4920 Load64BitValue(CpuRegister(TMP), value);
4921 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
4922 }
4923}
4924
Mark Mendellf55c3e02015-03-26 21:07:46 -04004925void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4926 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004927 X86_64Assembler* assembler = GetAssembler();
4928 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004929 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4930 // byte values. If used for vectors at a later time, this will need to be
4931 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004932 assembler->Align(4, 0);
4933 constant_area_start_ = assembler->CodeSize();
4934 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004935 }
4936
4937 // And finish up.
4938 CodeGenerator::Finalize(allocator);
4939}
4940
4941/**
4942 * Class to handle late fixup of offsets into constant area.
4943 */
4944class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4945 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004946 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004947 : codegen_(codegen), offset_into_constant_area_(offset) {}
4948
4949 private:
4950 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4951 // Patch the correct offset for the instruction. We use the address of the
4952 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4953 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4954 int relative_position = constant_offset - pos;
4955
4956 // Patch in the right value.
4957 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4958 }
4959
Mark Mendell39dcf552015-04-09 20:42:42 -04004960 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004961
4962 // Location in constant area that the fixup refers to.
4963 int offset_into_constant_area_;
4964};
4965
4966Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4967 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4968 return Address::RIP(fixup);
4969}
4970
4971Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4972 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4973 return Address::RIP(fixup);
4974}
4975
4976Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4977 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4978 return Address::RIP(fixup);
4979}
4980
4981Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4982 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4983 return Address::RIP(fixup);
4984}
4985
Roland Levillain4d027112015-07-01 15:41:14 +01004986#undef __
4987
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004988} // namespace x86_64
4989} // namespace art