blob: 0ea95e846041c63d112f89132e33a6dc602501e5 [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_;
453 __ movl(reg, Address(CpuRegister(method_reg),
454 ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
455 // temp = temp[index_in_cache]
456 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
457 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
458 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +0100459 }
Vladimir Marko58155012015-08-19 12:49:41 +0000460 }
461
462 switch (invoke->GetCodePtrLocation()) {
463 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
464 __ call(&frame_entry_label_);
465 break;
466 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
467 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
468 Label* label = &relative_call_patches_.back().label;
469 __ call(label); // Bind to the patch label, override at link time.
470 __ Bind(label); // Bind the label at the end of the "call" insn.
471 break;
472 }
473 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
474 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
475 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
476 FALLTHROUGH_INTENDED;
477 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
478 // (callee_method + offset_of_quick_compiled_code)()
479 __ call(Address(callee_method.AsRegister<CpuRegister>(),
480 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
481 kX86_64WordSize).SizeValue()));
482 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000483 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800484
485 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800486}
487
Vladimir Marko58155012015-08-19 12:49:41 +0000488void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
489 DCHECK(linker_patches->empty());
490 size_t size =
491 method_patches_.size() + relative_call_patches_.size() + pc_rel_dex_cache_patches_.size();
492 linker_patches->reserve(size);
493 for (const MethodPatchInfo<Label>& info : method_patches_) {
494 // The label points to the end of the "movl" instruction but the literal offset for method
495 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
496 uint32_t literal_offset = info.label.Position() - 4;
497 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
498 info.target_method.dex_file,
499 info.target_method.dex_method_index));
500 }
501 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
502 // The label points to the end of the "call" instruction but the literal offset for method
503 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
504 uint32_t literal_offset = info.label.Position() - 4;
505 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
506 info.target_method.dex_file,
507 info.target_method.dex_method_index));
508 }
509 for (const PcRelativeDexCacheAccessInfo& info : pc_rel_dex_cache_patches_) {
510 // The label points to the end of the "mov" instruction but the literal offset for method
511 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
512 uint32_t literal_offset = info.label.Position() - 4;
513 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
514 &info.target_dex_file,
515 info.label.Position(),
516 info.element_offset));
517 }
518}
519
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100520void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100521 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100522}
523
524void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100525 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100526}
527
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100528size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
529 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
530 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100531}
532
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100533size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
534 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
535 return kX86_64WordSize;
536}
537
538size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
539 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
540 return kX86_64WordSize;
541}
542
543size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
544 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
545 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100546}
547
Alexandre Rames8158f282015-08-07 10:26:17 +0100548void CodeGeneratorX86_64::InvokeRuntime(Address entry_point,
549 HInstruction* instruction,
550 uint32_t dex_pc,
551 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100552 ValidateInvokeRuntime(instruction, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100553 __ gs()->call(entry_point);
554 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100555}
556
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000557static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000558// Use a fake return address register to mimic Quick.
559static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400560CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
561 const X86_64InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100562 const CompilerOptions& compiler_options,
563 OptimizingCompilerStats* stats)
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)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100573 compiler_options,
574 stats),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100575 block_labels_(graph->GetArena(), 0),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100576 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000577 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400578 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400579 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000580 constant_area_start_(0),
581 method_patches_(graph->GetArena()->Adapter()),
582 relative_call_patches_(graph->GetArena()->Adapter()),
583 pc_rel_dex_cache_patches_(graph->GetArena()->Adapter()) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000584 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
585}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100586
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100587InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
588 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100589 : HGraphVisitor(graph),
590 assembler_(codegen->GetAssembler()),
591 codegen_(codegen) {}
592
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100593Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100594 switch (type) {
595 case Primitive::kPrimLong:
596 case Primitive::kPrimByte:
597 case Primitive::kPrimBoolean:
598 case Primitive::kPrimChar:
599 case Primitive::kPrimShort:
600 case Primitive::kPrimInt:
601 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100602 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100603 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100604 }
605
606 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100607 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100608 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100609 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100610 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100611
612 case Primitive::kPrimVoid:
613 LOG(FATAL) << "Unreachable type " << type;
614 }
615
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100616 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100617}
618
Nicolas Geoffray98893962015-01-21 12:32:32 +0000619void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100620 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100621 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100622
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000623 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100624 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000625
Nicolas Geoffray98893962015-01-21 12:32:32 +0000626 if (is_baseline) {
627 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
628 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
629 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000630 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
631 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
632 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000633 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100634}
635
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100636static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100637 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100638}
David Srbecky9d8606d2015-04-12 09:35:32 +0100639
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100640static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100641 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100642}
643
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100644void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100645 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000646 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100647 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700648 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000649 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100650
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000651 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100652 __ testq(CpuRegister(RAX), Address(
653 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100654 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100655 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000656
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000657 if (HasEmptyFrame()) {
658 return;
659 }
660
Nicolas Geoffray98893962015-01-21 12:32:32 +0000661 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000662 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000663 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000664 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100665 __ cfi().AdjustCFAOffset(kX86_64WordSize);
666 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000667 }
668 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100669
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100670 int adjust = GetFrameSize() - GetCoreSpillSize();
671 __ subq(CpuRegister(RSP), Immediate(adjust));
672 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000673 uint32_t xmm_spill_location = GetFpuSpillStart();
674 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100675
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000676 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
677 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100678 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
679 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
680 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000681 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100682 }
683
Mathieu Chartiere401d142015-04-22 13:56:20 -0700684 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100685 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100686}
687
688void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100689 __ cfi().RememberState();
690 if (!HasEmptyFrame()) {
691 uint32_t xmm_spill_location = GetFpuSpillStart();
692 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
693 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
694 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
695 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
696 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
697 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
698 }
699 }
700
701 int adjust = GetFrameSize() - GetCoreSpillSize();
702 __ addq(CpuRegister(RSP), Immediate(adjust));
703 __ cfi().AdjustCFAOffset(-adjust);
704
705 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
706 Register reg = kCoreCalleeSaves[i];
707 if (allocated_registers_.ContainsCoreRegister(reg)) {
708 __ popq(CpuRegister(reg));
709 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
710 __ cfi().Restore(DWARFReg(reg));
711 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000712 }
713 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100714 __ ret();
715 __ cfi().RestoreState();
716 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100717}
718
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100719void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
720 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100721}
722
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100723Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
724 switch (load->GetType()) {
725 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100726 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100727 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100728
729 case Primitive::kPrimInt:
730 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100731 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100732 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100733
734 case Primitive::kPrimBoolean:
735 case Primitive::kPrimByte:
736 case Primitive::kPrimChar:
737 case Primitive::kPrimShort:
738 case Primitive::kPrimVoid:
739 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700740 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100741 }
742
743 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700744 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100745}
746
747void CodeGeneratorX86_64::Move(Location destination, Location source) {
748 if (source.Equals(destination)) {
749 return;
750 }
751 if (destination.IsRegister()) {
752 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000753 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100754 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000755 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100756 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000757 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100758 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100759 } else {
760 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000761 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100762 Address(CpuRegister(RSP), source.GetStackIndex()));
763 }
764 } else if (destination.IsFpuRegister()) {
765 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000766 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100767 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000768 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100769 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000770 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100771 Address(CpuRegister(RSP), source.GetStackIndex()));
772 } else {
773 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000774 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100775 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100776 }
777 } else if (destination.IsStackSlot()) {
778 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100779 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000780 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100781 } else if (source.IsFpuRegister()) {
782 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000783 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500784 } else if (source.IsConstant()) {
785 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000786 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500787 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100788 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500789 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000790 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
791 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100792 }
793 } else {
794 DCHECK(destination.IsDoubleStackSlot());
795 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100796 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000797 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100798 } else if (source.IsFpuRegister()) {
799 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000800 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500801 } else if (source.IsConstant()) {
802 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800803 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500804 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000805 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500806 } else {
807 DCHECK(constant->IsLongConstant());
808 value = constant->AsLongConstant()->GetValue();
809 }
Mark Mendellcfa410b2015-05-25 16:02:44 -0400810 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100811 } else {
812 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000813 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
814 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100815 }
816 }
817}
818
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100819void CodeGeneratorX86_64::Move(HInstruction* instruction,
820 Location location,
821 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000822 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100823 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700824 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100825 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000826 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100827 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000828 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000829 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
830 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000831 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000832 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000833 } else if (location.IsStackSlot()) {
834 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
835 } else {
836 DCHECK(location.IsConstant());
837 DCHECK_EQ(location.GetConstant(), const_to_move);
838 }
839 } else if (const_to_move->IsLongConstant()) {
840 int64_t value = const_to_move->AsLongConstant()->GetValue();
841 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400842 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000843 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400844 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000845 } else {
846 DCHECK(location.IsConstant());
847 DCHECK_EQ(location.GetConstant(), const_to_move);
848 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100849 }
Roland Levillain476df552014-10-09 17:51:36 +0100850 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100851 switch (instruction->GetType()) {
852 case Primitive::kPrimBoolean:
853 case Primitive::kPrimByte:
854 case Primitive::kPrimChar:
855 case Primitive::kPrimShort:
856 case Primitive::kPrimInt:
857 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100858 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100859 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
860 break;
861
862 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100863 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000864 Move(location,
865 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100866 break;
867
868 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100869 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100870 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000871 } else if (instruction->IsTemporary()) {
872 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
873 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100874 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100875 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100876 switch (instruction->GetType()) {
877 case Primitive::kPrimBoolean:
878 case Primitive::kPrimByte:
879 case Primitive::kPrimChar:
880 case Primitive::kPrimShort:
881 case Primitive::kPrimInt:
882 case Primitive::kPrimNot:
883 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100884 case Primitive::kPrimFloat:
885 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000886 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887 break;
888
889 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100890 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100891 }
892 }
893}
894
David Brazdilfc6a86a2015-06-26 10:33:45 +0000895void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100896 DCHECK(!successor->IsExitBlock());
897
898 HBasicBlock* block = got->GetBlock();
899 HInstruction* previous = got->GetPrevious();
900
901 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000902 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100903 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
904 return;
905 }
906
907 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
908 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
909 }
910 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100911 __ jmp(codegen_->GetLabelOf(successor));
912 }
913}
914
David Brazdilfc6a86a2015-06-26 10:33:45 +0000915void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
916 got->SetLocations(nullptr);
917}
918
919void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
920 HandleGoto(got, got->GetSuccessor());
921}
922
923void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
924 try_boundary->SetLocations(nullptr);
925}
926
927void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
928 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
929 if (!successor->IsExitBlock()) {
930 HandleGoto(try_boundary, successor);
931 }
932}
933
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100934void LocationsBuilderX86_64::VisitExit(HExit* exit) {
935 exit->SetLocations(nullptr);
936}
937
938void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700939 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940}
941
Mark Mendellc4701932015-04-10 13:18:51 -0400942void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
943 Label* true_label,
944 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100945 if (cond->IsFPConditionTrueIfNaN()) {
946 __ j(kUnordered, true_label);
947 } else if (cond->IsFPConditionFalseIfNaN()) {
948 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400949 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100950 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400951}
952
953void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
954 HCondition* condition,
955 Label* true_target,
956 Label* false_target,
957 Label* always_true_target) {
958 LocationSummary* locations = condition->GetLocations();
959 Location left = locations->InAt(0);
960 Location right = locations->InAt(1);
961
962 // We don't want true_target as a nullptr.
963 if (true_target == nullptr) {
964 true_target = always_true_target;
965 }
966 bool falls_through = (false_target == nullptr);
967
968 // FP compares don't like null false_targets.
969 if (false_target == nullptr) {
970 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
971 }
972
973 Primitive::Type type = condition->InputAt(0)->GetType();
974 switch (type) {
975 case Primitive::kPrimLong: {
976 CpuRegister left_reg = left.AsRegister<CpuRegister>();
977 if (right.IsConstant()) {
978 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
979 if (IsInt<32>(value)) {
980 if (value == 0) {
981 __ testq(left_reg, left_reg);
982 } else {
983 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
984 }
985 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100986 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -0400987 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
988 }
989 } else if (right.IsDoubleStackSlot()) {
990 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
991 } else {
992 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
993 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100994 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -0400995 break;
996 }
997 case Primitive::kPrimFloat: {
998 if (right.IsFpuRegister()) {
999 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1000 } else if (right.IsConstant()) {
1001 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1002 codegen_->LiteralFloatAddress(
1003 right.GetConstant()->AsFloatConstant()->GetValue()));
1004 } else {
1005 DCHECK(right.IsStackSlot());
1006 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1007 Address(CpuRegister(RSP), right.GetStackIndex()));
1008 }
1009 GenerateFPJumps(condition, true_target, false_target);
1010 break;
1011 }
1012 case Primitive::kPrimDouble: {
1013 if (right.IsFpuRegister()) {
1014 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1015 } else if (right.IsConstant()) {
1016 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1017 codegen_->LiteralDoubleAddress(
1018 right.GetConstant()->AsDoubleConstant()->GetValue()));
1019 } else {
1020 DCHECK(right.IsDoubleStackSlot());
1021 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1022 Address(CpuRegister(RSP), right.GetStackIndex()));
1023 }
1024 GenerateFPJumps(condition, true_target, false_target);
1025 break;
1026 }
1027 default:
1028 LOG(FATAL) << "Unexpected condition type " << type;
1029 }
1030
1031 if (!falls_through) {
1032 __ jmp(false_target);
1033 }
1034}
1035
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001036void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
1037 Label* true_target,
1038 Label* false_target,
1039 Label* always_true_target) {
1040 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001041 if (cond->IsIntConstant()) {
1042 // Constant condition, statically compared against 1.
1043 int32_t cond_value = cond->AsIntConstant()->GetValue();
1044 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001045 if (always_true_target != nullptr) {
1046 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001047 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001048 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001049 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001050 DCHECK_EQ(cond_value, 0);
1051 }
1052 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001053 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001054 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1055 // Moves do not affect the eflags register, so if the condition is
1056 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001057 // again. We can't use the eflags on FP conditions if they are
1058 // materialized due to the complex branching.
1059 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001060 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001061 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
1062 && !Primitive::IsFloatingPointType(type);
1063
Roland Levillain4fa13f62015-07-06 18:11:54 +01001064 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001065 if (!eflags_set) {
1066 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001067 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001068 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001069 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001070 } else {
1071 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
1072 Immediate(0));
1073 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001074 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001075 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001076 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001077 }
1078 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001079 // Condition has not been materialized, use its inputs as the
1080 // comparison and its condition as the branch condition.
1081
Mark Mendellc4701932015-04-10 13:18:51 -04001082 // Is this a long or FP comparison that has been folded into the HCondition?
1083 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001084 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -04001085 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1086 true_target, false_target, always_true_target);
1087 return;
1088 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001089
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001090 Location lhs = cond->GetLocations()->InAt(0);
1091 Location rhs = cond->GetLocations()->InAt(1);
1092 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001093 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001094 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001095 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001096 if (constant == 0) {
1097 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1098 } else {
1099 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1100 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001101 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001103 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1104 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001105 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001106 }
Dave Allison20dfc792014-06-16 20:44:29 -07001107 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001108 if (false_target != nullptr) {
1109 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001110 }
1111}
1112
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001113void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1114 LocationSummary* locations =
1115 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1116 HInstruction* cond = if_instr->InputAt(0);
1117 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1118 locations->SetInAt(0, Location::Any());
1119 }
1120}
1121
1122void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1123 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1124 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1125 Label* always_true_target = true_target;
1126 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1127 if_instr->IfTrueSuccessor())) {
1128 always_true_target = nullptr;
1129 }
1130 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1131 if_instr->IfFalseSuccessor())) {
1132 false_target = nullptr;
1133 }
1134 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1135}
1136
1137void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1138 LocationSummary* locations = new (GetGraph()->GetArena())
1139 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1140 HInstruction* cond = deoptimize->InputAt(0);
1141 DCHECK(cond->IsCondition());
1142 if (cond->AsCondition()->NeedsMaterialization()) {
1143 locations->SetInAt(0, Location::Any());
1144 }
1145}
1146
1147void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1148 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena())
1149 DeoptimizationSlowPathX86_64(deoptimize);
1150 codegen_->AddSlowPath(slow_path);
1151 Label* slow_path_entry = slow_path->GetEntryLabel();
1152 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1153}
1154
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001155void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1156 local->SetLocations(nullptr);
1157}
1158
1159void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1160 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1161}
1162
1163void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1164 local->SetLocations(nullptr);
1165}
1166
1167void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
1168 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001169 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001170}
1171
1172void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001173 LocationSummary* locations =
1174 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001175 switch (store->InputAt(1)->GetType()) {
1176 case Primitive::kPrimBoolean:
1177 case Primitive::kPrimByte:
1178 case Primitive::kPrimChar:
1179 case Primitive::kPrimShort:
1180 case Primitive::kPrimInt:
1181 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001182 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001183 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1184 break;
1185
1186 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001187 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001188 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1189 break;
1190
1191 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001192 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001193 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001194}
1195
1196void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001197 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001198}
1199
Roland Levillain0d37cd02015-05-27 16:39:19 +01001200void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001201 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001202 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001203 // Handle the long/FP comparisons made in instruction simplification.
1204 switch (cond->InputAt(0)->GetType()) {
1205 case Primitive::kPrimLong:
1206 locations->SetInAt(0, Location::RequiresRegister());
1207 locations->SetInAt(1, Location::Any());
1208 break;
1209 case Primitive::kPrimFloat:
1210 case Primitive::kPrimDouble:
1211 locations->SetInAt(0, Location::RequiresFpuRegister());
1212 locations->SetInAt(1, Location::Any());
1213 break;
1214 default:
1215 locations->SetInAt(0, Location::RequiresRegister());
1216 locations->SetInAt(1, Location::Any());
1217 break;
1218 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001219 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001220 locations->SetOut(Location::RequiresRegister());
1221 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001222}
1223
Roland Levillain0d37cd02015-05-27 16:39:19 +01001224void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001225 if (!cond->NeedsMaterialization()) {
1226 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001227 }
Mark Mendellc4701932015-04-10 13:18:51 -04001228
1229 LocationSummary* locations = cond->GetLocations();
1230 Location lhs = locations->InAt(0);
1231 Location rhs = locations->InAt(1);
1232 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1233 Label true_label, false_label;
1234
1235 switch (cond->InputAt(0)->GetType()) {
1236 default:
1237 // Integer case.
1238
1239 // Clear output register: setcc only sets the low byte.
1240 __ xorl(reg, reg);
1241
1242 if (rhs.IsRegister()) {
1243 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1244 } else if (rhs.IsConstant()) {
1245 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1246 if (constant == 0) {
1247 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1248 } else {
1249 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1250 }
1251 } else {
1252 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1253 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001254 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001255 return;
1256 case Primitive::kPrimLong:
1257 // Clear output register: setcc only sets the low byte.
1258 __ xorl(reg, reg);
1259
1260 if (rhs.IsRegister()) {
1261 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1262 } else if (rhs.IsConstant()) {
1263 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1264 if (IsInt<32>(value)) {
1265 if (value == 0) {
1266 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1267 } else {
1268 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1269 }
1270 } else {
1271 // Value won't fit in an int.
1272 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1273 }
1274 } else {
1275 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1276 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001277 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001278 return;
1279 case Primitive::kPrimFloat: {
1280 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1281 if (rhs.IsConstant()) {
1282 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1283 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1284 } else if (rhs.IsStackSlot()) {
1285 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1286 } else {
1287 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1288 }
1289 GenerateFPJumps(cond, &true_label, &false_label);
1290 break;
1291 }
1292 case Primitive::kPrimDouble: {
1293 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1294 if (rhs.IsConstant()) {
1295 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1296 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1297 } else if (rhs.IsDoubleStackSlot()) {
1298 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1299 } else {
1300 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1301 }
1302 GenerateFPJumps(cond, &true_label, &false_label);
1303 break;
1304 }
1305 }
1306
1307 // Convert the jumps into the result.
1308 Label done_label;
1309
Roland Levillain4fa13f62015-07-06 18:11:54 +01001310 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001311 __ Bind(&false_label);
1312 __ xorl(reg, reg);
1313 __ jmp(&done_label);
1314
Roland Levillain4fa13f62015-07-06 18:11:54 +01001315 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001316 __ Bind(&true_label);
1317 __ movl(reg, Immediate(1));
1318 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001319}
1320
1321void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1322 VisitCondition(comp);
1323}
1324
1325void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1326 VisitCondition(comp);
1327}
1328
1329void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1330 VisitCondition(comp);
1331}
1332
1333void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1334 VisitCondition(comp);
1335}
1336
1337void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1338 VisitCondition(comp);
1339}
1340
1341void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1342 VisitCondition(comp);
1343}
1344
1345void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1346 VisitCondition(comp);
1347}
1348
1349void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1350 VisitCondition(comp);
1351}
1352
1353void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1354 VisitCondition(comp);
1355}
1356
1357void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1358 VisitCondition(comp);
1359}
1360
1361void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1362 VisitCondition(comp);
1363}
1364
1365void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1366 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001367}
1368
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001369void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001370 LocationSummary* locations =
1371 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001372 switch (compare->InputAt(0)->GetType()) {
1373 case Primitive::kPrimLong: {
1374 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001375 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001376 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1377 break;
1378 }
1379 case Primitive::kPrimFloat:
1380 case Primitive::kPrimDouble: {
1381 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001382 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001383 locations->SetOut(Location::RequiresRegister());
1384 break;
1385 }
1386 default:
1387 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1388 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001389}
1390
1391void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001392 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001393 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001394 Location left = locations->InAt(0);
1395 Location right = locations->InAt(1);
1396
1397 Label less, greater, done;
1398 Primitive::Type type = compare->InputAt(0)->GetType();
1399 switch (type) {
1400 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001401 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1402 if (right.IsConstant()) {
1403 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001404 if (IsInt<32>(value)) {
1405 if (value == 0) {
1406 __ testq(left_reg, left_reg);
1407 } else {
1408 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1409 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001410 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001411 // Value won't fit in an int.
1412 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001413 }
Mark Mendell40741f32015-04-20 22:10:34 -04001414 } else if (right.IsDoubleStackSlot()) {
1415 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001416 } else {
1417 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1418 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001419 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001420 }
1421 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001422 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1423 if (right.IsConstant()) {
1424 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1425 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1426 } else if (right.IsStackSlot()) {
1427 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1428 } else {
1429 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1430 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001431 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1432 break;
1433 }
1434 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001435 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1436 if (right.IsConstant()) {
1437 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1438 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1439 } else if (right.IsDoubleStackSlot()) {
1440 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1441 } else {
1442 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1443 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001444 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1445 break;
1446 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001447 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001448 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001449 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001450 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001451 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001452 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001453
Calin Juravle91debbc2014-11-26 19:01:09 +00001454 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001455 __ movl(out, Immediate(1));
1456 __ jmp(&done);
1457
1458 __ Bind(&less);
1459 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001460
1461 __ Bind(&done);
1462}
1463
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001464void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001465 LocationSummary* locations =
1466 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001467 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001468}
1469
1470void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001471 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001472 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001473}
1474
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001475void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1476 LocationSummary* locations =
1477 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1478 locations->SetOut(Location::ConstantLocation(constant));
1479}
1480
1481void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1482 // Will be generated at use site.
1483 UNUSED(constant);
1484}
1485
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001486void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001487 LocationSummary* locations =
1488 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001489 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001490}
1491
1492void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001493 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001494 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001495}
1496
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001497void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1498 LocationSummary* locations =
1499 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1500 locations->SetOut(Location::ConstantLocation(constant));
1501}
1502
1503void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1504 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001505 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001506}
1507
1508void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1509 LocationSummary* locations =
1510 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1511 locations->SetOut(Location::ConstantLocation(constant));
1512}
1513
1514void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1515 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001516 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001517}
1518
Calin Juravle27df7582015-04-17 19:12:31 +01001519void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1520 memory_barrier->SetLocations(nullptr);
1521}
1522
1523void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1524 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1525}
1526
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001527void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1528 ret->SetLocations(nullptr);
1529}
1530
1531void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001532 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001533 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001534}
1535
1536void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001537 LocationSummary* locations =
1538 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001539 switch (ret->InputAt(0)->GetType()) {
1540 case Primitive::kPrimBoolean:
1541 case Primitive::kPrimByte:
1542 case Primitive::kPrimChar:
1543 case Primitive::kPrimShort:
1544 case Primitive::kPrimInt:
1545 case Primitive::kPrimNot:
1546 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001547 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001548 break;
1549
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001550 case Primitive::kPrimFloat:
1551 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001552 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001553 break;
1554
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001555 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001556 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001557 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001558}
1559
1560void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1561 if (kIsDebugBuild) {
1562 switch (ret->InputAt(0)->GetType()) {
1563 case Primitive::kPrimBoolean:
1564 case Primitive::kPrimByte:
1565 case Primitive::kPrimChar:
1566 case Primitive::kPrimShort:
1567 case Primitive::kPrimInt:
1568 case Primitive::kPrimNot:
1569 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001570 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001571 break;
1572
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001573 case Primitive::kPrimFloat:
1574 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001575 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001576 XMM0);
1577 break;
1578
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001579 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001580 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001581 }
1582 }
1583 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001584}
1585
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001586Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1587 switch (type) {
1588 case Primitive::kPrimBoolean:
1589 case Primitive::kPrimByte:
1590 case Primitive::kPrimChar:
1591 case Primitive::kPrimShort:
1592 case Primitive::kPrimInt:
1593 case Primitive::kPrimNot:
1594 case Primitive::kPrimLong:
1595 return Location::RegisterLocation(RAX);
1596
1597 case Primitive::kPrimVoid:
1598 return Location::NoLocation();
1599
1600 case Primitive::kPrimDouble:
1601 case Primitive::kPrimFloat:
1602 return Location::FpuRegisterLocation(XMM0);
1603 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001604
1605 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001606}
1607
1608Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1609 return Location::RegisterLocation(kMethodRegisterArgument);
1610}
1611
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001612Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001613 switch (type) {
1614 case Primitive::kPrimBoolean:
1615 case Primitive::kPrimByte:
1616 case Primitive::kPrimChar:
1617 case Primitive::kPrimShort:
1618 case Primitive::kPrimInt:
1619 case Primitive::kPrimNot: {
1620 uint32_t index = gp_index_++;
1621 stack_index_++;
1622 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001623 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001624 } else {
1625 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1626 }
1627 }
1628
1629 case Primitive::kPrimLong: {
1630 uint32_t index = gp_index_;
1631 stack_index_ += 2;
1632 if (index < calling_convention.GetNumberOfRegisters()) {
1633 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001634 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001635 } else {
1636 gp_index_ += 2;
1637 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1638 }
1639 }
1640
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001641 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001642 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001643 stack_index_++;
1644 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001645 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001646 } else {
1647 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1648 }
1649 }
1650
1651 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001652 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001653 stack_index_ += 2;
1654 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001655 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001656 } else {
1657 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1658 }
1659 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001660
1661 case Primitive::kPrimVoid:
1662 LOG(FATAL) << "Unexpected parameter type " << type;
1663 break;
1664 }
1665 return Location();
1666}
1667
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001668void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001669 // When we do not run baseline, explicit clinit checks triggered by static
1670 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1671 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001672
Mark Mendellfb8d2792015-03-31 22:16:59 -04001673 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001674 if (intrinsic.TryDispatch(invoke)) {
1675 return;
1676 }
1677
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001678 HandleInvoke(invoke);
1679}
1680
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001681static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1682 if (invoke->GetLocations()->Intrinsified()) {
1683 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1684 intrinsic.Dispatch(invoke);
1685 return true;
1686 }
1687 return false;
1688}
1689
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001690void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001691 // When we do not run baseline, explicit clinit checks triggered by static
1692 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1693 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001694
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001695 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1696 return;
1697 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001698
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001699 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001700 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001701 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001702 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001703}
1704
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001705void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001706 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001707 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001708}
1709
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001710void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001711 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001712 if (intrinsic.TryDispatch(invoke)) {
1713 return;
1714 }
1715
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001716 HandleInvoke(invoke);
1717}
1718
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001719void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001720 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1721 return;
1722 }
1723
Roland Levillain271ab9c2014-11-27 15:23:57 +00001724 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001725 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1726 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001727 LocationSummary* locations = invoke->GetLocations();
1728 Location receiver = locations->InAt(0);
1729 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1730 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001731 DCHECK(receiver.IsRegister());
1732 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001733 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001734 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001735 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001736 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001737 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001738 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001739 kX86_64WordSize).SizeValue()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001740
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001741 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001742 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001743}
1744
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001745void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1746 HandleInvoke(invoke);
1747 // Add the hidden argument.
1748 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1749}
1750
1751void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1752 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001753 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001754 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1755 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001756 LocationSummary* locations = invoke->GetLocations();
1757 Location receiver = locations->InAt(0);
1758 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1759
1760 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001761 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1762 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001763
1764 // temp = object->GetClass();
1765 if (receiver.IsStackSlot()) {
1766 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1767 __ movl(temp, Address(temp, class_offset));
1768 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001769 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001770 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001771 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001772 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001773 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001774 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001775 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001776 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001777 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001778
1779 DCHECK(!codegen_->IsLeafMethod());
1780 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1781}
1782
Roland Levillain88cb1752014-10-20 16:36:47 +01001783void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1784 LocationSummary* locations =
1785 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1786 switch (neg->GetResultType()) {
1787 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001788 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001789 locations->SetInAt(0, Location::RequiresRegister());
1790 locations->SetOut(Location::SameAsFirstInput());
1791 break;
1792
Roland Levillain88cb1752014-10-20 16:36:47 +01001793 case Primitive::kPrimFloat:
1794 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001795 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001796 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001797 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001798 break;
1799
1800 default:
1801 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1802 }
1803}
1804
1805void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1806 LocationSummary* locations = neg->GetLocations();
1807 Location out = locations->Out();
1808 Location in = locations->InAt(0);
1809 switch (neg->GetResultType()) {
1810 case Primitive::kPrimInt:
1811 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001812 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001813 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001814 break;
1815
1816 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001817 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001818 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001819 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001820 break;
1821
Roland Levillain5368c212014-11-27 15:03:41 +00001822 case Primitive::kPrimFloat: {
1823 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001824 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001825 // Implement float negation with an exclusive or with value
1826 // 0x80000000 (mask for bit 31, representing the sign of a
1827 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001828 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001829 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001830 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001831 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001832
Roland Levillain5368c212014-11-27 15:03:41 +00001833 case Primitive::kPrimDouble: {
1834 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001835 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001836 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001837 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001838 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001839 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001840 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001841 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001842 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001843
1844 default:
1845 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1846 }
1847}
1848
Roland Levillaindff1f282014-11-05 14:15:05 +00001849void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1850 LocationSummary* locations =
1851 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1852 Primitive::Type result_type = conversion->GetResultType();
1853 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001854 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001855
David Brazdilb2bd1c52015-03-25 11:17:37 +00001856 // The Java language does not allow treating boolean as an integral type but
1857 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001858
Roland Levillaindff1f282014-11-05 14:15:05 +00001859 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001860 case Primitive::kPrimByte:
1861 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001862 case Primitive::kPrimBoolean:
1863 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001864 case Primitive::kPrimShort:
1865 case Primitive::kPrimInt:
1866 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001867 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001868 locations->SetInAt(0, Location::Any());
1869 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1870 break;
1871
1872 default:
1873 LOG(FATAL) << "Unexpected type conversion from " << input_type
1874 << " to " << result_type;
1875 }
1876 break;
1877
Roland Levillain01a8d712014-11-14 16:27:39 +00001878 case Primitive::kPrimShort:
1879 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001880 case Primitive::kPrimBoolean:
1881 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001882 case Primitive::kPrimByte:
1883 case Primitive::kPrimInt:
1884 case Primitive::kPrimChar:
1885 // Processing a Dex `int-to-short' instruction.
1886 locations->SetInAt(0, Location::Any());
1887 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1888 break;
1889
1890 default:
1891 LOG(FATAL) << "Unexpected type conversion from " << input_type
1892 << " to " << result_type;
1893 }
1894 break;
1895
Roland Levillain946e1432014-11-11 17:35:19 +00001896 case Primitive::kPrimInt:
1897 switch (input_type) {
1898 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001899 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001900 locations->SetInAt(0, Location::Any());
1901 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1902 break;
1903
1904 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001905 // Processing a Dex `float-to-int' instruction.
1906 locations->SetInAt(0, Location::RequiresFpuRegister());
1907 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00001908 break;
1909
Roland Levillain946e1432014-11-11 17:35:19 +00001910 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001911 // Processing a Dex `double-to-int' instruction.
1912 locations->SetInAt(0, Location::RequiresFpuRegister());
1913 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001914 break;
1915
1916 default:
1917 LOG(FATAL) << "Unexpected type conversion from " << input_type
1918 << " to " << result_type;
1919 }
1920 break;
1921
Roland Levillaindff1f282014-11-05 14:15:05 +00001922 case Primitive::kPrimLong:
1923 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001924 case Primitive::kPrimBoolean:
1925 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001926 case Primitive::kPrimByte:
1927 case Primitive::kPrimShort:
1928 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001929 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001930 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001931 // TODO: We would benefit from a (to-be-implemented)
1932 // Location::RegisterOrStackSlot requirement for this input.
1933 locations->SetInAt(0, Location::RequiresRegister());
1934 locations->SetOut(Location::RequiresRegister());
1935 break;
1936
1937 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001938 // Processing a Dex `float-to-long' instruction.
1939 locations->SetInAt(0, Location::RequiresFpuRegister());
1940 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00001941 break;
1942
Roland Levillaindff1f282014-11-05 14:15:05 +00001943 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001944 // Processing a Dex `double-to-long' instruction.
1945 locations->SetInAt(0, Location::RequiresFpuRegister());
1946 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00001947 break;
1948
1949 default:
1950 LOG(FATAL) << "Unexpected type conversion from " << input_type
1951 << " to " << result_type;
1952 }
1953 break;
1954
Roland Levillain981e4542014-11-14 11:47:14 +00001955 case Primitive::kPrimChar:
1956 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001957 case Primitive::kPrimBoolean:
1958 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001959 case Primitive::kPrimByte:
1960 case Primitive::kPrimShort:
1961 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001962 // Processing a Dex `int-to-char' instruction.
1963 locations->SetInAt(0, Location::Any());
1964 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1965 break;
1966
1967 default:
1968 LOG(FATAL) << "Unexpected type conversion from " << input_type
1969 << " to " << result_type;
1970 }
1971 break;
1972
Roland Levillaindff1f282014-11-05 14:15:05 +00001973 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001974 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001975 case Primitive::kPrimBoolean:
1976 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001977 case Primitive::kPrimByte:
1978 case Primitive::kPrimShort:
1979 case Primitive::kPrimInt:
1980 case Primitive::kPrimChar:
1981 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001982 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00001983 locations->SetOut(Location::RequiresFpuRegister());
1984 break;
1985
1986 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001987 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001988 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001989 locations->SetOut(Location::RequiresFpuRegister());
1990 break;
1991
Roland Levillaincff13742014-11-17 14:32:17 +00001992 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001993 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04001994 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00001995 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001996 break;
1997
1998 default:
1999 LOG(FATAL) << "Unexpected type conversion from " << input_type
2000 << " to " << result_type;
2001 };
2002 break;
2003
Roland Levillaindff1f282014-11-05 14:15:05 +00002004 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002005 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002006 case Primitive::kPrimBoolean:
2007 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002008 case Primitive::kPrimByte:
2009 case Primitive::kPrimShort:
2010 case Primitive::kPrimInt:
2011 case Primitive::kPrimChar:
2012 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002013 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002014 locations->SetOut(Location::RequiresFpuRegister());
2015 break;
2016
2017 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002018 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002019 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002020 locations->SetOut(Location::RequiresFpuRegister());
2021 break;
2022
Roland Levillaincff13742014-11-17 14:32:17 +00002023 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002024 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002025 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002026 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002027 break;
2028
2029 default:
2030 LOG(FATAL) << "Unexpected type conversion from " << input_type
2031 << " to " << result_type;
2032 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002033 break;
2034
2035 default:
2036 LOG(FATAL) << "Unexpected type conversion from " << input_type
2037 << " to " << result_type;
2038 }
2039}
2040
2041void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2042 LocationSummary* locations = conversion->GetLocations();
2043 Location out = locations->Out();
2044 Location in = locations->InAt(0);
2045 Primitive::Type result_type = conversion->GetResultType();
2046 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002047 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002048 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002049 case Primitive::kPrimByte:
2050 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002051 case Primitive::kPrimBoolean:
2052 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002053 case Primitive::kPrimShort:
2054 case Primitive::kPrimInt:
2055 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002056 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002057 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002058 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002059 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002060 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002061 Address(CpuRegister(RSP), in.GetStackIndex()));
2062 } else {
2063 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002064 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002065 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2066 }
2067 break;
2068
2069 default:
2070 LOG(FATAL) << "Unexpected type conversion from " << input_type
2071 << " to " << result_type;
2072 }
2073 break;
2074
Roland Levillain01a8d712014-11-14 16:27:39 +00002075 case Primitive::kPrimShort:
2076 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002077 case Primitive::kPrimBoolean:
2078 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002079 case Primitive::kPrimByte:
2080 case Primitive::kPrimInt:
2081 case Primitive::kPrimChar:
2082 // Processing a Dex `int-to-short' instruction.
2083 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002084 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002085 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002086 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002087 Address(CpuRegister(RSP), in.GetStackIndex()));
2088 } else {
2089 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002090 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002091 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2092 }
2093 break;
2094
2095 default:
2096 LOG(FATAL) << "Unexpected type conversion from " << input_type
2097 << " to " << result_type;
2098 }
2099 break;
2100
Roland Levillain946e1432014-11-11 17:35:19 +00002101 case Primitive::kPrimInt:
2102 switch (input_type) {
2103 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002104 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002105 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002106 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002107 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002108 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002109 Address(CpuRegister(RSP), in.GetStackIndex()));
2110 } else {
2111 DCHECK(in.IsConstant());
2112 DCHECK(in.GetConstant()->IsLongConstant());
2113 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002114 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002115 }
2116 break;
2117
Roland Levillain3f8f9362014-12-02 17:45:01 +00002118 case Primitive::kPrimFloat: {
2119 // Processing a Dex `float-to-int' instruction.
2120 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2121 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain3f8f9362014-12-02 17:45:01 +00002122 Label done, nan;
2123
2124 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002125 // if input >= (float)INT_MAX goto done
2126 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002127 __ j(kAboveEqual, &done);
2128 // if input == NaN goto nan
2129 __ j(kUnordered, &nan);
2130 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002131 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002132 __ jmp(&done);
2133 __ Bind(&nan);
2134 // output = 0
2135 __ xorl(output, output);
2136 __ Bind(&done);
2137 break;
2138 }
2139
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002140 case Primitive::kPrimDouble: {
2141 // Processing a Dex `double-to-int' instruction.
2142 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2143 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002144 Label done, nan;
2145
2146 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002147 // if input >= (double)INT_MAX goto done
2148 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002149 __ j(kAboveEqual, &done);
2150 // if input == NaN goto nan
2151 __ j(kUnordered, &nan);
2152 // output = double-to-int-truncate(input)
2153 __ cvttsd2si(output, input);
2154 __ jmp(&done);
2155 __ Bind(&nan);
2156 // output = 0
2157 __ xorl(output, output);
2158 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002159 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002160 }
Roland Levillain946e1432014-11-11 17:35:19 +00002161
2162 default:
2163 LOG(FATAL) << "Unexpected type conversion from " << input_type
2164 << " to " << result_type;
2165 }
2166 break;
2167
Roland Levillaindff1f282014-11-05 14:15:05 +00002168 case Primitive::kPrimLong:
2169 switch (input_type) {
2170 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002171 case Primitive::kPrimBoolean:
2172 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002173 case Primitive::kPrimByte:
2174 case Primitive::kPrimShort:
2175 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002176 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002177 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002178 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002179 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002180 break;
2181
Roland Levillain624279f2014-12-04 11:54:28 +00002182 case Primitive::kPrimFloat: {
2183 // Processing a Dex `float-to-long' instruction.
2184 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2185 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain624279f2014-12-04 11:54:28 +00002186 Label done, nan;
2187
Mark Mendell92e83bf2015-05-07 11:25:03 -04002188 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002189 // if input >= (float)LONG_MAX goto done
2190 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002191 __ j(kAboveEqual, &done);
2192 // if input == NaN goto nan
2193 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002194 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002195 __ cvttss2si(output, input, true);
2196 __ jmp(&done);
2197 __ Bind(&nan);
2198 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002199 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002200 __ Bind(&done);
2201 break;
2202 }
2203
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002204 case Primitive::kPrimDouble: {
2205 // Processing a Dex `double-to-long' instruction.
2206 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2207 CpuRegister output = out.AsRegister<CpuRegister>();
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002208 Label done, nan;
2209
Mark Mendell92e83bf2015-05-07 11:25:03 -04002210 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002211 // if input >= (double)LONG_MAX goto done
2212 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002213 __ j(kAboveEqual, &done);
2214 // if input == NaN goto nan
2215 __ j(kUnordered, &nan);
2216 // output = double-to-long-truncate(input)
2217 __ cvttsd2si(output, input, true);
2218 __ jmp(&done);
2219 __ Bind(&nan);
2220 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002221 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002222 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002223 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002224 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002225
2226 default:
2227 LOG(FATAL) << "Unexpected type conversion from " << input_type
2228 << " to " << result_type;
2229 }
2230 break;
2231
Roland Levillain981e4542014-11-14 11:47:14 +00002232 case Primitive::kPrimChar:
2233 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002234 case Primitive::kPrimBoolean:
2235 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002236 case Primitive::kPrimByte:
2237 case Primitive::kPrimShort:
2238 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002239 // Processing a Dex `int-to-char' instruction.
2240 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002241 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002242 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002243 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002244 Address(CpuRegister(RSP), in.GetStackIndex()));
2245 } else {
2246 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002247 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002248 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2249 }
2250 break;
2251
2252 default:
2253 LOG(FATAL) << "Unexpected type conversion from " << input_type
2254 << " to " << result_type;
2255 }
2256 break;
2257
Roland Levillaindff1f282014-11-05 14:15:05 +00002258 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002259 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002260 case Primitive::kPrimBoolean:
2261 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002262 case Primitive::kPrimByte:
2263 case Primitive::kPrimShort:
2264 case Primitive::kPrimInt:
2265 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002266 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002267 if (in.IsRegister()) {
2268 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2269 } else if (in.IsConstant()) {
2270 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2271 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2272 if (v == 0) {
2273 __ xorps(dest, dest);
2274 } else {
2275 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2276 }
2277 } else {
2278 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2279 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2280 }
Roland Levillaincff13742014-11-17 14:32:17 +00002281 break;
2282
2283 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002284 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002285 if (in.IsRegister()) {
2286 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2287 } else if (in.IsConstant()) {
2288 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2289 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2290 if (v == 0) {
2291 __ xorps(dest, dest);
2292 } else {
2293 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2294 }
2295 } else {
2296 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2297 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2298 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002299 break;
2300
Roland Levillaincff13742014-11-17 14:32:17 +00002301 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002302 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002303 if (in.IsFpuRegister()) {
2304 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2305 } else if (in.IsConstant()) {
2306 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2307 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2308 if (bit_cast<int64_t, double>(v) == 0) {
2309 __ xorps(dest, dest);
2310 } else {
2311 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2312 }
2313 } else {
2314 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2315 Address(CpuRegister(RSP), in.GetStackIndex()));
2316 }
Roland Levillaincff13742014-11-17 14:32:17 +00002317 break;
2318
2319 default:
2320 LOG(FATAL) << "Unexpected type conversion from " << input_type
2321 << " to " << result_type;
2322 };
2323 break;
2324
Roland Levillaindff1f282014-11-05 14:15:05 +00002325 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002326 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002327 case Primitive::kPrimBoolean:
2328 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002329 case Primitive::kPrimByte:
2330 case Primitive::kPrimShort:
2331 case Primitive::kPrimInt:
2332 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002333 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002334 if (in.IsRegister()) {
2335 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2336 } else if (in.IsConstant()) {
2337 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2338 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2339 if (v == 0) {
2340 __ xorpd(dest, dest);
2341 } else {
2342 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2343 }
2344 } else {
2345 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2346 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2347 }
Roland Levillaincff13742014-11-17 14:32:17 +00002348 break;
2349
2350 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002351 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002352 if (in.IsRegister()) {
2353 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2354 } else if (in.IsConstant()) {
2355 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2356 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2357 if (v == 0) {
2358 __ xorpd(dest, dest);
2359 } else {
2360 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2361 }
2362 } else {
2363 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2364 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2365 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002366 break;
2367
Roland Levillaincff13742014-11-17 14:32:17 +00002368 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002369 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002370 if (in.IsFpuRegister()) {
2371 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2372 } else if (in.IsConstant()) {
2373 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2374 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2375 if (bit_cast<int32_t, float>(v) == 0) {
2376 __ xorpd(dest, dest);
2377 } else {
2378 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2379 }
2380 } else {
2381 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2382 Address(CpuRegister(RSP), in.GetStackIndex()));
2383 }
Roland Levillaincff13742014-11-17 14:32:17 +00002384 break;
2385
2386 default:
2387 LOG(FATAL) << "Unexpected type conversion from " << input_type
2388 << " to " << result_type;
2389 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002390 break;
2391
2392 default:
2393 LOG(FATAL) << "Unexpected type conversion from " << input_type
2394 << " to " << result_type;
2395 }
2396}
2397
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002398void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002399 LocationSummary* locations =
2400 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002401 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002402 case Primitive::kPrimInt: {
2403 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002404 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2405 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002406 break;
2407 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002408
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002409 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002410 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002411 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002412 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002413 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002414 break;
2415 }
2416
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002417 case Primitive::kPrimDouble:
2418 case Primitive::kPrimFloat: {
2419 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002420 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002421 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002422 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002423 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002424
2425 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002426 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002427 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002428}
2429
2430void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2431 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002432 Location first = locations->InAt(0);
2433 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002434 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002435
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002436 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002437 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002438 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002439 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2440 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002441 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2442 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002443 } else {
2444 __ leal(out.AsRegister<CpuRegister>(), Address(
2445 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2446 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002447 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002448 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2449 __ addl(out.AsRegister<CpuRegister>(),
2450 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2451 } else {
2452 __ leal(out.AsRegister<CpuRegister>(), Address(
2453 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2454 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002455 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002456 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002457 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002458 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002459 break;
2460 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002461
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002462 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002463 if (second.IsRegister()) {
2464 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2465 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002466 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2467 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002468 } else {
2469 __ leaq(out.AsRegister<CpuRegister>(), Address(
2470 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2471 }
2472 } else {
2473 DCHECK(second.IsConstant());
2474 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2475 int32_t int32_value = Low32Bits(value);
2476 DCHECK_EQ(int32_value, value);
2477 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2478 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2479 } else {
2480 __ leaq(out.AsRegister<CpuRegister>(), Address(
2481 first.AsRegister<CpuRegister>(), int32_value));
2482 }
2483 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002484 break;
2485 }
2486
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002487 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002488 if (second.IsFpuRegister()) {
2489 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2490 } else if (second.IsConstant()) {
2491 __ addss(first.AsFpuRegister<XmmRegister>(),
2492 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2493 } else {
2494 DCHECK(second.IsStackSlot());
2495 __ addss(first.AsFpuRegister<XmmRegister>(),
2496 Address(CpuRegister(RSP), second.GetStackIndex()));
2497 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002498 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002499 }
2500
2501 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002502 if (second.IsFpuRegister()) {
2503 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2504 } else if (second.IsConstant()) {
2505 __ addsd(first.AsFpuRegister<XmmRegister>(),
2506 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2507 } else {
2508 DCHECK(second.IsDoubleStackSlot());
2509 __ addsd(first.AsFpuRegister<XmmRegister>(),
2510 Address(CpuRegister(RSP), second.GetStackIndex()));
2511 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002512 break;
2513 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002514
2515 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002516 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002517 }
2518}
2519
2520void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002521 LocationSummary* locations =
2522 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002523 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002524 case Primitive::kPrimInt: {
2525 locations->SetInAt(0, Location::RequiresRegister());
2526 locations->SetInAt(1, Location::Any());
2527 locations->SetOut(Location::SameAsFirstInput());
2528 break;
2529 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002530 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002531 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002532 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002533 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002534 break;
2535 }
Calin Juravle11351682014-10-23 15:38:15 +01002536 case Primitive::kPrimFloat:
2537 case Primitive::kPrimDouble: {
2538 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002539 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002540 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002541 break;
Calin Juravle11351682014-10-23 15:38:15 +01002542 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002543 default:
Calin Juravle11351682014-10-23 15:38:15 +01002544 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002545 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002546}
2547
2548void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2549 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002550 Location first = locations->InAt(0);
2551 Location second = locations->InAt(1);
2552 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002553 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002554 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002555 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002556 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002557 } else if (second.IsConstant()) {
2558 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002559 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002560 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002561 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002562 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002563 break;
2564 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002565 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002566 if (second.IsConstant()) {
2567 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2568 DCHECK(IsInt<32>(value));
2569 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2570 } else {
2571 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2572 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002573 break;
2574 }
2575
Calin Juravle11351682014-10-23 15:38:15 +01002576 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002577 if (second.IsFpuRegister()) {
2578 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2579 } else if (second.IsConstant()) {
2580 __ subss(first.AsFpuRegister<XmmRegister>(),
2581 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2582 } else {
2583 DCHECK(second.IsStackSlot());
2584 __ subss(first.AsFpuRegister<XmmRegister>(),
2585 Address(CpuRegister(RSP), second.GetStackIndex()));
2586 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002587 break;
Calin Juravle11351682014-10-23 15:38:15 +01002588 }
2589
2590 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002591 if (second.IsFpuRegister()) {
2592 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2593 } else if (second.IsConstant()) {
2594 __ subsd(first.AsFpuRegister<XmmRegister>(),
2595 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2596 } else {
2597 DCHECK(second.IsDoubleStackSlot());
2598 __ subsd(first.AsFpuRegister<XmmRegister>(),
2599 Address(CpuRegister(RSP), second.GetStackIndex()));
2600 }
Calin Juravle11351682014-10-23 15:38:15 +01002601 break;
2602 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002603
2604 default:
Calin Juravle11351682014-10-23 15:38:15 +01002605 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002606 }
2607}
2608
Calin Juravle34bacdf2014-10-07 20:23:36 +01002609void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2610 LocationSummary* locations =
2611 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2612 switch (mul->GetResultType()) {
2613 case Primitive::kPrimInt: {
2614 locations->SetInAt(0, Location::RequiresRegister());
2615 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002616 if (mul->InputAt(1)->IsIntConstant()) {
2617 // Can use 3 operand multiply.
2618 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2619 } else {
2620 locations->SetOut(Location::SameAsFirstInput());
2621 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002622 break;
2623 }
2624 case Primitive::kPrimLong: {
2625 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002626 locations->SetInAt(1, Location::Any());
2627 if (mul->InputAt(1)->IsLongConstant() &&
2628 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002629 // Can use 3 operand multiply.
2630 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2631 } else {
2632 locations->SetOut(Location::SameAsFirstInput());
2633 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002634 break;
2635 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002636 case Primitive::kPrimFloat:
2637 case Primitive::kPrimDouble: {
2638 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002639 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002640 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002641 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002642 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002643
2644 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002645 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002646 }
2647}
2648
2649void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2650 LocationSummary* locations = mul->GetLocations();
2651 Location first = locations->InAt(0);
2652 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002653 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002654 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002655 case Primitive::kPrimInt:
2656 // The constant may have ended up in a register, so test explicitly to avoid
2657 // problems where the output may not be the same as the first operand.
2658 if (mul->InputAt(1)->IsIntConstant()) {
2659 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2660 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2661 } else if (second.IsRegister()) {
2662 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002663 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002664 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002665 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002666 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002667 __ imull(first.AsRegister<CpuRegister>(),
2668 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002669 }
2670 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002671 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002672 // The constant may have ended up in a register, so test explicitly to avoid
2673 // problems where the output may not be the same as the first operand.
2674 if (mul->InputAt(1)->IsLongConstant()) {
2675 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2676 if (IsInt<32>(value)) {
2677 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2678 Immediate(static_cast<int32_t>(value)));
2679 } else {
2680 // Have to use the constant area.
2681 DCHECK(first.Equals(out));
2682 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2683 }
2684 } else if (second.IsRegister()) {
2685 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002686 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002687 } else {
2688 DCHECK(second.IsDoubleStackSlot());
2689 DCHECK(first.Equals(out));
2690 __ imulq(first.AsRegister<CpuRegister>(),
2691 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002692 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002693 break;
2694 }
2695
Calin Juravleb5bfa962014-10-21 18:02:24 +01002696 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002697 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002698 if (second.IsFpuRegister()) {
2699 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2700 } else if (second.IsConstant()) {
2701 __ mulss(first.AsFpuRegister<XmmRegister>(),
2702 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2703 } else {
2704 DCHECK(second.IsStackSlot());
2705 __ mulss(first.AsFpuRegister<XmmRegister>(),
2706 Address(CpuRegister(RSP), second.GetStackIndex()));
2707 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002708 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002709 }
2710
2711 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002712 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002713 if (second.IsFpuRegister()) {
2714 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2715 } else if (second.IsConstant()) {
2716 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2717 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2718 } else {
2719 DCHECK(second.IsDoubleStackSlot());
2720 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2721 Address(CpuRegister(RSP), second.GetStackIndex()));
2722 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002723 break;
2724 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002725
2726 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002727 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002728 }
2729}
2730
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002731void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2732 uint32_t stack_adjustment, bool is_float) {
2733 if (source.IsStackSlot()) {
2734 DCHECK(is_float);
2735 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2736 } else if (source.IsDoubleStackSlot()) {
2737 DCHECK(!is_float);
2738 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2739 } else {
2740 // Write the value to the temporary location on the stack and load to FP stack.
2741 if (is_float) {
2742 Location stack_temp = Location::StackSlot(temp_offset);
2743 codegen_->Move(stack_temp, source);
2744 __ flds(Address(CpuRegister(RSP), temp_offset));
2745 } else {
2746 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2747 codegen_->Move(stack_temp, source);
2748 __ fldl(Address(CpuRegister(RSP), temp_offset));
2749 }
2750 }
2751}
2752
2753void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2754 Primitive::Type type = rem->GetResultType();
2755 bool is_float = type == Primitive::kPrimFloat;
2756 size_t elem_size = Primitive::ComponentSize(type);
2757 LocationSummary* locations = rem->GetLocations();
2758 Location first = locations->InAt(0);
2759 Location second = locations->InAt(1);
2760 Location out = locations->Out();
2761
2762 // Create stack space for 2 elements.
2763 // TODO: enhance register allocator to ask for stack temporaries.
2764 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2765
2766 // Load the values to the FP stack in reverse order, using temporaries if needed.
2767 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2768 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2769
2770 // Loop doing FPREM until we stabilize.
2771 Label retry;
2772 __ Bind(&retry);
2773 __ fprem();
2774
2775 // Move FP status to AX.
2776 __ fstsw();
2777
2778 // And see if the argument reduction is complete. This is signaled by the
2779 // C2 FPU flag bit set to 0.
2780 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2781 __ j(kNotEqual, &retry);
2782
2783 // We have settled on the final value. Retrieve it into an XMM register.
2784 // Store FP top of stack to real stack.
2785 if (is_float) {
2786 __ fsts(Address(CpuRegister(RSP), 0));
2787 } else {
2788 __ fstl(Address(CpuRegister(RSP), 0));
2789 }
2790
2791 // Pop the 2 items from the FP stack.
2792 __ fucompp();
2793
2794 // Load the value from the stack into an XMM register.
2795 DCHECK(out.IsFpuRegister()) << out;
2796 if (is_float) {
2797 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2798 } else {
2799 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2800 }
2801
2802 // And remove the temporary stack space we allocated.
2803 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2804}
2805
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002806void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2807 DCHECK(instruction->IsDiv() || instruction->IsRem());
2808
2809 LocationSummary* locations = instruction->GetLocations();
2810 Location second = locations->InAt(1);
2811 DCHECK(second.IsConstant());
2812
2813 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2814 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002815 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002816
2817 DCHECK(imm == 1 || imm == -1);
2818
2819 switch (instruction->GetResultType()) {
2820 case Primitive::kPrimInt: {
2821 if (instruction->IsRem()) {
2822 __ xorl(output_register, output_register);
2823 } else {
2824 __ movl(output_register, input_register);
2825 if (imm == -1) {
2826 __ negl(output_register);
2827 }
2828 }
2829 break;
2830 }
2831
2832 case Primitive::kPrimLong: {
2833 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002834 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002835 } else {
2836 __ movq(output_register, input_register);
2837 if (imm == -1) {
2838 __ negq(output_register);
2839 }
2840 }
2841 break;
2842 }
2843
2844 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002845 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002846 }
2847}
2848
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002849void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002850 LocationSummary* locations = instruction->GetLocations();
2851 Location second = locations->InAt(1);
2852
2853 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2854 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2855
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002856 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002857
2858 DCHECK(IsPowerOfTwo(std::abs(imm)));
2859
2860 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2861
2862 if (instruction->GetResultType() == Primitive::kPrimInt) {
2863 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2864 __ testl(numerator, numerator);
2865 __ cmov(kGreaterEqual, tmp, numerator);
2866 int shift = CTZ(imm);
2867 __ sarl(tmp, Immediate(shift));
2868
2869 if (imm < 0) {
2870 __ negl(tmp);
2871 }
2872
2873 __ movl(output_register, tmp);
2874 } else {
2875 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2876 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
2877
Mark Mendell92e83bf2015-05-07 11:25:03 -04002878 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002879 __ addq(rdx, numerator);
2880 __ testq(numerator, numerator);
2881 __ cmov(kGreaterEqual, rdx, numerator);
2882 int shift = CTZ(imm);
2883 __ sarq(rdx, Immediate(shift));
2884
2885 if (imm < 0) {
2886 __ negq(rdx);
2887 }
2888
2889 __ movq(output_register, rdx);
2890 }
2891}
2892
2893void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2894 DCHECK(instruction->IsDiv() || instruction->IsRem());
2895
2896 LocationSummary* locations = instruction->GetLocations();
2897 Location second = locations->InAt(1);
2898
2899 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
2900 : locations->GetTemp(0).AsRegister<CpuRegister>();
2901 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
2902 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
2903 : locations->Out().AsRegister<CpuRegister>();
2904 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
2905
2906 DCHECK_EQ(RAX, eax.AsRegister());
2907 DCHECK_EQ(RDX, edx.AsRegister());
2908 if (instruction->IsDiv()) {
2909 DCHECK_EQ(RAX, out.AsRegister());
2910 } else {
2911 DCHECK_EQ(RDX, out.AsRegister());
2912 }
2913
2914 int64_t magic;
2915 int shift;
2916
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002917 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002918 if (instruction->GetResultType() == Primitive::kPrimInt) {
2919 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2920
2921 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2922
2923 __ movl(numerator, eax);
2924
2925 Label no_div;
2926 Label end;
2927 __ testl(eax, eax);
2928 __ j(kNotEqual, &no_div);
2929
2930 __ xorl(out, out);
2931 __ jmp(&end);
2932
2933 __ Bind(&no_div);
2934
2935 __ movl(eax, Immediate(magic));
2936 __ imull(numerator);
2937
2938 if (imm > 0 && magic < 0) {
2939 __ addl(edx, numerator);
2940 } else if (imm < 0 && magic > 0) {
2941 __ subl(edx, numerator);
2942 }
2943
2944 if (shift != 0) {
2945 __ sarl(edx, Immediate(shift));
2946 }
2947
2948 __ movl(eax, edx);
2949 __ shrl(edx, Immediate(31));
2950 __ addl(edx, eax);
2951
2952 if (instruction->IsRem()) {
2953 __ movl(eax, numerator);
2954 __ imull(edx, Immediate(imm));
2955 __ subl(eax, edx);
2956 __ movl(edx, eax);
2957 } else {
2958 __ movl(eax, edx);
2959 }
2960 __ Bind(&end);
2961 } else {
2962 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
2963
2964 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
2965
2966 CpuRegister rax = eax;
2967 CpuRegister rdx = edx;
2968
2969 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
2970
2971 // Save the numerator.
2972 __ movq(numerator, rax);
2973
2974 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04002975 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002976
2977 // RDX:RAX = magic * numerator
2978 __ imulq(numerator);
2979
2980 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002981 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002982 __ addq(rdx, numerator);
2983 } else if (imm < 0 && magic > 0) {
2984 // RDX -= numerator
2985 __ subq(rdx, numerator);
2986 }
2987
2988 // Shift if needed.
2989 if (shift != 0) {
2990 __ sarq(rdx, Immediate(shift));
2991 }
2992
2993 // RDX += 1 if RDX < 0
2994 __ movq(rax, rdx);
2995 __ shrq(rdx, Immediate(63));
2996 __ addq(rdx, rax);
2997
2998 if (instruction->IsRem()) {
2999 __ movq(rax, numerator);
3000
3001 if (IsInt<32>(imm)) {
3002 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3003 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003004 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003005 }
3006
3007 __ subq(rax, rdx);
3008 __ movq(rdx, rax);
3009 } else {
3010 __ movq(rax, rdx);
3011 }
3012 }
3013}
3014
Calin Juravlebacfec32014-11-14 15:54:36 +00003015void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3016 DCHECK(instruction->IsDiv() || instruction->IsRem());
3017 Primitive::Type type = instruction->GetResultType();
3018 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3019
3020 bool is_div = instruction->IsDiv();
3021 LocationSummary* locations = instruction->GetLocations();
3022
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003023 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3024 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003025
Roland Levillain271ab9c2014-11-27 15:23:57 +00003026 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003027 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003028
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003029 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003030 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003031
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003032 if (imm == 0) {
3033 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3034 } else if (imm == 1 || imm == -1) {
3035 DivRemOneOrMinusOne(instruction);
3036 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003037 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003038 } else {
3039 DCHECK(imm <= -2 || imm >= 2);
3040 GenerateDivRemWithAnyConstant(instruction);
3041 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003042 } else {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003043 SlowPathCodeX86_64* slow_path =
3044 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3045 out.AsRegister(), type, is_div);
3046 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003047
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003048 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3049 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3050 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3051 // so it's safe to just use negl instead of more complex comparisons.
3052 if (type == Primitive::kPrimInt) {
3053 __ cmpl(second_reg, Immediate(-1));
3054 __ j(kEqual, slow_path->GetEntryLabel());
3055 // edx:eax <- sign-extended of eax
3056 __ cdq();
3057 // eax = quotient, edx = remainder
3058 __ idivl(second_reg);
3059 } else {
3060 __ cmpq(second_reg, Immediate(-1));
3061 __ j(kEqual, slow_path->GetEntryLabel());
3062 // rdx:rax <- sign-extended of rax
3063 __ cqo();
3064 // rax = quotient, rdx = remainder
3065 __ idivq(second_reg);
3066 }
3067 __ Bind(slow_path->GetExitLabel());
3068 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003069}
3070
Calin Juravle7c4954d2014-10-28 16:57:40 +00003071void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3072 LocationSummary* locations =
3073 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3074 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003075 case Primitive::kPrimInt:
3076 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003077 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003078 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003079 locations->SetOut(Location::SameAsFirstInput());
3080 // Intel uses edx:eax as the dividend.
3081 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003082 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3083 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3084 // output and request another temp.
3085 if (div->InputAt(1)->IsConstant()) {
3086 locations->AddTemp(Location::RequiresRegister());
3087 }
Calin Juravled0d48522014-11-04 16:40:20 +00003088 break;
3089 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003090
Calin Juravle7c4954d2014-10-28 16:57:40 +00003091 case Primitive::kPrimFloat:
3092 case Primitive::kPrimDouble: {
3093 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003094 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003095 locations->SetOut(Location::SameAsFirstInput());
3096 break;
3097 }
3098
3099 default:
3100 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3101 }
3102}
3103
3104void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3105 LocationSummary* locations = div->GetLocations();
3106 Location first = locations->InAt(0);
3107 Location second = locations->InAt(1);
3108 DCHECK(first.Equals(locations->Out()));
3109
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003110 Primitive::Type type = div->GetResultType();
3111 switch (type) {
3112 case Primitive::kPrimInt:
3113 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003114 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003115 break;
3116 }
3117
Calin Juravle7c4954d2014-10-28 16:57:40 +00003118 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003119 if (second.IsFpuRegister()) {
3120 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3121 } else if (second.IsConstant()) {
3122 __ divss(first.AsFpuRegister<XmmRegister>(),
3123 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3124 } else {
3125 DCHECK(second.IsStackSlot());
3126 __ divss(first.AsFpuRegister<XmmRegister>(),
3127 Address(CpuRegister(RSP), second.GetStackIndex()));
3128 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003129 break;
3130 }
3131
3132 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003133 if (second.IsFpuRegister()) {
3134 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3135 } else if (second.IsConstant()) {
3136 __ divsd(first.AsFpuRegister<XmmRegister>(),
3137 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3138 } else {
3139 DCHECK(second.IsDoubleStackSlot());
3140 __ divsd(first.AsFpuRegister<XmmRegister>(),
3141 Address(CpuRegister(RSP), second.GetStackIndex()));
3142 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003143 break;
3144 }
3145
3146 default:
3147 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3148 }
3149}
3150
Calin Juravlebacfec32014-11-14 15:54:36 +00003151void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003152 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003153 LocationSummary* locations =
3154 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003155
3156 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003157 case Primitive::kPrimInt:
3158 case Primitive::kPrimLong: {
3159 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003160 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003161 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3162 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003163 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3164 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3165 // output and request another temp.
3166 if (rem->InputAt(1)->IsConstant()) {
3167 locations->AddTemp(Location::RequiresRegister());
3168 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003169 break;
3170 }
3171
3172 case Primitive::kPrimFloat:
3173 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003174 locations->SetInAt(0, Location::Any());
3175 locations->SetInAt(1, Location::Any());
3176 locations->SetOut(Location::RequiresFpuRegister());
3177 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003178 break;
3179 }
3180
3181 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003182 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003183 }
3184}
3185
3186void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3187 Primitive::Type type = rem->GetResultType();
3188 switch (type) {
3189 case Primitive::kPrimInt:
3190 case Primitive::kPrimLong: {
3191 GenerateDivRemIntegral(rem);
3192 break;
3193 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003194 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003195 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003196 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003197 break;
3198 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003199 default:
3200 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3201 }
3202}
3203
Calin Juravled0d48522014-11-04 16:40:20 +00003204void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3205 LocationSummary* locations =
3206 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3207 locations->SetInAt(0, Location::Any());
3208 if (instruction->HasUses()) {
3209 locations->SetOut(Location::SameAsFirstInput());
3210 }
3211}
3212
3213void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3214 SlowPathCodeX86_64* slow_path =
3215 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3216 codegen_->AddSlowPath(slow_path);
3217
3218 LocationSummary* locations = instruction->GetLocations();
3219 Location value = locations->InAt(0);
3220
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003221 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003222 case Primitive::kPrimByte:
3223 case Primitive::kPrimChar:
3224 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003225 case Primitive::kPrimInt: {
3226 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003227 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003228 __ j(kEqual, slow_path->GetEntryLabel());
3229 } else if (value.IsStackSlot()) {
3230 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3231 __ j(kEqual, slow_path->GetEntryLabel());
3232 } else {
3233 DCHECK(value.IsConstant()) << value;
3234 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3235 __ jmp(slow_path->GetEntryLabel());
3236 }
3237 }
3238 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003239 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003240 case Primitive::kPrimLong: {
3241 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003242 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003243 __ j(kEqual, slow_path->GetEntryLabel());
3244 } else if (value.IsDoubleStackSlot()) {
3245 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3246 __ j(kEqual, slow_path->GetEntryLabel());
3247 } else {
3248 DCHECK(value.IsConstant()) << value;
3249 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3250 __ jmp(slow_path->GetEntryLabel());
3251 }
3252 }
3253 break;
3254 }
3255 default:
3256 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003257 }
Calin Juravled0d48522014-11-04 16:40:20 +00003258}
3259
Calin Juravle9aec02f2014-11-18 23:06:35 +00003260void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3261 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3262
3263 LocationSummary* locations =
3264 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3265
3266 switch (op->GetResultType()) {
3267 case Primitive::kPrimInt:
3268 case Primitive::kPrimLong: {
3269 locations->SetInAt(0, Location::RequiresRegister());
3270 // The shift count needs to be in CL.
3271 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3272 locations->SetOut(Location::SameAsFirstInput());
3273 break;
3274 }
3275 default:
3276 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3277 }
3278}
3279
3280void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3281 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3282
3283 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003284 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003285 Location second = locations->InAt(1);
3286
3287 switch (op->GetResultType()) {
3288 case Primitive::kPrimInt: {
3289 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003290 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003291 if (op->IsShl()) {
3292 __ shll(first_reg, second_reg);
3293 } else if (op->IsShr()) {
3294 __ sarl(first_reg, second_reg);
3295 } else {
3296 __ shrl(first_reg, second_reg);
3297 }
3298 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003299 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003300 if (op->IsShl()) {
3301 __ shll(first_reg, imm);
3302 } else if (op->IsShr()) {
3303 __ sarl(first_reg, imm);
3304 } else {
3305 __ shrl(first_reg, imm);
3306 }
3307 }
3308 break;
3309 }
3310 case Primitive::kPrimLong: {
3311 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003312 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003313 if (op->IsShl()) {
3314 __ shlq(first_reg, second_reg);
3315 } else if (op->IsShr()) {
3316 __ sarq(first_reg, second_reg);
3317 } else {
3318 __ shrq(first_reg, second_reg);
3319 }
3320 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003321 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003322 if (op->IsShl()) {
3323 __ shlq(first_reg, imm);
3324 } else if (op->IsShr()) {
3325 __ sarq(first_reg, imm);
3326 } else {
3327 __ shrq(first_reg, imm);
3328 }
3329 }
3330 break;
3331 }
3332 default:
3333 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3334 }
3335}
3336
3337void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3338 HandleShift(shl);
3339}
3340
3341void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3342 HandleShift(shl);
3343}
3344
3345void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3346 HandleShift(shr);
3347}
3348
3349void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3350 HandleShift(shr);
3351}
3352
3353void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3354 HandleShift(ushr);
3355}
3356
3357void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3358 HandleShift(ushr);
3359}
3360
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003361void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003362 LocationSummary* locations =
3363 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003364 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003365 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003366 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003367 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003368}
3369
3370void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3371 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003372 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3373 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003374 // Note: if heap poisoning is enabled, the entry point takes cares
3375 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003376
3377 codegen_->InvokeRuntime(
3378 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3379 instruction,
3380 instruction->GetDexPc(),
3381 nullptr);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003382
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003383 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003384}
3385
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003386void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3387 LocationSummary* locations =
3388 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3389 InvokeRuntimeCallingConvention calling_convention;
3390 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003391 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003392 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003393 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003394}
3395
3396void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3397 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003398 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3399 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003400
Roland Levillain4d027112015-07-01 15:41:14 +01003401 // Note: if heap poisoning is enabled, the entry point takes cares
3402 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003403 codegen_->InvokeRuntime(
3404 Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true),
3405 instruction,
3406 instruction->GetDexPc(),
3407 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003408
3409 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003410}
3411
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003412void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003413 LocationSummary* locations =
3414 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003415 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3416 if (location.IsStackSlot()) {
3417 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3418 } else if (location.IsDoubleStackSlot()) {
3419 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3420 }
3421 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003422}
3423
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003424void InstructionCodeGeneratorX86_64::VisitParameterValue(
3425 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003426 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003427}
3428
3429void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3430 LocationSummary* locations =
3431 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3432 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3433}
3434
3435void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3436 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3437 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003438}
3439
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003440void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003441 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003442 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003443 locations->SetInAt(0, Location::RequiresRegister());
3444 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003445}
3446
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003447void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3448 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003449 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3450 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003451 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003452 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003453 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003454 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003455 break;
3456
3457 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003458 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003459 break;
3460
3461 default:
3462 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3463 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003464}
3465
David Brazdil66d126e2015-04-03 16:02:44 +01003466void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3467 LocationSummary* locations =
3468 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3469 locations->SetInAt(0, Location::RequiresRegister());
3470 locations->SetOut(Location::SameAsFirstInput());
3471}
3472
3473void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003474 LocationSummary* locations = bool_not->GetLocations();
3475 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3476 locations->Out().AsRegister<CpuRegister>().AsRegister());
3477 Location out = locations->Out();
3478 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3479}
3480
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003481void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003482 LocationSummary* locations =
3483 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003484 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3485 locations->SetInAt(i, Location::Any());
3486 }
3487 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003488}
3489
3490void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003491 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003492 LOG(FATAL) << "Unimplemented";
3493}
3494
Calin Juravle52c48962014-12-16 17:02:57 +00003495void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3496 /*
3497 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3498 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3499 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3500 */
3501 switch (kind) {
3502 case MemBarrierKind::kAnyAny: {
3503 __ mfence();
3504 break;
3505 }
3506 case MemBarrierKind::kAnyStore:
3507 case MemBarrierKind::kLoadAny:
3508 case MemBarrierKind::kStoreStore: {
3509 // nop
3510 break;
3511 }
3512 default:
3513 LOG(FATAL) << "Unexpected memory barier " << kind;
3514 }
3515}
3516
3517void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3518 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3519
Nicolas Geoffray39468442014-09-02 15:17:15 +01003520 LocationSummary* locations =
3521 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003522 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003523 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3524 locations->SetOut(Location::RequiresFpuRegister());
3525 } else {
3526 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3527 }
Calin Juravle52c48962014-12-16 17:02:57 +00003528}
3529
3530void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3531 const FieldInfo& field_info) {
3532 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3533
3534 LocationSummary* locations = instruction->GetLocations();
3535 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3536 Location out = locations->Out();
3537 bool is_volatile = field_info.IsVolatile();
3538 Primitive::Type field_type = field_info.GetFieldType();
3539 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3540
3541 switch (field_type) {
3542 case Primitive::kPrimBoolean: {
3543 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3544 break;
3545 }
3546
3547 case Primitive::kPrimByte: {
3548 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3549 break;
3550 }
3551
3552 case Primitive::kPrimShort: {
3553 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3554 break;
3555 }
3556
3557 case Primitive::kPrimChar: {
3558 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3559 break;
3560 }
3561
3562 case Primitive::kPrimInt:
3563 case Primitive::kPrimNot: {
3564 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3565 break;
3566 }
3567
3568 case Primitive::kPrimLong: {
3569 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3570 break;
3571 }
3572
3573 case Primitive::kPrimFloat: {
3574 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3575 break;
3576 }
3577
3578 case Primitive::kPrimDouble: {
3579 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3580 break;
3581 }
3582
3583 case Primitive::kPrimVoid:
3584 LOG(FATAL) << "Unreachable type " << field_type;
3585 UNREACHABLE();
3586 }
3587
Calin Juravle77520bc2015-01-12 18:45:46 +00003588 codegen_->MaybeRecordImplicitNullCheck(instruction);
3589
Calin Juravle52c48962014-12-16 17:02:57 +00003590 if (is_volatile) {
3591 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3592 }
Roland Levillain4d027112015-07-01 15:41:14 +01003593
3594 if (field_type == Primitive::kPrimNot) {
3595 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3596 }
Calin Juravle52c48962014-12-16 17:02:57 +00003597}
3598
3599void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3600 const FieldInfo& field_info) {
3601 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3602
3603 LocationSummary* locations =
3604 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003605 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003606 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003607 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003608
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003609 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003610 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3611 locations->SetInAt(1, Location::RequiresFpuRegister());
3612 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003613 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003614 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003615 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003616 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003617 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003618 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003619 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3620 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003621 locations->AddTemp(Location::RequiresRegister());
3622 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003623}
3624
Calin Juravle52c48962014-12-16 17:02:57 +00003625void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003626 const FieldInfo& field_info,
3627 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003628 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3629
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003630 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003631 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3632 Location value = locations->InAt(1);
3633 bool is_volatile = field_info.IsVolatile();
3634 Primitive::Type field_type = field_info.GetFieldType();
3635 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3636
3637 if (is_volatile) {
3638 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3639 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003640
3641 switch (field_type) {
3642 case Primitive::kPrimBoolean:
3643 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003644 if (value.IsConstant()) {
3645 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3646 __ movb(Address(base, offset), Immediate(v));
3647 } else {
3648 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3649 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003650 break;
3651 }
3652
3653 case Primitive::kPrimShort:
3654 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003655 if (value.IsConstant()) {
3656 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3657 __ movw(Address(base, offset), Immediate(v));
3658 } else {
3659 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3660 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003661 break;
3662 }
3663
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003664 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003665 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003666 if (value.IsConstant()) {
3667 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003668 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3669 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3670 // Note: if heap poisoning is enabled, no need to poison
3671 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003672 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003673 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003674 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3675 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3676 __ movl(temp, value.AsRegister<CpuRegister>());
3677 __ PoisonHeapReference(temp);
3678 __ movl(Address(base, offset), temp);
3679 } else {
3680 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3681 }
Mark Mendell40741f32015-04-20 22:10:34 -04003682 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003683 break;
3684 }
3685
3686 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003687 if (value.IsConstant()) {
3688 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3689 DCHECK(IsInt<32>(v));
3690 int32_t v_32 = v;
3691 __ movq(Address(base, offset), Immediate(v_32));
3692 } else {
3693 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3694 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003695 break;
3696 }
3697
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003698 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003699 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003700 break;
3701 }
3702
3703 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003704 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003705 break;
3706 }
3707
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003708 case Primitive::kPrimVoid:
3709 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003710 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003711 }
Calin Juravle52c48962014-12-16 17:02:57 +00003712
Calin Juravle77520bc2015-01-12 18:45:46 +00003713 codegen_->MaybeRecordImplicitNullCheck(instruction);
3714
3715 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3716 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3717 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003718 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003719 }
3720
Calin Juravle52c48962014-12-16 17:02:57 +00003721 if (is_volatile) {
3722 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3723 }
3724}
3725
3726void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3727 HandleFieldSet(instruction, instruction->GetFieldInfo());
3728}
3729
3730void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003731 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003732}
3733
3734void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003735 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003736}
3737
3738void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003739 HandleFieldGet(instruction, instruction->GetFieldInfo());
3740}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003741
Calin Juravle52c48962014-12-16 17:02:57 +00003742void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3743 HandleFieldGet(instruction);
3744}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003745
Calin Juravle52c48962014-12-16 17:02:57 +00003746void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3747 HandleFieldGet(instruction, instruction->GetFieldInfo());
3748}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003749
Calin Juravle52c48962014-12-16 17:02:57 +00003750void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3751 HandleFieldSet(instruction, instruction->GetFieldInfo());
3752}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003753
Calin Juravle52c48962014-12-16 17:02:57 +00003754void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003755 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003756}
3757
3758void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003759 LocationSummary* locations =
3760 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003761 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3762 ? Location::RequiresRegister()
3763 : Location::Any();
3764 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003765 if (instruction->HasUses()) {
3766 locations->SetOut(Location::SameAsFirstInput());
3767 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003768}
3769
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003770void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003771 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3772 return;
3773 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003774 LocationSummary* locations = instruction->GetLocations();
3775 Location obj = locations->InAt(0);
3776
3777 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3778 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3779}
3780
3781void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003782 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003783 codegen_->AddSlowPath(slow_path);
3784
3785 LocationSummary* locations = instruction->GetLocations();
3786 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003787
3788 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003789 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003790 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003791 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003792 } else {
3793 DCHECK(obj.IsConstant()) << obj;
3794 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3795 __ jmp(slow_path->GetEntryLabel());
3796 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003797 }
3798 __ j(kEqual, slow_path->GetEntryLabel());
3799}
3800
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003801void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
3802 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3803 GenerateImplicitNullCheck(instruction);
3804 } else {
3805 GenerateExplicitNullCheck(instruction);
3806 }
3807}
3808
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003809void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003810 LocationSummary* locations =
3811 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003812 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04003813 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003814 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3815 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3816 } else {
3817 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3818 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003819}
3820
3821void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
3822 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003823 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003824 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003825 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003826
Roland Levillain4d027112015-07-01 15:41:14 +01003827 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003828 case Primitive::kPrimBoolean: {
3829 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003830 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003831 if (index.IsConstant()) {
3832 __ movzxb(out, Address(obj,
3833 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3834 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003835 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003836 }
3837 break;
3838 }
3839
3840 case Primitive::kPrimByte: {
3841 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003842 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003843 if (index.IsConstant()) {
3844 __ movsxb(out, Address(obj,
3845 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3846 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003847 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003848 }
3849 break;
3850 }
3851
3852 case Primitive::kPrimShort: {
3853 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003854 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003855 if (index.IsConstant()) {
3856 __ movsxw(out, Address(obj,
3857 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3858 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003859 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003860 }
3861 break;
3862 }
3863
3864 case Primitive::kPrimChar: {
3865 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003866 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003867 if (index.IsConstant()) {
3868 __ movzxw(out, Address(obj,
3869 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3870 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003871 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003872 }
3873 break;
3874 }
3875
3876 case Primitive::kPrimInt:
3877 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003878 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3879 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003880 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003881 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003882 if (index.IsConstant()) {
3883 __ movl(out, Address(obj,
3884 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3885 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003886 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003887 }
3888 break;
3889 }
3890
3891 case Primitive::kPrimLong: {
3892 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003893 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003894 if (index.IsConstant()) {
3895 __ movq(out, Address(obj,
3896 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3897 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003898 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003899 }
3900 break;
3901 }
3902
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003903 case Primitive::kPrimFloat: {
3904 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003905 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003906 if (index.IsConstant()) {
3907 __ movss(out, Address(obj,
3908 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3909 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003910 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003911 }
3912 break;
3913 }
3914
3915 case Primitive::kPrimDouble: {
3916 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003917 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003918 if (index.IsConstant()) {
3919 __ movsd(out, Address(obj,
3920 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3921 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003922 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003923 }
3924 break;
3925 }
3926
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003928 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003929 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003930 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003931 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003932
3933 if (type == Primitive::kPrimNot) {
3934 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3935 __ MaybeUnpoisonHeapReference(out);
3936 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003937}
3938
3939void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003940 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003941
3942 bool needs_write_barrier =
3943 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3944 bool needs_runtime_call = instruction->NeedsTypeCheck();
3945
Nicolas Geoffray39468442014-09-02 15:17:15 +01003946 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003947 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3948 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003949 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003950 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3951 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3952 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003953 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003954 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003955 locations->SetInAt(
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003956 1, Location::RegisterOrConstant(instruction->InputAt(1)));
3957 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003958 if (value_type == Primitive::kPrimLong) {
Mark Mendell40741f32015-04-20 22:10:34 -04003959 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003960 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
3961 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003962 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003963 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003964 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003965
3966 if (needs_write_barrier) {
3967 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003968 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003969 locations->AddTemp(Location::RequiresRegister());
3970 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003971 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003972}
3973
3974void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
3975 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003976 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003977 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003978 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003979 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003980 bool needs_runtime_call = locations->WillCall();
3981 bool needs_write_barrier =
3982 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003983
3984 switch (value_type) {
3985 case Primitive::kPrimBoolean:
3986 case Primitive::kPrimByte: {
3987 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003988 if (index.IsConstant()) {
3989 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003990 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003991 __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003992 } else {
Roland Levillain199f3362014-11-27 17:15:16 +00003993 __ movb(Address(obj, offset),
3994 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003995 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003996 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003997 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003998 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
3999 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004000 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004001 __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004002 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4003 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004004 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004005 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004006 break;
4007 }
4008
4009 case Primitive::kPrimShort:
4010 case Primitive::kPrimChar: {
4011 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004012 if (index.IsConstant()) {
4013 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004014 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004015 __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004016 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004017 DCHECK(value.IsConstant()) << value;
Roland Levillain199f3362014-11-27 17:15:16 +00004018 __ movw(Address(obj, offset),
4019 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004020 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004021 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004022 DCHECK(index.IsRegister()) << index;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004023 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004024 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
4025 value.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004026 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004027 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00004028 __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004029 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4030 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004031 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004032 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004033 break;
4034 }
4035
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004036 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004037 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004038 if (!needs_runtime_call) {
4039 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4040 if (index.IsConstant()) {
4041 size_t offset =
4042 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4043 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004044 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4045 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4046 __ movl(temp, value.AsRegister<CpuRegister>());
4047 __ PoisonHeapReference(temp);
4048 __ movl(Address(obj, offset), temp);
4049 } else {
4050 __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
4051 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004052 } else {
4053 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004054 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004055 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4056 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4057 // Note: if heap poisoning is enabled, no need to poison
4058 // (negate) `v` if it is a reference, as it would be null.
Mark Mendell40741f32015-04-20 22:10:34 -04004059 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004060 }
4061 } else {
4062 DCHECK(index.IsRegister()) << index;
4063 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004064 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4065 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4066 __ movl(temp, value.AsRegister<CpuRegister>());
4067 __ PoisonHeapReference(temp);
4068 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
4069 } else {
4070 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4071 value.AsRegister<CpuRegister>());
4072 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004073 } else {
4074 DCHECK(value.IsConstant()) << value;
Mark Mendell40741f32015-04-20 22:10:34 -04004075 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004076 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4077 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4078 // Note: if heap poisoning is enabled, no need to poison
4079 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004080 __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
Mark Mendell40741f32015-04-20 22:10:34 -04004081 Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004082 }
4083 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004084 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004085 if (needs_write_barrier) {
4086 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004087 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4088 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004089 codegen_->MarkGCCard(
4090 temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004091 }
4092 } else {
4093 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01004094 // Note: if heap poisoning is enabled, pAputObject takes cares
4095 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01004096 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
4097 instruction,
4098 instruction->GetDexPc(),
4099 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004100 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004101 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004102 break;
4103 }
4104
4105 case Primitive::kPrimLong: {
4106 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004107 if (index.IsConstant()) {
4108 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Mark Mendell40741f32015-04-20 22:10:34 -04004109 if (value.IsRegister()) {
4110 __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
4111 } else {
4112 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4113 DCHECK(IsInt<32>(v));
4114 int32_t v_32 = v;
4115 __ movq(Address(obj, offset), Immediate(v_32));
4116 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004117 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04004118 if (value.IsRegister()) {
4119 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4120 value.AsRegister<CpuRegister>());
4121 } else {
4122 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4123 DCHECK(IsInt<32>(v));
4124 int32_t v_32 = v;
4125 __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4126 Immediate(v_32));
4127 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004128 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004129 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004130 break;
4131 }
4132
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004133 case Primitive::kPrimFloat: {
4134 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4135 if (index.IsConstant()) {
4136 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4137 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004138 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004139 } else {
4140 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004141 __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
4142 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004143 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004144 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004145 break;
4146 }
4147
4148 case Primitive::kPrimDouble: {
4149 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4150 if (index.IsConstant()) {
4151 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4152 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004153 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004154 } else {
4155 DCHECK(value.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004156 __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
4157 value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004158 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004159 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004160 break;
4161 }
4162
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004163 case Primitive::kPrimVoid:
4164 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004165 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004166 }
4167}
4168
4169void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004170 LocationSummary* locations =
4171 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004172 locations->SetInAt(0, Location::RequiresRegister());
4173 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004174}
4175
4176void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4177 LocationSummary* locations = instruction->GetLocations();
4178 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004179 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4180 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004181 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004182 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004183}
4184
4185void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004186 LocationSummary* locations =
4187 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004188 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004189 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004190 if (instruction->HasUses()) {
4191 locations->SetOut(Location::SameAsFirstInput());
4192 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004193}
4194
4195void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4196 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004197 Location index_loc = locations->InAt(0);
4198 Location length_loc = locations->InAt(1);
4199 SlowPathCodeX86_64* slow_path =
4200 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004201
Mark Mendell99dbd682015-04-22 16:18:52 -04004202 if (length_loc.IsConstant()) {
4203 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4204 if (index_loc.IsConstant()) {
4205 // BCE will remove the bounds check if we are guarenteed to pass.
4206 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4207 if (index < 0 || index >= length) {
4208 codegen_->AddSlowPath(slow_path);
4209 __ jmp(slow_path->GetEntryLabel());
4210 } else {
4211 // Some optimization after BCE may have generated this, and we should not
4212 // generate a bounds check if it is a valid range.
4213 }
4214 return;
4215 }
4216
4217 // We have to reverse the jump condition because the length is the constant.
4218 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4219 __ cmpl(index_reg, Immediate(length));
4220 codegen_->AddSlowPath(slow_path);
4221 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004222 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004223 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4224 if (index_loc.IsConstant()) {
4225 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4226 __ cmpl(length, Immediate(value));
4227 } else {
4228 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4229 }
4230 codegen_->AddSlowPath(slow_path);
4231 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004232 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004233}
4234
4235void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4236 CpuRegister card,
4237 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004238 CpuRegister value,
4239 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004240 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004241 if (value_can_be_null) {
4242 __ testl(value, value);
4243 __ j(kEqual, &is_null);
4244 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004245 __ gs()->movq(card, Address::Absolute(
4246 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4247 __ movq(temp, object);
4248 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004249 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004250 if (value_can_be_null) {
4251 __ Bind(&is_null);
4252 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004253}
4254
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004255void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4256 temp->SetLocations(nullptr);
4257}
4258
4259void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4260 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004261 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004262}
4263
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004264void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004265 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004266 LOG(FATAL) << "Unimplemented";
4267}
4268
4269void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004270 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4271}
4272
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004273void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4274 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4275}
4276
4277void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004278 HBasicBlock* block = instruction->GetBlock();
4279 if (block->GetLoopInformation() != nullptr) {
4280 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4281 // The back edge will generate the suspend check.
4282 return;
4283 }
4284 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4285 // The goto will generate the suspend check.
4286 return;
4287 }
4288 GenerateSuspendCheck(instruction, nullptr);
4289}
4290
4291void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4292 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004293 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004294 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4295 if (slow_path == nullptr) {
4296 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4297 instruction->SetSlowPath(slow_path);
4298 codegen_->AddSlowPath(slow_path);
4299 if (successor != nullptr) {
4300 DCHECK(successor->IsLoopHeader());
4301 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4302 }
4303 } else {
4304 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4305 }
4306
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004307 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004308 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004309 if (successor == nullptr) {
4310 __ j(kNotEqual, slow_path->GetEntryLabel());
4311 __ Bind(slow_path->GetReturnLabel());
4312 } else {
4313 __ j(kEqual, codegen_->GetLabelOf(successor));
4314 __ jmp(slow_path->GetEntryLabel());
4315 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004316}
4317
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004318X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4319 return codegen_->GetAssembler();
4320}
4321
4322void ParallelMoveResolverX86_64::EmitMove(size_t index) {
4323 MoveOperands* move = moves_.Get(index);
4324 Location source = move->GetSource();
4325 Location destination = move->GetDestination();
4326
4327 if (source.IsRegister()) {
4328 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004329 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004330 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004331 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004332 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004333 } else {
4334 DCHECK(destination.IsDoubleStackSlot());
4335 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004336 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004337 }
4338 } else if (source.IsStackSlot()) {
4339 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004340 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004341 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004342 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004343 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004344 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004345 } else {
4346 DCHECK(destination.IsStackSlot());
4347 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4348 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4349 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004350 } else if (source.IsDoubleStackSlot()) {
4351 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004352 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004353 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004354 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004355 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4356 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004357 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004358 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004359 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4360 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4361 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004362 } else if (source.IsConstant()) {
4363 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004364 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4365 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004366 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004367 if (value == 0) {
4368 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4369 } else {
4370 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4371 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004372 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004373 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004374 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004375 }
4376 } else if (constant->IsLongConstant()) {
4377 int64_t value = constant->AsLongConstant()->GetValue();
4378 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004379 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004380 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004381 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004382 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004383 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004384 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004385 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004386 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004387 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004388 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4389 if (value == 0) {
4390 // easy FP 0.0.
4391 __ xorps(dest, dest);
4392 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004393 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004394 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004395 } else {
4396 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004397 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004398 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4399 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004400 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004401 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004402 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004403 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004404 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004405 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4406 if (value == 0) {
4407 __ xorpd(dest, dest);
4408 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004409 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004410 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004411 } else {
4412 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004413 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004414 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004415 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004416 } else if (source.IsFpuRegister()) {
4417 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004418 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004419 } else if (destination.IsStackSlot()) {
4420 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004421 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004422 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004423 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004424 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004425 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004426 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004427 }
4428}
4429
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004430void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004431 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004432 __ movl(Address(CpuRegister(RSP), mem), reg);
4433 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004434}
4435
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004436void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004437 ScratchRegisterScope ensure_scratch(
4438 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4439
4440 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4441 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4442 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4443 Address(CpuRegister(RSP), mem2 + stack_offset));
4444 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4445 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4446 CpuRegister(ensure_scratch.GetRegister()));
4447}
4448
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004449void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4450 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4451 __ movq(Address(CpuRegister(RSP), mem), reg);
4452 __ movq(reg, CpuRegister(TMP));
4453}
4454
4455void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4456 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004457 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004458
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004459 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4460 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4461 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4462 Address(CpuRegister(RSP), mem2 + stack_offset));
4463 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4464 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4465 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004466}
4467
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004468void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4469 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4470 __ movss(Address(CpuRegister(RSP), mem), reg);
4471 __ movd(reg, CpuRegister(TMP));
4472}
4473
4474void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4475 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4476 __ movsd(Address(CpuRegister(RSP), mem), reg);
4477 __ movd(reg, CpuRegister(TMP));
4478}
4479
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004480void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
4481 MoveOperands* move = moves_.Get(index);
4482 Location source = move->GetSource();
4483 Location destination = move->GetDestination();
4484
4485 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004486 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004487 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004488 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004489 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004490 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004491 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004492 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4493 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004494 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004495 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004496 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004497 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4498 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004499 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004500 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4501 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4502 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004503 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004504 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004505 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004506 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004507 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004508 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004509 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004510 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004511 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004512 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004513 }
4514}
4515
4516
4517void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4518 __ pushq(CpuRegister(reg));
4519}
4520
4521
4522void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4523 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004524}
4525
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004526void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
4527 SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
4528 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4529 Immediate(mirror::Class::kStatusInitialized));
4530 __ j(kLess, slow_path->GetEntryLabel());
4531 __ Bind(slow_path->GetExitLabel());
4532 // No need for memory fence, thanks to the X86_64 memory model.
4533}
4534
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004535void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004536 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4537 ? LocationSummary::kCallOnSlowPath
4538 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004539 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004540 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004541 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004542 locations->SetOut(Location::RequiresRegister());
4543}
4544
4545void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004546 LocationSummary* locations = cls->GetLocations();
4547 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4548 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004549 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004550 DCHECK(!cls->CanCallRuntime());
4551 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004552 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004553 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004554 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004555 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004556 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004557 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004558 __ MaybeUnpoisonHeapReference(out);
4559
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004560 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4561 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4562 codegen_->AddSlowPath(slow_path);
4563 __ testl(out, out);
4564 __ j(kEqual, slow_path->GetEntryLabel());
4565 if (cls->MustGenerateClinitCheck()) {
4566 GenerateClassInitializationCheck(slow_path, out);
4567 } else {
4568 __ Bind(slow_path->GetExitLabel());
4569 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004570 }
4571}
4572
4573void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4574 LocationSummary* locations =
4575 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4576 locations->SetInAt(0, Location::RequiresRegister());
4577 if (check->HasUses()) {
4578 locations->SetOut(Location::SameAsFirstInput());
4579 }
4580}
4581
4582void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004583 // We assume the class to not be null.
4584 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
4585 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004586 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004587 GenerateClassInitializationCheck(slow_path,
4588 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004589}
4590
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004591void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4592 LocationSummary* locations =
4593 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004594 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004595 locations->SetOut(Location::RequiresRegister());
4596}
4597
4598void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
4599 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
4600 codegen_->AddSlowPath(slow_path);
4601
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004602 LocationSummary* locations = load->GetLocations();
4603 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4604 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004605 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004606 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Roland Levillain4d027112015-07-01 15:41:14 +01004607 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004608 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Roland Levillain4d027112015-07-01 15:41:14 +01004609 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004610 __ testl(out, out);
4611 __ j(kEqual, slow_path->GetEntryLabel());
4612 __ Bind(slow_path->GetExitLabel());
4613}
4614
David Brazdilcb1c0552015-08-04 16:22:25 +01004615static Address GetExceptionTlsAddress() {
4616 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4617}
4618
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004619void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4620 LocationSummary* locations =
4621 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4622 locations->SetOut(Location::RequiresRegister());
4623}
4624
4625void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004626 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4627}
4628
4629void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4630 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4631}
4632
4633void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4634 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004635}
4636
4637void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4638 LocationSummary* locations =
4639 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4640 InvokeRuntimeCallingConvention calling_convention;
4641 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4642}
4643
4644void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004645 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4646 instruction,
4647 instruction->GetDexPc(),
4648 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004649}
4650
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004651void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004652 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4653 ? LocationSummary::kNoCall
4654 : LocationSummary::kCallOnSlowPath;
4655 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4656 locations->SetInAt(0, Location::RequiresRegister());
4657 locations->SetInAt(1, Location::Any());
4658 locations->SetOut(Location::RequiresRegister());
4659}
4660
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004661void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004662 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004663 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004664 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004665 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004666 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4667 Label done, zero;
4668 SlowPathCodeX86_64* slow_path = nullptr;
4669
4670 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004671 // Avoid null check if we know obj is not null.
4672 if (instruction->MustDoNullCheck()) {
4673 __ testl(obj, obj);
4674 __ j(kEqual, &zero);
4675 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004676 // Compare the class of `obj` with `cls`.
4677 __ movl(out, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004678 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004679 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004680 __ cmpl(out, cls.AsRegister<CpuRegister>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004681 } else {
4682 DCHECK(cls.IsStackSlot()) << cls;
4683 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4684 }
4685 if (instruction->IsClassFinal()) {
4686 // Classes must be equal for the instanceof to succeed.
4687 __ j(kNotEqual, &zero);
4688 __ movl(out, Immediate(1));
4689 __ jmp(&done);
4690 } else {
4691 // If the classes are not equal, we go into a slow path.
4692 DCHECK(locations->OnlyCallsOnSlowPath());
4693 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004694 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004695 codegen_->AddSlowPath(slow_path);
4696 __ j(kNotEqual, slow_path->GetEntryLabel());
4697 __ movl(out, Immediate(1));
4698 __ jmp(&done);
4699 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004700
4701 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4702 __ Bind(&zero);
4703 __ movl(out, Immediate(0));
4704 }
4705
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004706 if (slow_path != nullptr) {
4707 __ Bind(slow_path->GetExitLabel());
4708 }
4709 __ Bind(&done);
4710}
4711
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004712void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
4713 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4714 instruction, LocationSummary::kCallOnSlowPath);
4715 locations->SetInAt(0, Location::RequiresRegister());
4716 locations->SetInAt(1, Location::Any());
4717 locations->AddTemp(Location::RequiresRegister());
4718}
4719
4720void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
4721 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004722 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004723 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004724 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004725 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4726 SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
4727 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4728 codegen_->AddSlowPath(slow_path);
4729
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004730 // Avoid null check if we know obj is not null.
4731 if (instruction->MustDoNullCheck()) {
4732 __ testl(obj, obj);
4733 __ j(kEqual, slow_path->GetExitLabel());
4734 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004735 // Compare the class of `obj` with `cls`.
4736 __ movl(temp, Address(obj, class_offset));
Roland Levillain4d027112015-07-01 15:41:14 +01004737 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004738 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004739 __ cmpl(temp, cls.AsRegister<CpuRegister>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004740 } else {
4741 DCHECK(cls.IsStackSlot()) << cls;
4742 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
4743 }
Roland Levillain4d027112015-07-01 15:41:14 +01004744 // The checkcast succeeds if the classes are equal (fast path).
4745 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004746 __ j(kNotEqual, slow_path->GetEntryLabel());
4747 __ Bind(slow_path->GetExitLabel());
4748}
4749
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004750void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
4751 LocationSummary* locations =
4752 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4753 InvokeRuntimeCallingConvention calling_convention;
4754 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4755}
4756
4757void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004758 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
4759 : QUICK_ENTRY_POINT(pUnlockObject),
4760 instruction,
4761 instruction->GetDexPc(),
4762 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004763}
4764
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004765void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4766void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4767void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4768
4769void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4770 LocationSummary* locations =
4771 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4772 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4773 || instruction->GetResultType() == Primitive::kPrimLong);
4774 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004775 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004776 locations->SetOut(Location::SameAsFirstInput());
4777}
4778
4779void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
4780 HandleBitwiseOperation(instruction);
4781}
4782
4783void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
4784 HandleBitwiseOperation(instruction);
4785}
4786
4787void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
4788 HandleBitwiseOperation(instruction);
4789}
4790
4791void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
4792 LocationSummary* locations = instruction->GetLocations();
4793 Location first = locations->InAt(0);
4794 Location second = locations->InAt(1);
4795 DCHECK(first.Equals(locations->Out()));
4796
4797 if (instruction->GetResultType() == Primitive::kPrimInt) {
4798 if (second.IsRegister()) {
4799 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004800 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004801 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004802 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004803 } else {
4804 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004805 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004806 }
4807 } else if (second.IsConstant()) {
4808 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
4809 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004810 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004811 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004812 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004813 } else {
4814 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004815 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004816 }
4817 } else {
4818 Address address(CpuRegister(RSP), second.GetStackIndex());
4819 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004820 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004821 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004822 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004823 } else {
4824 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004825 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004826 }
4827 }
4828 } else {
4829 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004830 CpuRegister first_reg = first.AsRegister<CpuRegister>();
4831 bool second_is_constant = false;
4832 int64_t value = 0;
4833 if (second.IsConstant()) {
4834 second_is_constant = true;
4835 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004836 }
Mark Mendell40741f32015-04-20 22:10:34 -04004837 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004838
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004839 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004840 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004841 if (is_int32_value) {
4842 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
4843 } else {
4844 __ andq(first_reg, codegen_->LiteralInt64Address(value));
4845 }
4846 } else if (second.IsDoubleStackSlot()) {
4847 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004848 } else {
4849 __ andq(first_reg, second.AsRegister<CpuRegister>());
4850 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004851 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004852 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004853 if (is_int32_value) {
4854 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
4855 } else {
4856 __ orq(first_reg, codegen_->LiteralInt64Address(value));
4857 }
4858 } else if (second.IsDoubleStackSlot()) {
4859 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004860 } else {
4861 __ orq(first_reg, second.AsRegister<CpuRegister>());
4862 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004863 } else {
4864 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004865 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04004866 if (is_int32_value) {
4867 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
4868 } else {
4869 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
4870 }
4871 } else if (second.IsDoubleStackSlot()) {
4872 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004873 } else {
4874 __ xorq(first_reg, second.AsRegister<CpuRegister>());
4875 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004876 }
4877 }
4878}
4879
Calin Juravleb1498f62015-02-16 13:13:29 +00004880void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
4881 // Nothing to do, this should be removed during prepare for register allocator.
4882 UNUSED(instruction);
4883 LOG(FATAL) << "Unreachable";
4884}
4885
4886void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
4887 // Nothing to do, this should be removed during prepare for register allocator.
4888 UNUSED(instruction);
4889 LOG(FATAL) << "Unreachable";
4890}
4891
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004892void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
4893 DCHECK(codegen_->IsBaseline());
4894 LocationSummary* locations =
4895 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4896 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4897}
4898
4899void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4900 DCHECK(codegen_->IsBaseline());
4901 // Will be generated at use site.
4902}
4903
Mark Mendell92e83bf2015-05-07 11:25:03 -04004904void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
4905 if (value == 0) {
4906 __ xorl(dest, dest);
4907 } else if (value > 0 && IsInt<32>(value)) {
4908 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
4909 __ movl(dest, Immediate(static_cast<int32_t>(value)));
4910 } else {
4911 __ movq(dest, Immediate(value));
4912 }
4913}
4914
Mark Mendellcfa410b2015-05-25 16:02:44 -04004915void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
4916 DCHECK(dest.IsDoubleStackSlot());
4917 if (IsInt<32>(value)) {
4918 // Can move directly as an int32 constant.
4919 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
4920 Immediate(static_cast<int32_t>(value)));
4921 } else {
4922 Load64BitValue(CpuRegister(TMP), value);
4923 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
4924 }
4925}
4926
Mark Mendellf55c3e02015-03-26 21:07:46 -04004927void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
4928 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04004929 X86_64Assembler* assembler = GetAssembler();
4930 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04004931 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
4932 // byte values. If used for vectors at a later time, this will need to be
4933 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04004934 assembler->Align(4, 0);
4935 constant_area_start_ = assembler->CodeSize();
4936 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04004937 }
4938
4939 // And finish up.
4940 CodeGenerator::Finalize(allocator);
4941}
4942
4943/**
4944 * Class to handle late fixup of offsets into constant area.
4945 */
4946class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
4947 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04004948 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04004949 : codegen_(codegen), offset_into_constant_area_(offset) {}
4950
4951 private:
4952 void Process(const MemoryRegion& region, int pos) OVERRIDE {
4953 // Patch the correct offset for the instruction. We use the address of the
4954 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
4955 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
4956 int relative_position = constant_offset - pos;
4957
4958 // Patch in the right value.
4959 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
4960 }
4961
Mark Mendell39dcf552015-04-09 20:42:42 -04004962 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04004963
4964 // Location in constant area that the fixup refers to.
4965 int offset_into_constant_area_;
4966};
4967
4968Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
4969 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
4970 return Address::RIP(fixup);
4971}
4972
4973Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
4974 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
4975 return Address::RIP(fixup);
4976}
4977
4978Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
4979 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
4980 return Address::RIP(fixup);
4981}
4982
4983Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
4984 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
4985 return Address::RIP(fixup);
4986}
4987
Roland Levillain4d027112015-07-01 15:41:14 +01004988#undef __
4989
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004990} // namespace x86_64
4991} // namespace art