blob: bf570f581beb2f92a2b237daf0bdbdf2377d194b [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 +010039static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010040static constexpr Register kMethodRegisterArgument = RDI;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010041
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000042static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000043static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010044
Mark Mendell24f2dfa2015-01-14 19:51:45 -050045static constexpr int kC2ConditionMask = 0x400;
46
Roland Levillain62a46b22015-06-01 18:24:13 +010047#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
Calin Juravle175dc732015-08-25 15:42:32 +010048#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010049
Andreas Gampe85b62f22015-09-09 13:15:38 -070050class NullCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010051 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010052 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010053
Alexandre Rames2ed20af2015-03-06 13:55:35 +000054 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010055 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000057 if (instruction_->CanThrowIntoCatchBlock()) {
58 // Live registers will be restored in the catch block if caught.
59 SaveLiveRegisters(codegen, instruction_->GetLocations());
60 }
Alexandre Rames8158f282015-08-07 10:26:17 +010061 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
62 instruction_,
63 instruction_->GetDexPc(),
64 this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065 }
66
Alexandre Rames8158f282015-08-07 10:26:17 +010067 bool IsFatal() const OVERRIDE { return true; }
68
Alexandre Rames9931f312015-06-19 14:47:01 +010069 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
70
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010072 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
74};
75
Andreas Gampe85b62f22015-09-09 13:15:38 -070076class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000077 public:
78 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
79
Alexandre Rames2ed20af2015-03-06 13:55:35 +000080 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010081 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000082 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000083 if (instruction_->CanThrowIntoCatchBlock()) {
84 // Live registers will be restored in the catch block if caught.
85 SaveLiveRegisters(codegen, instruction_->GetLocations());
86 }
Alexandre Rames8158f282015-08-07 10:26:17 +010087 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
88 instruction_,
89 instruction_->GetDexPc(),
90 this);
Calin Juravled0d48522014-11-04 16:40:20 +000091 }
92
Alexandre Rames8158f282015-08-07 10:26:17 +010093 bool IsFatal() const OVERRIDE { return true; }
94
Alexandre Rames9931f312015-06-19 14:47:01 +010095 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
96
Calin Juravled0d48522014-11-04 16:40:20 +000097 private:
98 HDivZeroCheck* const instruction_;
99 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
100};
101
Andreas Gampe85b62f22015-09-09 13:15:38 -0700102class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000103 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100104 DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
Calin Juravlebacfec32014-11-14 15:54:36 +0000105 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000106
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000107 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000108 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000109 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000110 if (is_div_) {
111 __ negl(cpu_reg_);
112 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400113 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000114 }
115
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000116 } else {
117 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000118 if (is_div_) {
119 __ negq(cpu_reg_);
120 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400121 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000122 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000123 }
Calin Juravled0d48522014-11-04 16:40:20 +0000124 __ jmp(GetExitLabel());
125 }
126
Alexandre Rames9931f312015-06-19 14:47:01 +0100127 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
128
Calin Juravled0d48522014-11-04 16:40:20 +0000129 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000130 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000131 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000132 const bool is_div_;
133 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000134};
135
Andreas Gampe85b62f22015-09-09 13:15:38 -0700136class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100138 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100139 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000141 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100142 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000144 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100145 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
146 instruction_,
147 instruction_->GetDexPc(),
148 this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000149 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100150 if (successor_ == nullptr) {
151 __ jmp(GetReturnLabel());
152 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100153 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100154 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000155 }
156
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100157 Label* GetReturnLabel() {
158 DCHECK(successor_ == nullptr);
159 return &return_label_;
160 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000161
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100162 HBasicBlock* GetSuccessor() const {
163 return successor_;
164 }
165
Alexandre Rames9931f312015-06-19 14:47:01 +0100166 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
167
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000168 private:
169 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100170 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000171 Label return_label_;
172
173 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
174};
175
Andreas Gampe85b62f22015-09-09 13:15:38 -0700176class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100177 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100178 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
179 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000181 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100182 LocationSummary* locations = instruction_->GetLocations();
Alexandre Rames8158f282015-08-07 10:26:17 +0100183 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100184 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000185 if (instruction_->CanThrowIntoCatchBlock()) {
186 // Live registers will be restored in the catch block if caught.
187 SaveLiveRegisters(codegen, instruction_->GetLocations());
188 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000189 // We're moving two locations to locations that could overlap, so we need a parallel
190 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100191 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000192 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100193 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000194 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100195 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100196 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100197 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
198 Primitive::kPrimInt);
Alexandre Rames8158f282015-08-07 10:26:17 +0100199 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
200 instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100201 }
202
Alexandre Rames8158f282015-08-07 10:26:17 +0100203 bool IsFatal() const OVERRIDE { return true; }
204
Alexandre Rames9931f312015-06-19 14:47:01 +0100205 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
206
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100207 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100208 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100209
210 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
211};
212
Andreas Gampe85b62f22015-09-09 13:15:38 -0700213class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100214 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 LoadClassSlowPathX86_64(HLoadClass* cls,
216 HInstruction* at,
217 uint32_t dex_pc,
218 bool do_clinit)
219 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
220 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
221 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100222
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000223 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100225 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
226 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100227
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000228 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000229
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000231 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100232 x64_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
233 : QUICK_ENTRY_POINT(pInitializeType),
234 at_, dex_pc_, this);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000236 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000238 if (out.IsValid()) {
239 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
240 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000241 }
242
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000243 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100244 __ jmp(GetExitLabel());
245 }
246
Alexandre Rames9931f312015-06-19 14:47:01 +0100247 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
248
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100249 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000250 // The class this slow path will load.
251 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100252
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000253 // The instruction where this slow path is happening.
254 // (Might be the load class or an initialization check).
255 HInstruction* const at_;
256
257 // The dex PC of `at_`.
258 const uint32_t dex_pc_;
259
260 // Whether to initialize the class.
261 const bool do_clinit_;
262
263 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100264};
265
Andreas Gampe85b62f22015-09-09 13:15:38 -0700266class LoadStringSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267 public:
268 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
269
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000270 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000271 LocationSummary* locations = instruction_->GetLocations();
272 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
273
274 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
275 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000276 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000277
278 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800279 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000280 Immediate(instruction_->GetStringIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100281 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
282 instruction_,
283 instruction_->GetDexPc(),
284 this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000285 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000286 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000287 __ jmp(GetExitLabel());
288 }
289
Alexandre Rames9931f312015-06-19 14:47:01 +0100290 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
291
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000292 private:
293 HLoadString* const instruction_;
294
295 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
296};
297
Andreas Gampe85b62f22015-09-09 13:15:38 -0700298class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000300 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
301 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000302
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000303 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000304 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100305 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
306 : locations->Out();
307 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000308 DCHECK(instruction_->IsCheckCast()
309 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310
311 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
312 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000313
314 if (instruction_->IsCheckCast()) {
315 // The codegen for the instruction overwrites `temp`, so put it back in place.
316 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
317 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
318 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
319 __ movl(temp, Address(obj, class_offset));
320 __ MaybeUnpoisonHeapReference(temp);
321 }
322
323 if (!is_fatal_) {
324 SaveLiveRegisters(codegen, locations);
325 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000326
327 // We're moving two locations to locations that could overlap, so we need a parallel
328 // move resolver.
329 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000330 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100331 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000332 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100333 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100334 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100335 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
336 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000337
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000338 if (instruction_->IsInstanceOf()) {
Alexandre Rames8158f282015-08-07 10:26:17 +0100339 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
340 instruction_,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100341 dex_pc,
Alexandre Rames8158f282015-08-07 10:26:17 +0100342 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000343 } else {
344 DCHECK(instruction_->IsCheckCast());
Alexandre Rames8158f282015-08-07 10:26:17 +0100345 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
346 instruction_,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100347 dex_pc,
Alexandre Rames8158f282015-08-07 10:26:17 +0100348 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000349 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000350
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000351 if (!is_fatal_) {
352 if (instruction_->IsInstanceOf()) {
353 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
354 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000355
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000356 RestoreLiveRegisters(codegen, locations);
357 __ jmp(GetExitLabel());
358 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000359 }
360
Alexandre Rames9931f312015-06-19 14:47:01 +0100361 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
362
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000363 bool IsFatal() const OVERRIDE { return is_fatal_; }
364
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000365 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000366 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000367 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000368
369 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
370};
371
Andreas Gampe85b62f22015-09-09 13:15:38 -0700372class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700373 public:
374 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
375 : instruction_(instruction) {}
376
377 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100378 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700379 __ Bind(GetEntryLabel());
380 SaveLiveRegisters(codegen, instruction_->GetLocations());
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700381 DCHECK(instruction_->IsDeoptimize());
382 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
Alexandre Rames8158f282015-08-07 10:26:17 +0100383 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
384 deoptimize,
385 deoptimize->GetDexPc(),
386 this);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700387 }
388
Alexandre Rames9931f312015-06-19 14:47:01 +0100389 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
390
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700391 private:
392 HInstruction* const instruction_;
393 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
394};
395
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100396class ArraySetSlowPathX86_64 : public SlowPathCode {
397 public:
398 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : instruction_(instruction) {}
399
400 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
401 LocationSummary* locations = instruction_->GetLocations();
402 __ Bind(GetEntryLabel());
403 SaveLiveRegisters(codegen, locations);
404
405 InvokeRuntimeCallingConvention calling_convention;
406 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
407 parallel_move.AddMove(
408 locations->InAt(0),
409 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
410 Primitive::kPrimNot,
411 nullptr);
412 parallel_move.AddMove(
413 locations->InAt(1),
414 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
415 Primitive::kPrimInt,
416 nullptr);
417 parallel_move.AddMove(
418 locations->InAt(2),
419 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
420 Primitive::kPrimNot,
421 nullptr);
422 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
423
424 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
425 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
426 instruction_,
427 instruction_->GetDexPc(),
428 this);
429 RestoreLiveRegisters(codegen, locations);
430 __ jmp(GetExitLabel());
431 }
432
433 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86_64"; }
434
435 private:
436 HInstruction* const instruction_;
437
438 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
439};
440
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100441#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100442#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100443
Roland Levillain4fa13f62015-07-06 18:11:54 +0100444inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700445 switch (cond) {
446 case kCondEQ: return kEqual;
447 case kCondNE: return kNotEqual;
448 case kCondLT: return kLess;
449 case kCondLE: return kLessEqual;
450 case kCondGT: return kGreater;
451 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700452 case kCondB: return kBelow;
453 case kCondBE: return kBelowEqual;
454 case kCondA: return kAbove;
455 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700456 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100457 LOG(FATAL) << "Unreachable";
458 UNREACHABLE();
459}
460
Aart Bike9f37602015-10-09 11:15:55 -0700461// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100462inline Condition X86_64FPCondition(IfCondition cond) {
463 switch (cond) {
464 case kCondEQ: return kEqual;
465 case kCondNE: return kNotEqual;
466 case kCondLT: return kBelow;
467 case kCondLE: return kBelowEqual;
468 case kCondGT: return kAbove;
469 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700470 default: break; // should not happen
Roland Levillain4fa13f62015-07-06 18:11:54 +0100471 };
472 LOG(FATAL) << "Unreachable";
473 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700474}
475
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800476void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100477 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800478 // All registers are assumed to be correctly set up.
479
Vladimir Marko58155012015-08-19 12:49:41 +0000480 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
481 switch (invoke->GetMethodLoadKind()) {
482 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
483 // temp = thread->string_init_entrypoint
484 __ gs()->movl(temp.AsRegister<CpuRegister>(),
485 Address::Absolute(invoke->GetStringInitOffset(), true));
486 break;
487 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
488 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
489 break;
490 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
491 __ movq(temp.AsRegister<CpuRegister>(), Immediate(invoke->GetMethodAddress()));
492 break;
493 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
494 __ movl(temp.AsRegister<CpuRegister>(), Immediate(0)); // Placeholder.
495 method_patches_.emplace_back(invoke->GetTargetMethod());
496 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
497 break;
498 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
499 pc_rel_dex_cache_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
500 invoke->GetDexCacheArrayOffset());
501 __ movq(temp.AsRegister<CpuRegister>(),
502 Address::Absolute(kDummy32BitOffset, false /* no_rip */));
503 // Bind the label at the end of the "movl" insn.
504 __ Bind(&pc_rel_dex_cache_patches_.back().label);
505 break;
506 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
507 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
508 Register method_reg;
509 CpuRegister reg = temp.AsRegister<CpuRegister>();
510 if (current_method.IsRegister()) {
511 method_reg = current_method.AsRegister<Register>();
512 } else {
513 DCHECK(invoke->GetLocations()->Intrinsified());
514 DCHECK(!current_method.IsValid());
515 method_reg = reg.AsRegister();
516 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
517 }
518 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +0100519 __ movq(reg,
520 Address(CpuRegister(method_reg),
521 ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +0000522 // temp = temp[index_in_cache]
523 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
524 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
525 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +0100526 }
Vladimir Marko58155012015-08-19 12:49:41 +0000527 }
528
529 switch (invoke->GetCodePtrLocation()) {
530 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
531 __ call(&frame_entry_label_);
532 break;
533 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
534 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
535 Label* label = &relative_call_patches_.back().label;
536 __ call(label); // Bind to the patch label, override at link time.
537 __ Bind(label); // Bind the label at the end of the "call" insn.
538 break;
539 }
540 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
541 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
542 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
543 FALLTHROUGH_INTENDED;
544 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
545 // (callee_method + offset_of_quick_compiled_code)()
546 __ call(Address(callee_method.AsRegister<CpuRegister>(),
547 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
548 kX86_64WordSize).SizeValue()));
549 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000550 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800551
552 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800553}
554
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000555void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
556 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
557 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
558 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
559 LocationSummary* locations = invoke->GetLocations();
560 Location receiver = locations->InAt(0);
561 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
562 // temp = object->GetClass();
563 DCHECK(receiver.IsRegister());
564 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
565 MaybeRecordImplicitNullCheck(invoke);
566 __ MaybeUnpoisonHeapReference(temp);
567 // temp = temp->GetMethodAt(method_offset);
568 __ movq(temp, Address(temp, method_offset));
569 // call temp->GetEntryPoint();
570 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
571 kX86_64WordSize).SizeValue()));
572}
573
Vladimir Marko58155012015-08-19 12:49:41 +0000574void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
575 DCHECK(linker_patches->empty());
576 size_t size =
577 method_patches_.size() + relative_call_patches_.size() + pc_rel_dex_cache_patches_.size();
578 linker_patches->reserve(size);
579 for (const MethodPatchInfo<Label>& info : method_patches_) {
580 // The label points to the end of the "movl" instruction but the literal offset for method
581 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
582 uint32_t literal_offset = info.label.Position() - 4;
583 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
584 info.target_method.dex_file,
585 info.target_method.dex_method_index));
586 }
587 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
588 // The label points to the end of the "call" instruction but the literal offset for method
589 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
590 uint32_t literal_offset = info.label.Position() - 4;
591 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
592 info.target_method.dex_file,
593 info.target_method.dex_method_index));
594 }
595 for (const PcRelativeDexCacheAccessInfo& info : pc_rel_dex_cache_patches_) {
596 // The label points to the end of the "mov" instruction but the literal offset for method
597 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
598 uint32_t literal_offset = info.label.Position() - 4;
599 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
600 &info.target_dex_file,
601 info.label.Position(),
602 info.element_offset));
603 }
604}
605
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100606void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100607 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100608}
609
610void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100611 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100612}
613
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100614size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
615 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
616 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100617}
618
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100619size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
620 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
621 return kX86_64WordSize;
622}
623
624size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
625 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
626 return kX86_64WordSize;
627}
628
629size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
630 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
631 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100632}
633
Calin Juravle175dc732015-08-25 15:42:32 +0100634void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
635 HInstruction* instruction,
636 uint32_t dex_pc,
637 SlowPathCode* slow_path) {
638 InvokeRuntime(GetThreadOffset<kX86_64WordSize>(entrypoint).Int32Value(),
639 instruction,
640 dex_pc,
641 slow_path);
642}
643
644void CodeGeneratorX86_64::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100645 HInstruction* instruction,
646 uint32_t dex_pc,
647 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100648 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100649 __ gs()->call(Address::Absolute(entry_point_offset, true));
Alexandre Rames8158f282015-08-07 10:26:17 +0100650 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100651}
652
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000653static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000654// Use a fake return address register to mimic Quick.
655static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400656CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
657 const X86_64InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100658 const CompilerOptions& compiler_options,
659 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000660 : CodeGenerator(graph,
661 kNumberOfCpuRegisters,
662 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000663 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000664 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
665 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000666 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000667 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
668 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100669 compiler_options,
670 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100671 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100672 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000673 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400674 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400675 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000676 constant_area_start_(0),
Vladimir Marko5233f932015-09-29 19:01:15 +0100677 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
678 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Mark Mendell9c86b482015-09-18 13:36:07 -0400679 pc_rel_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
680 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000681 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
682}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100683
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100684InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
685 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100686 : HGraphVisitor(graph),
687 assembler_(codegen->GetAssembler()),
688 codegen_(codegen) {}
689
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100690Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100691 switch (type) {
692 case Primitive::kPrimLong:
693 case Primitive::kPrimByte:
694 case Primitive::kPrimBoolean:
695 case Primitive::kPrimChar:
696 case Primitive::kPrimShort:
697 case Primitive::kPrimInt:
698 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100699 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100700 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100701 }
702
703 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100704 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100705 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100706 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100707 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100708
709 case Primitive::kPrimVoid:
710 LOG(FATAL) << "Unreachable type " << type;
711 }
712
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100713 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100714}
715
Nicolas Geoffray98893962015-01-21 12:32:32 +0000716void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100717 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100718 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100719
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000720 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100721 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000722
Nicolas Geoffray98893962015-01-21 12:32:32 +0000723 if (is_baseline) {
724 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
725 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
726 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000727 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
728 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
729 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000730 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100731}
732
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100733static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100734 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100735}
David Srbecky9d8606d2015-04-12 09:35:32 +0100736
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100737static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100738 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100739}
740
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100741void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100742 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000743 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100744 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700745 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000746 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100747
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000748 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100749 __ testq(CpuRegister(RAX), Address(
750 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100751 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100752 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000753
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000754 if (HasEmptyFrame()) {
755 return;
756 }
757
Nicolas Geoffray98893962015-01-21 12:32:32 +0000758 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000759 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000760 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000761 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100762 __ cfi().AdjustCFAOffset(kX86_64WordSize);
763 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000764 }
765 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100766
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100767 int adjust = GetFrameSize() - GetCoreSpillSize();
768 __ subq(CpuRegister(RSP), Immediate(adjust));
769 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000770 uint32_t xmm_spill_location = GetFpuSpillStart();
771 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100772
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000773 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
774 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100775 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
776 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
777 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000778 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100779 }
780
Mathieu Chartiere401d142015-04-22 13:56:20 -0700781 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100782 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100783}
784
785void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100786 __ cfi().RememberState();
787 if (!HasEmptyFrame()) {
788 uint32_t xmm_spill_location = GetFpuSpillStart();
789 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
790 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
791 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
792 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
793 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
794 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
795 }
796 }
797
798 int adjust = GetFrameSize() - GetCoreSpillSize();
799 __ addq(CpuRegister(RSP), Immediate(adjust));
800 __ cfi().AdjustCFAOffset(-adjust);
801
802 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
803 Register reg = kCoreCalleeSaves[i];
804 if (allocated_registers_.ContainsCoreRegister(reg)) {
805 __ popq(CpuRegister(reg));
806 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
807 __ cfi().Restore(DWARFReg(reg));
808 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000809 }
810 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100811 __ ret();
812 __ cfi().RestoreState();
813 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100814}
815
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100816void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
817 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100818}
819
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100820Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
821 switch (load->GetType()) {
822 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100823 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100824 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100825
826 case Primitive::kPrimInt:
827 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100828 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100829 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100830
831 case Primitive::kPrimBoolean:
832 case Primitive::kPrimByte:
833 case Primitive::kPrimChar:
834 case Primitive::kPrimShort:
835 case Primitive::kPrimVoid:
836 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700837 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100838 }
839
840 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700841 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100842}
843
844void CodeGeneratorX86_64::Move(Location destination, Location source) {
845 if (source.Equals(destination)) {
846 return;
847 }
848 if (destination.IsRegister()) {
849 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000850 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100851 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000852 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100853 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000854 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100855 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100856 } else {
857 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000858 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100859 Address(CpuRegister(RSP), source.GetStackIndex()));
860 }
861 } else if (destination.IsFpuRegister()) {
862 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000863 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100864 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000865 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000867 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100868 Address(CpuRegister(RSP), source.GetStackIndex()));
869 } else {
870 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000871 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100872 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100873 }
874 } else if (destination.IsStackSlot()) {
875 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100876 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000877 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100878 } else if (source.IsFpuRegister()) {
879 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000880 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500881 } else if (source.IsConstant()) {
882 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000883 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500884 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100885 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500886 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000887 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
888 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100889 }
890 } else {
891 DCHECK(destination.IsDoubleStackSlot());
892 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100893 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000894 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100895 } else if (source.IsFpuRegister()) {
896 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000897 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500898 } else if (source.IsConstant()) {
899 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800900 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500901 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000902 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500903 } else {
904 DCHECK(constant->IsLongConstant());
905 value = constant->AsLongConstant()->GetValue();
906 }
Mark Mendellcfa410b2015-05-25 16:02:44 -0400907 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100908 } else {
909 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000910 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
911 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100912 }
913 }
914}
915
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100916void CodeGeneratorX86_64::Move(HInstruction* instruction,
917 Location location,
918 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000919 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100920 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700921 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100922 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000923 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100924 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000925 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000926 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
927 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000928 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000929 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000930 } else if (location.IsStackSlot()) {
931 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
932 } else {
933 DCHECK(location.IsConstant());
934 DCHECK_EQ(location.GetConstant(), const_to_move);
935 }
936 } else if (const_to_move->IsLongConstant()) {
937 int64_t value = const_to_move->AsLongConstant()->GetValue();
938 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400939 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000940 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400941 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000942 } else {
943 DCHECK(location.IsConstant());
944 DCHECK_EQ(location.GetConstant(), const_to_move);
945 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100946 }
Roland Levillain476df552014-10-09 17:51:36 +0100947 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100948 switch (instruction->GetType()) {
949 case Primitive::kPrimBoolean:
950 case Primitive::kPrimByte:
951 case Primitive::kPrimChar:
952 case Primitive::kPrimShort:
953 case Primitive::kPrimInt:
954 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100955 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100956 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
957 break;
958
959 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100960 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000961 Move(location,
962 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100963 break;
964
965 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100966 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100967 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000968 } else if (instruction->IsTemporary()) {
969 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
970 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100971 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100972 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100973 switch (instruction->GetType()) {
974 case Primitive::kPrimBoolean:
975 case Primitive::kPrimByte:
976 case Primitive::kPrimChar:
977 case Primitive::kPrimShort:
978 case Primitive::kPrimInt:
979 case Primitive::kPrimNot:
980 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100981 case Primitive::kPrimFloat:
982 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000983 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100984 break;
985
986 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100987 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100988 }
989 }
990}
991
Calin Juravle175dc732015-08-25 15:42:32 +0100992void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
993 DCHECK(location.IsRegister());
994 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
995}
996
Calin Juravlee460d1d2015-09-29 04:52:17 +0100997void CodeGeneratorX86_64::MoveLocation(
998 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
999 Move(dst, src);
1000}
1001
1002void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1003 if (location.IsRegister()) {
1004 locations->AddTemp(location);
1005 } else {
1006 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1007 }
1008}
1009
David Brazdilfc6a86a2015-06-26 10:33:45 +00001010void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001011 DCHECK(!successor->IsExitBlock());
1012
1013 HBasicBlock* block = got->GetBlock();
1014 HInstruction* previous = got->GetPrevious();
1015
1016 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001017 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001018 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1019 return;
1020 }
1021
1022 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1023 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1024 }
1025 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001026 __ jmp(codegen_->GetLabelOf(successor));
1027 }
1028}
1029
David Brazdilfc6a86a2015-06-26 10:33:45 +00001030void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1031 got->SetLocations(nullptr);
1032}
1033
1034void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1035 HandleGoto(got, got->GetSuccessor());
1036}
1037
1038void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1039 try_boundary->SetLocations(nullptr);
1040}
1041
1042void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1043 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1044 if (!successor->IsExitBlock()) {
1045 HandleGoto(try_boundary, successor);
1046 }
1047}
1048
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001049void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1050 exit->SetLocations(nullptr);
1051}
1052
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001053void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001054}
1055
Mark Mendellc4701932015-04-10 13:18:51 -04001056void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
1057 Label* true_label,
1058 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001059 if (cond->IsFPConditionTrueIfNaN()) {
1060 __ j(kUnordered, true_label);
1061 } else if (cond->IsFPConditionFalseIfNaN()) {
1062 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001063 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001064 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001065}
1066
1067void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
1068 HCondition* condition,
1069 Label* true_target,
1070 Label* false_target,
1071 Label* always_true_target) {
1072 LocationSummary* locations = condition->GetLocations();
1073 Location left = locations->InAt(0);
1074 Location right = locations->InAt(1);
1075
1076 // We don't want true_target as a nullptr.
1077 if (true_target == nullptr) {
1078 true_target = always_true_target;
1079 }
1080 bool falls_through = (false_target == nullptr);
1081
1082 // FP compares don't like null false_targets.
1083 if (false_target == nullptr) {
1084 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1085 }
1086
1087 Primitive::Type type = condition->InputAt(0)->GetType();
1088 switch (type) {
1089 case Primitive::kPrimLong: {
1090 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1091 if (right.IsConstant()) {
1092 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1093 if (IsInt<32>(value)) {
1094 if (value == 0) {
1095 __ testq(left_reg, left_reg);
1096 } else {
1097 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1098 }
1099 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001100 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -04001101 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
1102 }
1103 } else if (right.IsDoubleStackSlot()) {
1104 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1105 } else {
1106 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1107 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001108 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -04001109 break;
1110 }
1111 case Primitive::kPrimFloat: {
1112 if (right.IsFpuRegister()) {
1113 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1114 } else if (right.IsConstant()) {
1115 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1116 codegen_->LiteralFloatAddress(
1117 right.GetConstant()->AsFloatConstant()->GetValue()));
1118 } else {
1119 DCHECK(right.IsStackSlot());
1120 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1121 Address(CpuRegister(RSP), right.GetStackIndex()));
1122 }
1123 GenerateFPJumps(condition, true_target, false_target);
1124 break;
1125 }
1126 case Primitive::kPrimDouble: {
1127 if (right.IsFpuRegister()) {
1128 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1129 } else if (right.IsConstant()) {
1130 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1131 codegen_->LiteralDoubleAddress(
1132 right.GetConstant()->AsDoubleConstant()->GetValue()));
1133 } else {
1134 DCHECK(right.IsDoubleStackSlot());
1135 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1136 Address(CpuRegister(RSP), right.GetStackIndex()));
1137 }
1138 GenerateFPJumps(condition, true_target, false_target);
1139 break;
1140 }
1141 default:
1142 LOG(FATAL) << "Unexpected condition type " << type;
1143 }
1144
1145 if (!falls_through) {
1146 __ jmp(false_target);
1147 }
1148}
1149
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001150void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
1151 Label* true_target,
1152 Label* false_target,
1153 Label* always_true_target) {
1154 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001155 if (cond->IsIntConstant()) {
1156 // Constant condition, statically compared against 1.
1157 int32_t cond_value = cond->AsIntConstant()->GetValue();
1158 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001159 if (always_true_target != nullptr) {
1160 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001161 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001162 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001163 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001164 DCHECK_EQ(cond_value, 0);
1165 }
1166 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001167 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001168 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1169 // Moves do not affect the eflags register, so if the condition is
1170 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001171 // again. We can't use the eflags on FP conditions if they are
1172 // materialized due to the complex branching.
1173 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001174 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001175 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
1176 && !Primitive::IsFloatingPointType(type);
1177
Roland Levillain4fa13f62015-07-06 18:11:54 +01001178 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001179 if (!eflags_set) {
1180 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001181 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001182 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001183 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001184 } else {
1185 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
1186 Immediate(0));
1187 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001188 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001189 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001190 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001191 }
1192 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001193 // Condition has not been materialized, use its inputs as the
1194 // comparison and its condition as the branch condition.
1195
Mark Mendellc4701932015-04-10 13:18:51 -04001196 // Is this a long or FP comparison that has been folded into the HCondition?
1197 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001198 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -04001199 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1200 true_target, false_target, always_true_target);
1201 return;
1202 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001203
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001204 Location lhs = cond->GetLocations()->InAt(0);
1205 Location rhs = cond->GetLocations()->InAt(1);
1206 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001207 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001208 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001209 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001210 if (constant == 0) {
1211 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1212 } else {
1213 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1214 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001215 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001216 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001217 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1218 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001219 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001220 }
Dave Allison20dfc792014-06-16 20:44:29 -07001221 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001222 if (false_target != nullptr) {
1223 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001224 }
1225}
1226
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001227void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1228 LocationSummary* locations =
1229 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1230 HInstruction* cond = if_instr->InputAt(0);
1231 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1232 locations->SetInAt(0, Location::Any());
1233 }
1234}
1235
1236void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1237 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1238 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1239 Label* always_true_target = true_target;
1240 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1241 if_instr->IfTrueSuccessor())) {
1242 always_true_target = nullptr;
1243 }
1244 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1245 if_instr->IfFalseSuccessor())) {
1246 false_target = nullptr;
1247 }
1248 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1249}
1250
1251void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1252 LocationSummary* locations = new (GetGraph()->GetArena())
1253 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1254 HInstruction* cond = deoptimize->InputAt(0);
1255 DCHECK(cond->IsCondition());
1256 if (cond->AsCondition()->NeedsMaterialization()) {
1257 locations->SetInAt(0, Location::Any());
1258 }
1259}
1260
1261void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001262 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001263 DeoptimizationSlowPathX86_64(deoptimize);
1264 codegen_->AddSlowPath(slow_path);
1265 Label* slow_path_entry = slow_path->GetEntryLabel();
1266 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1267}
1268
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001269void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1270 local->SetLocations(nullptr);
1271}
1272
1273void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1274 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1275}
1276
1277void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1278 local->SetLocations(nullptr);
1279}
1280
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001281void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001282 // Nothing to do, this is driven by the code generator.
1283}
1284
1285void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001286 LocationSummary* locations =
1287 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001288 switch (store->InputAt(1)->GetType()) {
1289 case Primitive::kPrimBoolean:
1290 case Primitive::kPrimByte:
1291 case Primitive::kPrimChar:
1292 case Primitive::kPrimShort:
1293 case Primitive::kPrimInt:
1294 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001295 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001296 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1297 break;
1298
1299 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001300 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001301 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1302 break;
1303
1304 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001305 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001306 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001307}
1308
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001309void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001310}
1311
Roland Levillain0d37cd02015-05-27 16:39:19 +01001312void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001313 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001314 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001315 // Handle the long/FP comparisons made in instruction simplification.
1316 switch (cond->InputAt(0)->GetType()) {
1317 case Primitive::kPrimLong:
1318 locations->SetInAt(0, Location::RequiresRegister());
1319 locations->SetInAt(1, Location::Any());
1320 break;
1321 case Primitive::kPrimFloat:
1322 case Primitive::kPrimDouble:
1323 locations->SetInAt(0, Location::RequiresFpuRegister());
1324 locations->SetInAt(1, Location::Any());
1325 break;
1326 default:
1327 locations->SetInAt(0, Location::RequiresRegister());
1328 locations->SetInAt(1, Location::Any());
1329 break;
1330 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001331 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001332 locations->SetOut(Location::RequiresRegister());
1333 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001334}
1335
Roland Levillain0d37cd02015-05-27 16:39:19 +01001336void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001337 if (!cond->NeedsMaterialization()) {
1338 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001339 }
Mark Mendellc4701932015-04-10 13:18:51 -04001340
1341 LocationSummary* locations = cond->GetLocations();
1342 Location lhs = locations->InAt(0);
1343 Location rhs = locations->InAt(1);
1344 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1345 Label true_label, false_label;
1346
1347 switch (cond->InputAt(0)->GetType()) {
1348 default:
1349 // Integer case.
1350
1351 // Clear output register: setcc only sets the low byte.
1352 __ xorl(reg, reg);
1353
1354 if (rhs.IsRegister()) {
1355 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1356 } else if (rhs.IsConstant()) {
1357 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1358 if (constant == 0) {
1359 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1360 } else {
1361 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1362 }
1363 } else {
1364 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1365 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001366 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001367 return;
1368 case Primitive::kPrimLong:
1369 // Clear output register: setcc only sets the low byte.
1370 __ xorl(reg, reg);
1371
1372 if (rhs.IsRegister()) {
1373 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1374 } else if (rhs.IsConstant()) {
1375 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1376 if (IsInt<32>(value)) {
1377 if (value == 0) {
1378 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1379 } else {
1380 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1381 }
1382 } else {
1383 // Value won't fit in an int.
1384 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1385 }
1386 } else {
1387 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1388 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001389 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001390 return;
1391 case Primitive::kPrimFloat: {
1392 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1393 if (rhs.IsConstant()) {
1394 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1395 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1396 } else if (rhs.IsStackSlot()) {
1397 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1398 } else {
1399 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1400 }
1401 GenerateFPJumps(cond, &true_label, &false_label);
1402 break;
1403 }
1404 case Primitive::kPrimDouble: {
1405 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1406 if (rhs.IsConstant()) {
1407 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1408 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1409 } else if (rhs.IsDoubleStackSlot()) {
1410 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1411 } else {
1412 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1413 }
1414 GenerateFPJumps(cond, &true_label, &false_label);
1415 break;
1416 }
1417 }
1418
1419 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001420 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001421
Roland Levillain4fa13f62015-07-06 18:11:54 +01001422 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001423 __ Bind(&false_label);
1424 __ xorl(reg, reg);
1425 __ jmp(&done_label);
1426
Roland Levillain4fa13f62015-07-06 18:11:54 +01001427 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001428 __ Bind(&true_label);
1429 __ movl(reg, Immediate(1));
1430 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001431}
1432
1433void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1434 VisitCondition(comp);
1435}
1436
1437void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1438 VisitCondition(comp);
1439}
1440
1441void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1442 VisitCondition(comp);
1443}
1444
1445void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1446 VisitCondition(comp);
1447}
1448
1449void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1450 VisitCondition(comp);
1451}
1452
1453void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1454 VisitCondition(comp);
1455}
1456
1457void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1458 VisitCondition(comp);
1459}
1460
1461void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1462 VisitCondition(comp);
1463}
1464
1465void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1466 VisitCondition(comp);
1467}
1468
1469void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1470 VisitCondition(comp);
1471}
1472
1473void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1474 VisitCondition(comp);
1475}
1476
1477void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1478 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001479}
1480
Aart Bike9f37602015-10-09 11:15:55 -07001481void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
1482 VisitCondition(comp);
1483}
1484
1485void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
1486 VisitCondition(comp);
1487}
1488
1489void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1490 VisitCondition(comp);
1491}
1492
1493void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1494 VisitCondition(comp);
1495}
1496
1497void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
1498 VisitCondition(comp);
1499}
1500
1501void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
1502 VisitCondition(comp);
1503}
1504
1505void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1506 VisitCondition(comp);
1507}
1508
1509void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1510 VisitCondition(comp);
1511}
1512
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001513void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001514 LocationSummary* locations =
1515 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001516 switch (compare->InputAt(0)->GetType()) {
1517 case Primitive::kPrimLong: {
1518 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001519 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001520 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1521 break;
1522 }
1523 case Primitive::kPrimFloat:
1524 case Primitive::kPrimDouble: {
1525 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001526 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001527 locations->SetOut(Location::RequiresRegister());
1528 break;
1529 }
1530 default:
1531 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1532 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001533}
1534
1535void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001536 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001537 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001538 Location left = locations->InAt(0);
1539 Location right = locations->InAt(1);
1540
Mark Mendell0c9497d2015-08-21 09:30:05 -04001541 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00001542 Primitive::Type type = compare->InputAt(0)->GetType();
1543 switch (type) {
1544 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001545 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1546 if (right.IsConstant()) {
1547 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001548 if (IsInt<32>(value)) {
1549 if (value == 0) {
1550 __ testq(left_reg, left_reg);
1551 } else {
1552 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1553 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001554 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001555 // Value won't fit in an int.
1556 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001557 }
Mark Mendell40741f32015-04-20 22:10:34 -04001558 } else if (right.IsDoubleStackSlot()) {
1559 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001560 } else {
1561 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1562 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001563 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001564 }
1565 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001566 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1567 if (right.IsConstant()) {
1568 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1569 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1570 } else if (right.IsStackSlot()) {
1571 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1572 } else {
1573 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1574 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001575 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1576 break;
1577 }
1578 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001579 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1580 if (right.IsConstant()) {
1581 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1582 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1583 } else if (right.IsDoubleStackSlot()) {
1584 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1585 } else {
1586 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1587 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001588 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1589 break;
1590 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001591 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001592 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001593 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001594 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001595 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001596 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001597
Calin Juravle91debbc2014-11-26 19:01:09 +00001598 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001599 __ movl(out, Immediate(1));
1600 __ jmp(&done);
1601
1602 __ Bind(&less);
1603 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001604
1605 __ Bind(&done);
1606}
1607
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001608void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001609 LocationSummary* locations =
1610 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001611 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001612}
1613
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001614void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001615 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001616}
1617
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001618void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1619 LocationSummary* locations =
1620 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1621 locations->SetOut(Location::ConstantLocation(constant));
1622}
1623
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001624void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001625 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001626}
1627
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001628void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001629 LocationSummary* locations =
1630 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001631 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001632}
1633
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001634void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001635 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001636}
1637
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001638void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1639 LocationSummary* locations =
1640 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1641 locations->SetOut(Location::ConstantLocation(constant));
1642}
1643
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001644void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001645 // Will be generated at use site.
1646}
1647
1648void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1649 LocationSummary* locations =
1650 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1651 locations->SetOut(Location::ConstantLocation(constant));
1652}
1653
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001654void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
1655 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001656 // Will be generated at use site.
1657}
1658
Calin Juravle27df7582015-04-17 19:12:31 +01001659void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1660 memory_barrier->SetLocations(nullptr);
1661}
1662
1663void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1664 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1665}
1666
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001667void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1668 ret->SetLocations(nullptr);
1669}
1670
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001671void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001672 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001673}
1674
1675void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001676 LocationSummary* locations =
1677 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001678 switch (ret->InputAt(0)->GetType()) {
1679 case Primitive::kPrimBoolean:
1680 case Primitive::kPrimByte:
1681 case Primitive::kPrimChar:
1682 case Primitive::kPrimShort:
1683 case Primitive::kPrimInt:
1684 case Primitive::kPrimNot:
1685 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001686 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001687 break;
1688
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001689 case Primitive::kPrimFloat:
1690 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001691 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001692 break;
1693
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001694 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001695 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001696 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001697}
1698
1699void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1700 if (kIsDebugBuild) {
1701 switch (ret->InputAt(0)->GetType()) {
1702 case Primitive::kPrimBoolean:
1703 case Primitive::kPrimByte:
1704 case Primitive::kPrimChar:
1705 case Primitive::kPrimShort:
1706 case Primitive::kPrimInt:
1707 case Primitive::kPrimNot:
1708 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001709 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001710 break;
1711
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001712 case Primitive::kPrimFloat:
1713 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001714 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001715 XMM0);
1716 break;
1717
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001718 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001719 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001720 }
1721 }
1722 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001723}
1724
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001725Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1726 switch (type) {
1727 case Primitive::kPrimBoolean:
1728 case Primitive::kPrimByte:
1729 case Primitive::kPrimChar:
1730 case Primitive::kPrimShort:
1731 case Primitive::kPrimInt:
1732 case Primitive::kPrimNot:
1733 case Primitive::kPrimLong:
1734 return Location::RegisterLocation(RAX);
1735
1736 case Primitive::kPrimVoid:
1737 return Location::NoLocation();
1738
1739 case Primitive::kPrimDouble:
1740 case Primitive::kPrimFloat:
1741 return Location::FpuRegisterLocation(XMM0);
1742 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001743
1744 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001745}
1746
1747Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1748 return Location::RegisterLocation(kMethodRegisterArgument);
1749}
1750
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001751Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001752 switch (type) {
1753 case Primitive::kPrimBoolean:
1754 case Primitive::kPrimByte:
1755 case Primitive::kPrimChar:
1756 case Primitive::kPrimShort:
1757 case Primitive::kPrimInt:
1758 case Primitive::kPrimNot: {
1759 uint32_t index = gp_index_++;
1760 stack_index_++;
1761 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001762 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001763 } else {
1764 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1765 }
1766 }
1767
1768 case Primitive::kPrimLong: {
1769 uint32_t index = gp_index_;
1770 stack_index_ += 2;
1771 if (index < calling_convention.GetNumberOfRegisters()) {
1772 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001773 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001774 } else {
1775 gp_index_ += 2;
1776 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1777 }
1778 }
1779
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001780 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001781 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001782 stack_index_++;
1783 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001784 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001785 } else {
1786 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1787 }
1788 }
1789
1790 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001791 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001792 stack_index_ += 2;
1793 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001794 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001795 } else {
1796 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1797 }
1798 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001799
1800 case Primitive::kPrimVoid:
1801 LOG(FATAL) << "Unexpected parameter type " << type;
1802 break;
1803 }
1804 return Location();
1805}
1806
Calin Juravle175dc732015-08-25 15:42:32 +01001807void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1808 // The trampoline uses the same calling convention as dex calling conventions,
1809 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1810 // the method_idx.
1811 HandleInvoke(invoke);
1812}
1813
1814void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1815 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1816}
1817
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001818void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001819 // When we do not run baseline, explicit clinit checks triggered by static
1820 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1821 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001822
Mark Mendellfb8d2792015-03-31 22:16:59 -04001823 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001824 if (intrinsic.TryDispatch(invoke)) {
1825 return;
1826 }
1827
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001828 HandleInvoke(invoke);
1829}
1830
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001831static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1832 if (invoke->GetLocations()->Intrinsified()) {
1833 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1834 intrinsic.Dispatch(invoke);
1835 return true;
1836 }
1837 return false;
1838}
1839
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001840void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001841 // When we do not run baseline, explicit clinit checks triggered by static
1842 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1843 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001844
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001845 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1846 return;
1847 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001848
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001849 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001850 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001851 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001852 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001853}
1854
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001855void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001856 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001857 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001858}
1859
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001860void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001861 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001862 if (intrinsic.TryDispatch(invoke)) {
1863 return;
1864 }
1865
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001866 HandleInvoke(invoke);
1867}
1868
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001869void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001870 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1871 return;
1872 }
1873
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001874 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001875
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001876 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001877 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001878}
1879
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001880void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1881 HandleInvoke(invoke);
1882 // Add the hidden argument.
1883 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1884}
1885
1886void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1887 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001888 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001889 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1890 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001891 LocationSummary* locations = invoke->GetLocations();
1892 Location receiver = locations->InAt(0);
1893 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1894
1895 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001896 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1897 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001898
1899 // temp = object->GetClass();
1900 if (receiver.IsStackSlot()) {
1901 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1902 __ movl(temp, Address(temp, class_offset));
1903 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001904 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001905 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001906 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001907 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001908 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001909 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001910 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001911 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001912 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001913
1914 DCHECK(!codegen_->IsLeafMethod());
1915 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1916}
1917
Roland Levillain88cb1752014-10-20 16:36:47 +01001918void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1919 LocationSummary* locations =
1920 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1921 switch (neg->GetResultType()) {
1922 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001923 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001924 locations->SetInAt(0, Location::RequiresRegister());
1925 locations->SetOut(Location::SameAsFirstInput());
1926 break;
1927
Roland Levillain88cb1752014-10-20 16:36:47 +01001928 case Primitive::kPrimFloat:
1929 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001930 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001931 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001932 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001933 break;
1934
1935 default:
1936 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1937 }
1938}
1939
1940void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1941 LocationSummary* locations = neg->GetLocations();
1942 Location out = locations->Out();
1943 Location in = locations->InAt(0);
1944 switch (neg->GetResultType()) {
1945 case Primitive::kPrimInt:
1946 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001947 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001948 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001949 break;
1950
1951 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001952 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001953 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001954 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001955 break;
1956
Roland Levillain5368c212014-11-27 15:03:41 +00001957 case Primitive::kPrimFloat: {
1958 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001959 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001960 // Implement float negation with an exclusive or with value
1961 // 0x80000000 (mask for bit 31, representing the sign of a
1962 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001963 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001964 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001965 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001966 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001967
Roland Levillain5368c212014-11-27 15:03:41 +00001968 case Primitive::kPrimDouble: {
1969 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001970 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001971 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001972 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001973 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001974 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001975 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001976 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001977 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001978
1979 default:
1980 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1981 }
1982}
1983
Roland Levillaindff1f282014-11-05 14:15:05 +00001984void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1985 LocationSummary* locations =
1986 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1987 Primitive::Type result_type = conversion->GetResultType();
1988 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001989 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00001990
David Brazdilb2bd1c52015-03-25 11:17:37 +00001991 // The Java language does not allow treating boolean as an integral type but
1992 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001993
Roland Levillaindff1f282014-11-05 14:15:05 +00001994 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001995 case Primitive::kPrimByte:
1996 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001997 case Primitive::kPrimBoolean:
1998 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001999 case Primitive::kPrimShort:
2000 case Primitive::kPrimInt:
2001 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002002 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002003 locations->SetInAt(0, Location::Any());
2004 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2005 break;
2006
2007 default:
2008 LOG(FATAL) << "Unexpected type conversion from " << input_type
2009 << " to " << result_type;
2010 }
2011 break;
2012
Roland Levillain01a8d712014-11-14 16:27:39 +00002013 case Primitive::kPrimShort:
2014 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002015 case Primitive::kPrimBoolean:
2016 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002017 case Primitive::kPrimByte:
2018 case Primitive::kPrimInt:
2019 case Primitive::kPrimChar:
2020 // Processing a Dex `int-to-short' instruction.
2021 locations->SetInAt(0, Location::Any());
2022 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2023 break;
2024
2025 default:
2026 LOG(FATAL) << "Unexpected type conversion from " << input_type
2027 << " to " << result_type;
2028 }
2029 break;
2030
Roland Levillain946e1432014-11-11 17:35:19 +00002031 case Primitive::kPrimInt:
2032 switch (input_type) {
2033 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002034 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002035 locations->SetInAt(0, Location::Any());
2036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2037 break;
2038
2039 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002040 // Processing a Dex `float-to-int' instruction.
2041 locations->SetInAt(0, Location::RequiresFpuRegister());
2042 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002043 break;
2044
Roland Levillain946e1432014-11-11 17:35:19 +00002045 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002046 // Processing a Dex `double-to-int' instruction.
2047 locations->SetInAt(0, Location::RequiresFpuRegister());
2048 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002049 break;
2050
2051 default:
2052 LOG(FATAL) << "Unexpected type conversion from " << input_type
2053 << " to " << result_type;
2054 }
2055 break;
2056
Roland Levillaindff1f282014-11-05 14:15:05 +00002057 case Primitive::kPrimLong:
2058 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002059 case Primitive::kPrimBoolean:
2060 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002061 case Primitive::kPrimByte:
2062 case Primitive::kPrimShort:
2063 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002064 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002065 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002066 // TODO: We would benefit from a (to-be-implemented)
2067 // Location::RegisterOrStackSlot requirement for this input.
2068 locations->SetInAt(0, Location::RequiresRegister());
2069 locations->SetOut(Location::RequiresRegister());
2070 break;
2071
2072 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002073 // Processing a Dex `float-to-long' instruction.
2074 locations->SetInAt(0, Location::RequiresFpuRegister());
2075 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002076 break;
2077
Roland Levillaindff1f282014-11-05 14:15:05 +00002078 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002079 // Processing a Dex `double-to-long' instruction.
2080 locations->SetInAt(0, Location::RequiresFpuRegister());
2081 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002082 break;
2083
2084 default:
2085 LOG(FATAL) << "Unexpected type conversion from " << input_type
2086 << " to " << result_type;
2087 }
2088 break;
2089
Roland Levillain981e4542014-11-14 11:47:14 +00002090 case Primitive::kPrimChar:
2091 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002092 case Primitive::kPrimBoolean:
2093 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002094 case Primitive::kPrimByte:
2095 case Primitive::kPrimShort:
2096 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002097 // Processing a Dex `int-to-char' instruction.
2098 locations->SetInAt(0, Location::Any());
2099 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2100 break;
2101
2102 default:
2103 LOG(FATAL) << "Unexpected type conversion from " << input_type
2104 << " to " << result_type;
2105 }
2106 break;
2107
Roland Levillaindff1f282014-11-05 14:15:05 +00002108 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002109 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002110 case Primitive::kPrimBoolean:
2111 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002112 case Primitive::kPrimByte:
2113 case Primitive::kPrimShort:
2114 case Primitive::kPrimInt:
2115 case Primitive::kPrimChar:
2116 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002117 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002118 locations->SetOut(Location::RequiresFpuRegister());
2119 break;
2120
2121 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002122 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002123 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002124 locations->SetOut(Location::RequiresFpuRegister());
2125 break;
2126
Roland Levillaincff13742014-11-17 14:32:17 +00002127 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002128 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002129 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002130 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002131 break;
2132
2133 default:
2134 LOG(FATAL) << "Unexpected type conversion from " << input_type
2135 << " to " << result_type;
2136 };
2137 break;
2138
Roland Levillaindff1f282014-11-05 14:15:05 +00002139 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002140 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002141 case Primitive::kPrimBoolean:
2142 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002143 case Primitive::kPrimByte:
2144 case Primitive::kPrimShort:
2145 case Primitive::kPrimInt:
2146 case Primitive::kPrimChar:
2147 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002148 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002149 locations->SetOut(Location::RequiresFpuRegister());
2150 break;
2151
2152 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002153 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002154 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002155 locations->SetOut(Location::RequiresFpuRegister());
2156 break;
2157
Roland Levillaincff13742014-11-17 14:32:17 +00002158 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002159 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002160 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002161 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002162 break;
2163
2164 default:
2165 LOG(FATAL) << "Unexpected type conversion from " << input_type
2166 << " to " << result_type;
2167 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002168 break;
2169
2170 default:
2171 LOG(FATAL) << "Unexpected type conversion from " << input_type
2172 << " to " << result_type;
2173 }
2174}
2175
2176void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2177 LocationSummary* locations = conversion->GetLocations();
2178 Location out = locations->Out();
2179 Location in = locations->InAt(0);
2180 Primitive::Type result_type = conversion->GetResultType();
2181 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002182 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002183 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002184 case Primitive::kPrimByte:
2185 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002186 case Primitive::kPrimBoolean:
2187 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002188 case Primitive::kPrimShort:
2189 case Primitive::kPrimInt:
2190 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002191 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002192 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002193 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002194 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002195 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002196 Address(CpuRegister(RSP), in.GetStackIndex()));
2197 } else {
2198 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002199 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002200 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2201 }
2202 break;
2203
2204 default:
2205 LOG(FATAL) << "Unexpected type conversion from " << input_type
2206 << " to " << result_type;
2207 }
2208 break;
2209
Roland Levillain01a8d712014-11-14 16:27:39 +00002210 case Primitive::kPrimShort:
2211 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002212 case Primitive::kPrimBoolean:
2213 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002214 case Primitive::kPrimByte:
2215 case Primitive::kPrimInt:
2216 case Primitive::kPrimChar:
2217 // Processing a Dex `int-to-short' instruction.
2218 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002219 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002220 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002221 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002222 Address(CpuRegister(RSP), in.GetStackIndex()));
2223 } else {
2224 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002225 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002226 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2227 }
2228 break;
2229
2230 default:
2231 LOG(FATAL) << "Unexpected type conversion from " << input_type
2232 << " to " << result_type;
2233 }
2234 break;
2235
Roland Levillain946e1432014-11-11 17:35:19 +00002236 case Primitive::kPrimInt:
2237 switch (input_type) {
2238 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002239 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002240 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002241 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002242 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002243 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002244 Address(CpuRegister(RSP), in.GetStackIndex()));
2245 } else {
2246 DCHECK(in.IsConstant());
2247 DCHECK(in.GetConstant()->IsLongConstant());
2248 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002249 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002250 }
2251 break;
2252
Roland Levillain3f8f9362014-12-02 17:45:01 +00002253 case Primitive::kPrimFloat: {
2254 // Processing a Dex `float-to-int' instruction.
2255 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2256 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002257 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002258
2259 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002260 // if input >= (float)INT_MAX goto done
2261 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002262 __ j(kAboveEqual, &done);
2263 // if input == NaN goto nan
2264 __ j(kUnordered, &nan);
2265 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002266 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002267 __ jmp(&done);
2268 __ Bind(&nan);
2269 // output = 0
2270 __ xorl(output, output);
2271 __ Bind(&done);
2272 break;
2273 }
2274
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002275 case Primitive::kPrimDouble: {
2276 // Processing a Dex `double-to-int' instruction.
2277 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2278 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002279 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002280
2281 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002282 // if input >= (double)INT_MAX goto done
2283 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002284 __ j(kAboveEqual, &done);
2285 // if input == NaN goto nan
2286 __ j(kUnordered, &nan);
2287 // output = double-to-int-truncate(input)
2288 __ cvttsd2si(output, input);
2289 __ jmp(&done);
2290 __ Bind(&nan);
2291 // output = 0
2292 __ xorl(output, output);
2293 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002294 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002295 }
Roland Levillain946e1432014-11-11 17:35:19 +00002296
2297 default:
2298 LOG(FATAL) << "Unexpected type conversion from " << input_type
2299 << " to " << result_type;
2300 }
2301 break;
2302
Roland Levillaindff1f282014-11-05 14:15:05 +00002303 case Primitive::kPrimLong:
2304 switch (input_type) {
2305 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002306 case Primitive::kPrimBoolean:
2307 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002308 case Primitive::kPrimByte:
2309 case Primitive::kPrimShort:
2310 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002311 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002312 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002313 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002314 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002315 break;
2316
Roland Levillain624279f2014-12-04 11:54:28 +00002317 case Primitive::kPrimFloat: {
2318 // Processing a Dex `float-to-long' instruction.
2319 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2320 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002321 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002322
Mark Mendell92e83bf2015-05-07 11:25:03 -04002323 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002324 // if input >= (float)LONG_MAX goto done
2325 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002326 __ j(kAboveEqual, &done);
2327 // if input == NaN goto nan
2328 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002329 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002330 __ cvttss2si(output, input, true);
2331 __ jmp(&done);
2332 __ Bind(&nan);
2333 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002334 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002335 __ Bind(&done);
2336 break;
2337 }
2338
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002339 case Primitive::kPrimDouble: {
2340 // Processing a Dex `double-to-long' instruction.
2341 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2342 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002343 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002344
Mark Mendell92e83bf2015-05-07 11:25:03 -04002345 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002346 // if input >= (double)LONG_MAX goto done
2347 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002348 __ j(kAboveEqual, &done);
2349 // if input == NaN goto nan
2350 __ j(kUnordered, &nan);
2351 // output = double-to-long-truncate(input)
2352 __ cvttsd2si(output, input, true);
2353 __ jmp(&done);
2354 __ Bind(&nan);
2355 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002356 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002357 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002358 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002359 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002360
2361 default:
2362 LOG(FATAL) << "Unexpected type conversion from " << input_type
2363 << " to " << result_type;
2364 }
2365 break;
2366
Roland Levillain981e4542014-11-14 11:47:14 +00002367 case Primitive::kPrimChar:
2368 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002369 case Primitive::kPrimBoolean:
2370 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002371 case Primitive::kPrimByte:
2372 case Primitive::kPrimShort:
2373 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002374 // Processing a Dex `int-to-char' instruction.
2375 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002376 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002377 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002378 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002379 Address(CpuRegister(RSP), in.GetStackIndex()));
2380 } else {
2381 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002382 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002383 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2384 }
2385 break;
2386
2387 default:
2388 LOG(FATAL) << "Unexpected type conversion from " << input_type
2389 << " to " << result_type;
2390 }
2391 break;
2392
Roland Levillaindff1f282014-11-05 14:15:05 +00002393 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002394 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002395 case Primitive::kPrimBoolean:
2396 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002397 case Primitive::kPrimByte:
2398 case Primitive::kPrimShort:
2399 case Primitive::kPrimInt:
2400 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002401 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002402 if (in.IsRegister()) {
2403 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2404 } else if (in.IsConstant()) {
2405 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2406 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2407 if (v == 0) {
2408 __ xorps(dest, dest);
2409 } else {
2410 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2411 }
2412 } else {
2413 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2414 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2415 }
Roland Levillaincff13742014-11-17 14:32:17 +00002416 break;
2417
2418 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002419 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002420 if (in.IsRegister()) {
2421 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2422 } else if (in.IsConstant()) {
2423 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2424 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2425 if (v == 0) {
2426 __ xorps(dest, dest);
2427 } else {
2428 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2429 }
2430 } else {
2431 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2432 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2433 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002434 break;
2435
Roland Levillaincff13742014-11-17 14:32:17 +00002436 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002437 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002438 if (in.IsFpuRegister()) {
2439 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2440 } else if (in.IsConstant()) {
2441 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2442 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2443 if (bit_cast<int64_t, double>(v) == 0) {
2444 __ xorps(dest, dest);
2445 } else {
2446 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2447 }
2448 } else {
2449 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2450 Address(CpuRegister(RSP), in.GetStackIndex()));
2451 }
Roland Levillaincff13742014-11-17 14:32:17 +00002452 break;
2453
2454 default:
2455 LOG(FATAL) << "Unexpected type conversion from " << input_type
2456 << " to " << result_type;
2457 };
2458 break;
2459
Roland Levillaindff1f282014-11-05 14:15:05 +00002460 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002461 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002462 case Primitive::kPrimBoolean:
2463 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002464 case Primitive::kPrimByte:
2465 case Primitive::kPrimShort:
2466 case Primitive::kPrimInt:
2467 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002468 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002469 if (in.IsRegister()) {
2470 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2471 } else if (in.IsConstant()) {
2472 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2473 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2474 if (v == 0) {
2475 __ xorpd(dest, dest);
2476 } else {
2477 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2478 }
2479 } else {
2480 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2481 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2482 }
Roland Levillaincff13742014-11-17 14:32:17 +00002483 break;
2484
2485 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002486 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002487 if (in.IsRegister()) {
2488 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2489 } else if (in.IsConstant()) {
2490 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2491 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2492 if (v == 0) {
2493 __ xorpd(dest, dest);
2494 } else {
2495 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2496 }
2497 } else {
2498 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2499 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2500 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002501 break;
2502
Roland Levillaincff13742014-11-17 14:32:17 +00002503 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002504 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002505 if (in.IsFpuRegister()) {
2506 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2507 } else if (in.IsConstant()) {
2508 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2509 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2510 if (bit_cast<int32_t, float>(v) == 0) {
2511 __ xorpd(dest, dest);
2512 } else {
2513 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2514 }
2515 } else {
2516 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2517 Address(CpuRegister(RSP), in.GetStackIndex()));
2518 }
Roland Levillaincff13742014-11-17 14:32:17 +00002519 break;
2520
2521 default:
2522 LOG(FATAL) << "Unexpected type conversion from " << input_type
2523 << " to " << result_type;
2524 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002525 break;
2526
2527 default:
2528 LOG(FATAL) << "Unexpected type conversion from " << input_type
2529 << " to " << result_type;
2530 }
2531}
2532
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002533void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002534 LocationSummary* locations =
2535 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002536 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002537 case Primitive::kPrimInt: {
2538 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002539 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2540 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002541 break;
2542 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002543
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002544 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002545 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002546 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002547 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002548 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002549 break;
2550 }
2551
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002552 case Primitive::kPrimDouble:
2553 case Primitive::kPrimFloat: {
2554 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002555 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002556 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002557 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002558 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002559
2560 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002561 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002562 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002563}
2564
2565void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2566 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002567 Location first = locations->InAt(0);
2568 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002569 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002570
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002571 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002572 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002573 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002574 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2575 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002576 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2577 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002578 } else {
2579 __ leal(out.AsRegister<CpuRegister>(), Address(
2580 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2581 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002582 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002583 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2584 __ addl(out.AsRegister<CpuRegister>(),
2585 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2586 } else {
2587 __ leal(out.AsRegister<CpuRegister>(), Address(
2588 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2589 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002590 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002591 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002592 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002593 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002594 break;
2595 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002596
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002597 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002598 if (second.IsRegister()) {
2599 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2600 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002601 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2602 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002603 } else {
2604 __ leaq(out.AsRegister<CpuRegister>(), Address(
2605 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2606 }
2607 } else {
2608 DCHECK(second.IsConstant());
2609 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2610 int32_t int32_value = Low32Bits(value);
2611 DCHECK_EQ(int32_value, value);
2612 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2613 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2614 } else {
2615 __ leaq(out.AsRegister<CpuRegister>(), Address(
2616 first.AsRegister<CpuRegister>(), int32_value));
2617 }
2618 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002619 break;
2620 }
2621
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002622 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002623 if (second.IsFpuRegister()) {
2624 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2625 } else if (second.IsConstant()) {
2626 __ addss(first.AsFpuRegister<XmmRegister>(),
2627 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2628 } else {
2629 DCHECK(second.IsStackSlot());
2630 __ addss(first.AsFpuRegister<XmmRegister>(),
2631 Address(CpuRegister(RSP), second.GetStackIndex()));
2632 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002633 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002634 }
2635
2636 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002637 if (second.IsFpuRegister()) {
2638 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2639 } else if (second.IsConstant()) {
2640 __ addsd(first.AsFpuRegister<XmmRegister>(),
2641 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2642 } else {
2643 DCHECK(second.IsDoubleStackSlot());
2644 __ addsd(first.AsFpuRegister<XmmRegister>(),
2645 Address(CpuRegister(RSP), second.GetStackIndex()));
2646 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002647 break;
2648 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002649
2650 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002651 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002652 }
2653}
2654
2655void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002656 LocationSummary* locations =
2657 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002658 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002659 case Primitive::kPrimInt: {
2660 locations->SetInAt(0, Location::RequiresRegister());
2661 locations->SetInAt(1, Location::Any());
2662 locations->SetOut(Location::SameAsFirstInput());
2663 break;
2664 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002665 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002666 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002667 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002668 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002669 break;
2670 }
Calin Juravle11351682014-10-23 15:38:15 +01002671 case Primitive::kPrimFloat:
2672 case Primitive::kPrimDouble: {
2673 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002674 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002675 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002676 break;
Calin Juravle11351682014-10-23 15:38:15 +01002677 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002678 default:
Calin Juravle11351682014-10-23 15:38:15 +01002679 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002680 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002681}
2682
2683void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2684 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002685 Location first = locations->InAt(0);
2686 Location second = locations->InAt(1);
2687 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002688 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002689 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002690 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002691 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002692 } else if (second.IsConstant()) {
2693 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002694 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002695 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002696 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002697 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002698 break;
2699 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002700 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002701 if (second.IsConstant()) {
2702 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2703 DCHECK(IsInt<32>(value));
2704 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2705 } else {
2706 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2707 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002708 break;
2709 }
2710
Calin Juravle11351682014-10-23 15:38:15 +01002711 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002712 if (second.IsFpuRegister()) {
2713 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2714 } else if (second.IsConstant()) {
2715 __ subss(first.AsFpuRegister<XmmRegister>(),
2716 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2717 } else {
2718 DCHECK(second.IsStackSlot());
2719 __ subss(first.AsFpuRegister<XmmRegister>(),
2720 Address(CpuRegister(RSP), second.GetStackIndex()));
2721 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002722 break;
Calin Juravle11351682014-10-23 15:38:15 +01002723 }
2724
2725 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002726 if (second.IsFpuRegister()) {
2727 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2728 } else if (second.IsConstant()) {
2729 __ subsd(first.AsFpuRegister<XmmRegister>(),
2730 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2731 } else {
2732 DCHECK(second.IsDoubleStackSlot());
2733 __ subsd(first.AsFpuRegister<XmmRegister>(),
2734 Address(CpuRegister(RSP), second.GetStackIndex()));
2735 }
Calin Juravle11351682014-10-23 15:38:15 +01002736 break;
2737 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002738
2739 default:
Calin Juravle11351682014-10-23 15:38:15 +01002740 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002741 }
2742}
2743
Calin Juravle34bacdf2014-10-07 20:23:36 +01002744void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2745 LocationSummary* locations =
2746 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2747 switch (mul->GetResultType()) {
2748 case Primitive::kPrimInt: {
2749 locations->SetInAt(0, Location::RequiresRegister());
2750 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002751 if (mul->InputAt(1)->IsIntConstant()) {
2752 // Can use 3 operand multiply.
2753 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2754 } else {
2755 locations->SetOut(Location::SameAsFirstInput());
2756 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002757 break;
2758 }
2759 case Primitive::kPrimLong: {
2760 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002761 locations->SetInAt(1, Location::Any());
2762 if (mul->InputAt(1)->IsLongConstant() &&
2763 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002764 // Can use 3 operand multiply.
2765 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2766 } else {
2767 locations->SetOut(Location::SameAsFirstInput());
2768 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002769 break;
2770 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002771 case Primitive::kPrimFloat:
2772 case Primitive::kPrimDouble: {
2773 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002774 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002775 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002776 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002777 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002778
2779 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002780 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002781 }
2782}
2783
2784void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2785 LocationSummary* locations = mul->GetLocations();
2786 Location first = locations->InAt(0);
2787 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002788 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002789 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002790 case Primitive::kPrimInt:
2791 // The constant may have ended up in a register, so test explicitly to avoid
2792 // problems where the output may not be the same as the first operand.
2793 if (mul->InputAt(1)->IsIntConstant()) {
2794 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2795 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2796 } else if (second.IsRegister()) {
2797 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002798 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002799 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002800 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002801 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002802 __ imull(first.AsRegister<CpuRegister>(),
2803 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002804 }
2805 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002806 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002807 // The constant may have ended up in a register, so test explicitly to avoid
2808 // problems where the output may not be the same as the first operand.
2809 if (mul->InputAt(1)->IsLongConstant()) {
2810 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2811 if (IsInt<32>(value)) {
2812 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2813 Immediate(static_cast<int32_t>(value)));
2814 } else {
2815 // Have to use the constant area.
2816 DCHECK(first.Equals(out));
2817 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2818 }
2819 } else if (second.IsRegister()) {
2820 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002821 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002822 } else {
2823 DCHECK(second.IsDoubleStackSlot());
2824 DCHECK(first.Equals(out));
2825 __ imulq(first.AsRegister<CpuRegister>(),
2826 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002827 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002828 break;
2829 }
2830
Calin Juravleb5bfa962014-10-21 18:02:24 +01002831 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002832 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002833 if (second.IsFpuRegister()) {
2834 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2835 } else if (second.IsConstant()) {
2836 __ mulss(first.AsFpuRegister<XmmRegister>(),
2837 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2838 } else {
2839 DCHECK(second.IsStackSlot());
2840 __ mulss(first.AsFpuRegister<XmmRegister>(),
2841 Address(CpuRegister(RSP), second.GetStackIndex()));
2842 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002843 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002844 }
2845
2846 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002847 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002848 if (second.IsFpuRegister()) {
2849 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2850 } else if (second.IsConstant()) {
2851 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2852 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2853 } else {
2854 DCHECK(second.IsDoubleStackSlot());
2855 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2856 Address(CpuRegister(RSP), second.GetStackIndex()));
2857 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002858 break;
2859 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002860
2861 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002862 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002863 }
2864}
2865
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002866void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2867 uint32_t stack_adjustment, bool is_float) {
2868 if (source.IsStackSlot()) {
2869 DCHECK(is_float);
2870 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2871 } else if (source.IsDoubleStackSlot()) {
2872 DCHECK(!is_float);
2873 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2874 } else {
2875 // Write the value to the temporary location on the stack and load to FP stack.
2876 if (is_float) {
2877 Location stack_temp = Location::StackSlot(temp_offset);
2878 codegen_->Move(stack_temp, source);
2879 __ flds(Address(CpuRegister(RSP), temp_offset));
2880 } else {
2881 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2882 codegen_->Move(stack_temp, source);
2883 __ fldl(Address(CpuRegister(RSP), temp_offset));
2884 }
2885 }
2886}
2887
2888void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2889 Primitive::Type type = rem->GetResultType();
2890 bool is_float = type == Primitive::kPrimFloat;
2891 size_t elem_size = Primitive::ComponentSize(type);
2892 LocationSummary* locations = rem->GetLocations();
2893 Location first = locations->InAt(0);
2894 Location second = locations->InAt(1);
2895 Location out = locations->Out();
2896
2897 // Create stack space for 2 elements.
2898 // TODO: enhance register allocator to ask for stack temporaries.
2899 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2900
2901 // Load the values to the FP stack in reverse order, using temporaries if needed.
2902 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2903 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2904
2905 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002906 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002907 __ Bind(&retry);
2908 __ fprem();
2909
2910 // Move FP status to AX.
2911 __ fstsw();
2912
2913 // And see if the argument reduction is complete. This is signaled by the
2914 // C2 FPU flag bit set to 0.
2915 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2916 __ j(kNotEqual, &retry);
2917
2918 // We have settled on the final value. Retrieve it into an XMM register.
2919 // Store FP top of stack to real stack.
2920 if (is_float) {
2921 __ fsts(Address(CpuRegister(RSP), 0));
2922 } else {
2923 __ fstl(Address(CpuRegister(RSP), 0));
2924 }
2925
2926 // Pop the 2 items from the FP stack.
2927 __ fucompp();
2928
2929 // Load the value from the stack into an XMM register.
2930 DCHECK(out.IsFpuRegister()) << out;
2931 if (is_float) {
2932 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2933 } else {
2934 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2935 }
2936
2937 // And remove the temporary stack space we allocated.
2938 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2939}
2940
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002941void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2942 DCHECK(instruction->IsDiv() || instruction->IsRem());
2943
2944 LocationSummary* locations = instruction->GetLocations();
2945 Location second = locations->InAt(1);
2946 DCHECK(second.IsConstant());
2947
2948 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2949 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002950 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002951
2952 DCHECK(imm == 1 || imm == -1);
2953
2954 switch (instruction->GetResultType()) {
2955 case Primitive::kPrimInt: {
2956 if (instruction->IsRem()) {
2957 __ xorl(output_register, output_register);
2958 } else {
2959 __ movl(output_register, input_register);
2960 if (imm == -1) {
2961 __ negl(output_register);
2962 }
2963 }
2964 break;
2965 }
2966
2967 case Primitive::kPrimLong: {
2968 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002969 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002970 } else {
2971 __ movq(output_register, input_register);
2972 if (imm == -1) {
2973 __ negq(output_register);
2974 }
2975 }
2976 break;
2977 }
2978
2979 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002980 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002981 }
2982}
2983
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002984void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002985 LocationSummary* locations = instruction->GetLocations();
2986 Location second = locations->InAt(1);
2987
2988 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2989 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
2990
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002991 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002992
2993 DCHECK(IsPowerOfTwo(std::abs(imm)));
2994
2995 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
2996
2997 if (instruction->GetResultType() == Primitive::kPrimInt) {
2998 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
2999 __ testl(numerator, numerator);
3000 __ cmov(kGreaterEqual, tmp, numerator);
3001 int shift = CTZ(imm);
3002 __ sarl(tmp, Immediate(shift));
3003
3004 if (imm < 0) {
3005 __ negl(tmp);
3006 }
3007
3008 __ movl(output_register, tmp);
3009 } else {
3010 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3011 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3012
Mark Mendell92e83bf2015-05-07 11:25:03 -04003013 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003014 __ addq(rdx, numerator);
3015 __ testq(numerator, numerator);
3016 __ cmov(kGreaterEqual, rdx, numerator);
3017 int shift = CTZ(imm);
3018 __ sarq(rdx, Immediate(shift));
3019
3020 if (imm < 0) {
3021 __ negq(rdx);
3022 }
3023
3024 __ movq(output_register, rdx);
3025 }
3026}
3027
3028void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3029 DCHECK(instruction->IsDiv() || instruction->IsRem());
3030
3031 LocationSummary* locations = instruction->GetLocations();
3032 Location second = locations->InAt(1);
3033
3034 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3035 : locations->GetTemp(0).AsRegister<CpuRegister>();
3036 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3037 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3038 : locations->Out().AsRegister<CpuRegister>();
3039 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3040
3041 DCHECK_EQ(RAX, eax.AsRegister());
3042 DCHECK_EQ(RDX, edx.AsRegister());
3043 if (instruction->IsDiv()) {
3044 DCHECK_EQ(RAX, out.AsRegister());
3045 } else {
3046 DCHECK_EQ(RDX, out.AsRegister());
3047 }
3048
3049 int64_t magic;
3050 int shift;
3051
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003052 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003053 if (instruction->GetResultType() == Primitive::kPrimInt) {
3054 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3055
3056 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3057
3058 __ movl(numerator, eax);
3059
Mark Mendell0c9497d2015-08-21 09:30:05 -04003060 NearLabel no_div;
3061 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003062 __ testl(eax, eax);
3063 __ j(kNotEqual, &no_div);
3064
3065 __ xorl(out, out);
3066 __ jmp(&end);
3067
3068 __ Bind(&no_div);
3069
3070 __ movl(eax, Immediate(magic));
3071 __ imull(numerator);
3072
3073 if (imm > 0 && magic < 0) {
3074 __ addl(edx, numerator);
3075 } else if (imm < 0 && magic > 0) {
3076 __ subl(edx, numerator);
3077 }
3078
3079 if (shift != 0) {
3080 __ sarl(edx, Immediate(shift));
3081 }
3082
3083 __ movl(eax, edx);
3084 __ shrl(edx, Immediate(31));
3085 __ addl(edx, eax);
3086
3087 if (instruction->IsRem()) {
3088 __ movl(eax, numerator);
3089 __ imull(edx, Immediate(imm));
3090 __ subl(eax, edx);
3091 __ movl(edx, eax);
3092 } else {
3093 __ movl(eax, edx);
3094 }
3095 __ Bind(&end);
3096 } else {
3097 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3098
3099 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3100
3101 CpuRegister rax = eax;
3102 CpuRegister rdx = edx;
3103
3104 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3105
3106 // Save the numerator.
3107 __ movq(numerator, rax);
3108
3109 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003110 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003111
3112 // RDX:RAX = magic * numerator
3113 __ imulq(numerator);
3114
3115 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003116 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003117 __ addq(rdx, numerator);
3118 } else if (imm < 0 && magic > 0) {
3119 // RDX -= numerator
3120 __ subq(rdx, numerator);
3121 }
3122
3123 // Shift if needed.
3124 if (shift != 0) {
3125 __ sarq(rdx, Immediate(shift));
3126 }
3127
3128 // RDX += 1 if RDX < 0
3129 __ movq(rax, rdx);
3130 __ shrq(rdx, Immediate(63));
3131 __ addq(rdx, rax);
3132
3133 if (instruction->IsRem()) {
3134 __ movq(rax, numerator);
3135
3136 if (IsInt<32>(imm)) {
3137 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3138 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003139 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003140 }
3141
3142 __ subq(rax, rdx);
3143 __ movq(rdx, rax);
3144 } else {
3145 __ movq(rax, rdx);
3146 }
3147 }
3148}
3149
Calin Juravlebacfec32014-11-14 15:54:36 +00003150void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3151 DCHECK(instruction->IsDiv() || instruction->IsRem());
3152 Primitive::Type type = instruction->GetResultType();
3153 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3154
3155 bool is_div = instruction->IsDiv();
3156 LocationSummary* locations = instruction->GetLocations();
3157
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003158 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3159 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003160
Roland Levillain271ab9c2014-11-27 15:23:57 +00003161 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003162 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003163
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003164 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003165 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003166
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003167 if (imm == 0) {
3168 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3169 } else if (imm == 1 || imm == -1) {
3170 DivRemOneOrMinusOne(instruction);
3171 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003172 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003173 } else {
3174 DCHECK(imm <= -2 || imm >= 2);
3175 GenerateDivRemWithAnyConstant(instruction);
3176 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003177 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003178 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003179 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3180 out.AsRegister(), type, is_div);
3181 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003182
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003183 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3184 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3185 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3186 // so it's safe to just use negl instead of more complex comparisons.
3187 if (type == Primitive::kPrimInt) {
3188 __ cmpl(second_reg, Immediate(-1));
3189 __ j(kEqual, slow_path->GetEntryLabel());
3190 // edx:eax <- sign-extended of eax
3191 __ cdq();
3192 // eax = quotient, edx = remainder
3193 __ idivl(second_reg);
3194 } else {
3195 __ cmpq(second_reg, Immediate(-1));
3196 __ j(kEqual, slow_path->GetEntryLabel());
3197 // rdx:rax <- sign-extended of rax
3198 __ cqo();
3199 // rax = quotient, rdx = remainder
3200 __ idivq(second_reg);
3201 }
3202 __ Bind(slow_path->GetExitLabel());
3203 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003204}
3205
Calin Juravle7c4954d2014-10-28 16:57:40 +00003206void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3207 LocationSummary* locations =
3208 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3209 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003210 case Primitive::kPrimInt:
3211 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003212 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003213 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003214 locations->SetOut(Location::SameAsFirstInput());
3215 // Intel uses edx:eax as the dividend.
3216 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003217 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3218 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3219 // output and request another temp.
3220 if (div->InputAt(1)->IsConstant()) {
3221 locations->AddTemp(Location::RequiresRegister());
3222 }
Calin Juravled0d48522014-11-04 16:40:20 +00003223 break;
3224 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003225
Calin Juravle7c4954d2014-10-28 16:57:40 +00003226 case Primitive::kPrimFloat:
3227 case Primitive::kPrimDouble: {
3228 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003229 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003230 locations->SetOut(Location::SameAsFirstInput());
3231 break;
3232 }
3233
3234 default:
3235 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3236 }
3237}
3238
3239void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3240 LocationSummary* locations = div->GetLocations();
3241 Location first = locations->InAt(0);
3242 Location second = locations->InAt(1);
3243 DCHECK(first.Equals(locations->Out()));
3244
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003245 Primitive::Type type = div->GetResultType();
3246 switch (type) {
3247 case Primitive::kPrimInt:
3248 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003249 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003250 break;
3251 }
3252
Calin Juravle7c4954d2014-10-28 16:57:40 +00003253 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003254 if (second.IsFpuRegister()) {
3255 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3256 } else if (second.IsConstant()) {
3257 __ divss(first.AsFpuRegister<XmmRegister>(),
3258 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3259 } else {
3260 DCHECK(second.IsStackSlot());
3261 __ divss(first.AsFpuRegister<XmmRegister>(),
3262 Address(CpuRegister(RSP), second.GetStackIndex()));
3263 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003264 break;
3265 }
3266
3267 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003268 if (second.IsFpuRegister()) {
3269 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3270 } else if (second.IsConstant()) {
3271 __ divsd(first.AsFpuRegister<XmmRegister>(),
3272 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3273 } else {
3274 DCHECK(second.IsDoubleStackSlot());
3275 __ divsd(first.AsFpuRegister<XmmRegister>(),
3276 Address(CpuRegister(RSP), second.GetStackIndex()));
3277 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003278 break;
3279 }
3280
3281 default:
3282 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3283 }
3284}
3285
Calin Juravlebacfec32014-11-14 15:54:36 +00003286void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003287 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003288 LocationSummary* locations =
3289 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003290
3291 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003292 case Primitive::kPrimInt:
3293 case Primitive::kPrimLong: {
3294 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003295 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003296 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3297 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003298 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3299 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3300 // output and request another temp.
3301 if (rem->InputAt(1)->IsConstant()) {
3302 locations->AddTemp(Location::RequiresRegister());
3303 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003304 break;
3305 }
3306
3307 case Primitive::kPrimFloat:
3308 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003309 locations->SetInAt(0, Location::Any());
3310 locations->SetInAt(1, Location::Any());
3311 locations->SetOut(Location::RequiresFpuRegister());
3312 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003313 break;
3314 }
3315
3316 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003317 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003318 }
3319}
3320
3321void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3322 Primitive::Type type = rem->GetResultType();
3323 switch (type) {
3324 case Primitive::kPrimInt:
3325 case Primitive::kPrimLong: {
3326 GenerateDivRemIntegral(rem);
3327 break;
3328 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003329 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003330 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003331 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003332 break;
3333 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003334 default:
3335 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3336 }
3337}
3338
Calin Juravled0d48522014-11-04 16:40:20 +00003339void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003340 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3341 ? LocationSummary::kCallOnSlowPath
3342 : LocationSummary::kNoCall;
3343 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled0d48522014-11-04 16:40:20 +00003344 locations->SetInAt(0, Location::Any());
3345 if (instruction->HasUses()) {
3346 locations->SetOut(Location::SameAsFirstInput());
3347 }
3348}
3349
3350void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003351 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003352 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3353 codegen_->AddSlowPath(slow_path);
3354
3355 LocationSummary* locations = instruction->GetLocations();
3356 Location value = locations->InAt(0);
3357
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003358 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003359 case Primitive::kPrimByte:
3360 case Primitive::kPrimChar:
3361 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003362 case Primitive::kPrimInt: {
3363 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003364 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003365 __ j(kEqual, slow_path->GetEntryLabel());
3366 } else if (value.IsStackSlot()) {
3367 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3368 __ j(kEqual, slow_path->GetEntryLabel());
3369 } else {
3370 DCHECK(value.IsConstant()) << value;
3371 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3372 __ jmp(slow_path->GetEntryLabel());
3373 }
3374 }
3375 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003376 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003377 case Primitive::kPrimLong: {
3378 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003379 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003380 __ j(kEqual, slow_path->GetEntryLabel());
3381 } else if (value.IsDoubleStackSlot()) {
3382 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3383 __ j(kEqual, slow_path->GetEntryLabel());
3384 } else {
3385 DCHECK(value.IsConstant()) << value;
3386 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3387 __ jmp(slow_path->GetEntryLabel());
3388 }
3389 }
3390 break;
3391 }
3392 default:
3393 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003394 }
Calin Juravled0d48522014-11-04 16:40:20 +00003395}
3396
Calin Juravle9aec02f2014-11-18 23:06:35 +00003397void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3398 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3399
3400 LocationSummary* locations =
3401 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3402
3403 switch (op->GetResultType()) {
3404 case Primitive::kPrimInt:
3405 case Primitive::kPrimLong: {
3406 locations->SetInAt(0, Location::RequiresRegister());
3407 // The shift count needs to be in CL.
3408 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3409 locations->SetOut(Location::SameAsFirstInput());
3410 break;
3411 }
3412 default:
3413 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3414 }
3415}
3416
3417void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3418 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3419
3420 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003421 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003422 Location second = locations->InAt(1);
3423
3424 switch (op->GetResultType()) {
3425 case Primitive::kPrimInt: {
3426 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003427 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003428 if (op->IsShl()) {
3429 __ shll(first_reg, second_reg);
3430 } else if (op->IsShr()) {
3431 __ sarl(first_reg, second_reg);
3432 } else {
3433 __ shrl(first_reg, second_reg);
3434 }
3435 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003436 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003437 if (op->IsShl()) {
3438 __ shll(first_reg, imm);
3439 } else if (op->IsShr()) {
3440 __ sarl(first_reg, imm);
3441 } else {
3442 __ shrl(first_reg, imm);
3443 }
3444 }
3445 break;
3446 }
3447 case Primitive::kPrimLong: {
3448 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003449 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003450 if (op->IsShl()) {
3451 __ shlq(first_reg, second_reg);
3452 } else if (op->IsShr()) {
3453 __ sarq(first_reg, second_reg);
3454 } else {
3455 __ shrq(first_reg, second_reg);
3456 }
3457 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003458 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003459 if (op->IsShl()) {
3460 __ shlq(first_reg, imm);
3461 } else if (op->IsShr()) {
3462 __ sarq(first_reg, imm);
3463 } else {
3464 __ shrq(first_reg, imm);
3465 }
3466 }
3467 break;
3468 }
3469 default:
3470 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3471 }
3472}
3473
3474void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3475 HandleShift(shl);
3476}
3477
3478void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3479 HandleShift(shl);
3480}
3481
3482void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3483 HandleShift(shr);
3484}
3485
3486void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3487 HandleShift(shr);
3488}
3489
3490void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3491 HandleShift(ushr);
3492}
3493
3494void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3495 HandleShift(ushr);
3496}
3497
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003498void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003499 LocationSummary* locations =
3500 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003501 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003502 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003503 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003504 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003505}
3506
3507void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3508 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003509 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3510 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003511 // Note: if heap poisoning is enabled, the entry point takes cares
3512 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003513
Calin Juravle175dc732015-08-25 15:42:32 +01003514 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3515 instruction,
3516 instruction->GetDexPc(),
3517 nullptr);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003518
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003519 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003520}
3521
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003522void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3523 LocationSummary* locations =
3524 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3525 InvokeRuntimeCallingConvention calling_convention;
3526 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003527 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003528 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003529 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003530}
3531
3532void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3533 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003534 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3535 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003536
Roland Levillain4d027112015-07-01 15:41:14 +01003537 // Note: if heap poisoning is enabled, the entry point takes cares
3538 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003539 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3540 instruction,
3541 instruction->GetDexPc(),
3542 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003543
3544 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003545}
3546
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003547void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003548 LocationSummary* locations =
3549 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003550 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3551 if (location.IsStackSlot()) {
3552 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3553 } else if (location.IsDoubleStackSlot()) {
3554 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3555 }
3556 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003557}
3558
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003559void InstructionCodeGeneratorX86_64::VisitParameterValue(
3560 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003561 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003562}
3563
3564void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3565 LocationSummary* locations =
3566 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3567 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3568}
3569
3570void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3571 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3572 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003573}
3574
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003575void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003576 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003577 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003578 locations->SetInAt(0, Location::RequiresRegister());
3579 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003580}
3581
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003582void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3583 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003584 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3585 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003586 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003587 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003588 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003589 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003590 break;
3591
3592 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003593 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003594 break;
3595
3596 default:
3597 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3598 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003599}
3600
David Brazdil66d126e2015-04-03 16:02:44 +01003601void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3602 LocationSummary* locations =
3603 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3604 locations->SetInAt(0, Location::RequiresRegister());
3605 locations->SetOut(Location::SameAsFirstInput());
3606}
3607
3608void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003609 LocationSummary* locations = bool_not->GetLocations();
3610 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3611 locations->Out().AsRegister<CpuRegister>().AsRegister());
3612 Location out = locations->Out();
3613 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3614}
3615
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003616void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003617 LocationSummary* locations =
3618 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003619 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3620 locations->SetInAt(i, Location::Any());
3621 }
3622 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003623}
3624
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003625void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003626 LOG(FATAL) << "Unimplemented";
3627}
3628
Calin Juravle52c48962014-12-16 17:02:57 +00003629void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3630 /*
3631 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3632 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3633 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3634 */
3635 switch (kind) {
3636 case MemBarrierKind::kAnyAny: {
3637 __ mfence();
3638 break;
3639 }
3640 case MemBarrierKind::kAnyStore:
3641 case MemBarrierKind::kLoadAny:
3642 case MemBarrierKind::kStoreStore: {
3643 // nop
3644 break;
3645 }
3646 default:
3647 LOG(FATAL) << "Unexpected memory barier " << kind;
3648 }
3649}
3650
3651void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3652 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3653
Nicolas Geoffray39468442014-09-02 15:17:15 +01003654 LocationSummary* locations =
3655 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003656 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003657 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3658 locations->SetOut(Location::RequiresFpuRegister());
3659 } else {
3660 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3661 }
Calin Juravle52c48962014-12-16 17:02:57 +00003662}
3663
3664void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3665 const FieldInfo& field_info) {
3666 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3667
3668 LocationSummary* locations = instruction->GetLocations();
3669 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3670 Location out = locations->Out();
3671 bool is_volatile = field_info.IsVolatile();
3672 Primitive::Type field_type = field_info.GetFieldType();
3673 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3674
3675 switch (field_type) {
3676 case Primitive::kPrimBoolean: {
3677 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3678 break;
3679 }
3680
3681 case Primitive::kPrimByte: {
3682 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3683 break;
3684 }
3685
3686 case Primitive::kPrimShort: {
3687 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3688 break;
3689 }
3690
3691 case Primitive::kPrimChar: {
3692 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3693 break;
3694 }
3695
3696 case Primitive::kPrimInt:
3697 case Primitive::kPrimNot: {
3698 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3699 break;
3700 }
3701
3702 case Primitive::kPrimLong: {
3703 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3704 break;
3705 }
3706
3707 case Primitive::kPrimFloat: {
3708 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3709 break;
3710 }
3711
3712 case Primitive::kPrimDouble: {
3713 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3714 break;
3715 }
3716
3717 case Primitive::kPrimVoid:
3718 LOG(FATAL) << "Unreachable type " << field_type;
3719 UNREACHABLE();
3720 }
3721
Calin Juravle77520bc2015-01-12 18:45:46 +00003722 codegen_->MaybeRecordImplicitNullCheck(instruction);
3723
Calin Juravle52c48962014-12-16 17:02:57 +00003724 if (is_volatile) {
3725 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3726 }
Roland Levillain4d027112015-07-01 15:41:14 +01003727
3728 if (field_type == Primitive::kPrimNot) {
3729 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3730 }
Calin Juravle52c48962014-12-16 17:02:57 +00003731}
3732
3733void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3734 const FieldInfo& field_info) {
3735 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3736
3737 LocationSummary* locations =
3738 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003739 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003740 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003741 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003742
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003743 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003744 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3745 locations->SetInAt(1, Location::RequiresFpuRegister());
3746 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003747 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003748 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003749 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003750 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003751 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003752 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003753 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3754 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003755 locations->AddTemp(Location::RequiresRegister());
3756 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003757}
3758
Calin Juravle52c48962014-12-16 17:02:57 +00003759void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003760 const FieldInfo& field_info,
3761 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003762 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3763
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003764 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003765 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3766 Location value = locations->InAt(1);
3767 bool is_volatile = field_info.IsVolatile();
3768 Primitive::Type field_type = field_info.GetFieldType();
3769 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3770
3771 if (is_volatile) {
3772 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3773 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003774
3775 switch (field_type) {
3776 case Primitive::kPrimBoolean:
3777 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003778 if (value.IsConstant()) {
3779 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3780 __ movb(Address(base, offset), Immediate(v));
3781 } else {
3782 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3783 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003784 break;
3785 }
3786
3787 case Primitive::kPrimShort:
3788 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003789 if (value.IsConstant()) {
3790 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3791 __ movw(Address(base, offset), Immediate(v));
3792 } else {
3793 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3794 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003795 break;
3796 }
3797
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003798 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003799 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003800 if (value.IsConstant()) {
3801 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003802 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3803 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3804 // Note: if heap poisoning is enabled, no need to poison
3805 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003806 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003807 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003808 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3809 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3810 __ movl(temp, value.AsRegister<CpuRegister>());
3811 __ PoisonHeapReference(temp);
3812 __ movl(Address(base, offset), temp);
3813 } else {
3814 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3815 }
Mark Mendell40741f32015-04-20 22:10:34 -04003816 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003817 break;
3818 }
3819
3820 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003821 if (value.IsConstant()) {
3822 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3823 DCHECK(IsInt<32>(v));
3824 int32_t v_32 = v;
3825 __ movq(Address(base, offset), Immediate(v_32));
3826 } else {
3827 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3828 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003829 break;
3830 }
3831
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003832 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003833 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003834 break;
3835 }
3836
3837 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003838 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003839 break;
3840 }
3841
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003842 case Primitive::kPrimVoid:
3843 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003844 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003845 }
Calin Juravle52c48962014-12-16 17:02:57 +00003846
Calin Juravle77520bc2015-01-12 18:45:46 +00003847 codegen_->MaybeRecordImplicitNullCheck(instruction);
3848
3849 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3850 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3851 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003852 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003853 }
3854
Calin Juravle52c48962014-12-16 17:02:57 +00003855 if (is_volatile) {
3856 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3857 }
3858}
3859
3860void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3861 HandleFieldSet(instruction, instruction->GetFieldInfo());
3862}
3863
3864void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003865 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003866}
3867
3868void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003869 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003870}
3871
3872void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003873 HandleFieldGet(instruction, instruction->GetFieldInfo());
3874}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003875
Calin Juravle52c48962014-12-16 17:02:57 +00003876void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3877 HandleFieldGet(instruction);
3878}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003879
Calin Juravle52c48962014-12-16 17:02:57 +00003880void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3881 HandleFieldGet(instruction, instruction->GetFieldInfo());
3882}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003883
Calin Juravle52c48962014-12-16 17:02:57 +00003884void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3885 HandleFieldSet(instruction, instruction->GetFieldInfo());
3886}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003887
Calin Juravle52c48962014-12-16 17:02:57 +00003888void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003889 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003890}
3891
Calin Juravlee460d1d2015-09-29 04:52:17 +01003892void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
3893 HUnresolvedInstanceFieldGet* instruction) {
3894 FieldAccessCallingConventionX86_64 calling_convention;
3895 codegen_->CreateUnresolvedFieldLocationSummary(
3896 instruction, instruction->GetFieldType(), calling_convention);
3897}
3898
3899void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
3900 HUnresolvedInstanceFieldGet* instruction) {
3901 FieldAccessCallingConventionX86_64 calling_convention;
3902 codegen_->GenerateUnresolvedFieldAccess(instruction,
3903 instruction->GetFieldType(),
3904 instruction->GetFieldIndex(),
3905 instruction->GetDexPc(),
3906 calling_convention);
3907}
3908
3909void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
3910 HUnresolvedInstanceFieldSet* instruction) {
3911 FieldAccessCallingConventionX86_64 calling_convention;
3912 codegen_->CreateUnresolvedFieldLocationSummary(
3913 instruction, instruction->GetFieldType(), calling_convention);
3914}
3915
3916void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
3917 HUnresolvedInstanceFieldSet* instruction) {
3918 FieldAccessCallingConventionX86_64 calling_convention;
3919 codegen_->GenerateUnresolvedFieldAccess(instruction,
3920 instruction->GetFieldType(),
3921 instruction->GetFieldIndex(),
3922 instruction->GetDexPc(),
3923 calling_convention);
3924}
3925
3926void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
3927 HUnresolvedStaticFieldGet* instruction) {
3928 FieldAccessCallingConventionX86_64 calling_convention;
3929 codegen_->CreateUnresolvedFieldLocationSummary(
3930 instruction, instruction->GetFieldType(), calling_convention);
3931}
3932
3933void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
3934 HUnresolvedStaticFieldGet* instruction) {
3935 FieldAccessCallingConventionX86_64 calling_convention;
3936 codegen_->GenerateUnresolvedFieldAccess(instruction,
3937 instruction->GetFieldType(),
3938 instruction->GetFieldIndex(),
3939 instruction->GetDexPc(),
3940 calling_convention);
3941}
3942
3943void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
3944 HUnresolvedStaticFieldSet* instruction) {
3945 FieldAccessCallingConventionX86_64 calling_convention;
3946 codegen_->CreateUnresolvedFieldLocationSummary(
3947 instruction, instruction->GetFieldType(), calling_convention);
3948}
3949
3950void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
3951 HUnresolvedStaticFieldSet* instruction) {
3952 FieldAccessCallingConventionX86_64 calling_convention;
3953 codegen_->GenerateUnresolvedFieldAccess(instruction,
3954 instruction->GetFieldType(),
3955 instruction->GetFieldIndex(),
3956 instruction->GetDexPc(),
3957 calling_convention);
3958}
3959
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003960void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003961 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3962 ? LocationSummary::kCallOnSlowPath
3963 : LocationSummary::kNoCall;
3964 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3965 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003966 ? Location::RequiresRegister()
3967 : Location::Any();
3968 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003969 if (instruction->HasUses()) {
3970 locations->SetOut(Location::SameAsFirstInput());
3971 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003972}
3973
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003974void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003975 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3976 return;
3977 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003978 LocationSummary* locations = instruction->GetLocations();
3979 Location obj = locations->InAt(0);
3980
3981 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3982 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3983}
3984
3985void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003986 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003987 codegen_->AddSlowPath(slow_path);
3988
3989 LocationSummary* locations = instruction->GetLocations();
3990 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003991
3992 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003993 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003994 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003995 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003996 } else {
3997 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00003998 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003999 __ jmp(slow_path->GetEntryLabel());
4000 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004001 }
4002 __ j(kEqual, slow_path->GetEntryLabel());
4003}
4004
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004005void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004006 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004007 GenerateImplicitNullCheck(instruction);
4008 } else {
4009 GenerateExplicitNullCheck(instruction);
4010 }
4011}
4012
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004013void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004014 LocationSummary* locations =
4015 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004016 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004017 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004018 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4019 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4020 } else {
4021 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4022 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004023}
4024
4025void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4026 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004027 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004028 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004029 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004030
Roland Levillain4d027112015-07-01 15:41:14 +01004031 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004032 case Primitive::kPrimBoolean: {
4033 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004034 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004035 if (index.IsConstant()) {
4036 __ movzxb(out, Address(obj,
4037 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4038 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004039 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004040 }
4041 break;
4042 }
4043
4044 case Primitive::kPrimByte: {
4045 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004046 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004047 if (index.IsConstant()) {
4048 __ movsxb(out, Address(obj,
4049 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4050 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004051 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004052 }
4053 break;
4054 }
4055
4056 case Primitive::kPrimShort: {
4057 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004058 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004059 if (index.IsConstant()) {
4060 __ movsxw(out, Address(obj,
4061 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4062 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004063 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004064 }
4065 break;
4066 }
4067
4068 case Primitive::kPrimChar: {
4069 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004070 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004071 if (index.IsConstant()) {
4072 __ movzxw(out, Address(obj,
4073 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4074 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004075 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004076 }
4077 break;
4078 }
4079
4080 case Primitive::kPrimInt:
4081 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01004082 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4083 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004084 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004085 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004086 if (index.IsConstant()) {
4087 __ movl(out, Address(obj,
4088 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4089 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004090 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004091 }
4092 break;
4093 }
4094
4095 case Primitive::kPrimLong: {
4096 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004097 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004098 if (index.IsConstant()) {
4099 __ movq(out, Address(obj,
4100 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4101 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004102 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004103 }
4104 break;
4105 }
4106
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004107 case Primitive::kPrimFloat: {
4108 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004109 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004110 if (index.IsConstant()) {
4111 __ movss(out, Address(obj,
4112 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4113 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004114 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004115 }
4116 break;
4117 }
4118
4119 case Primitive::kPrimDouble: {
4120 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004121 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004122 if (index.IsConstant()) {
4123 __ movsd(out, Address(obj,
4124 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4125 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004126 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004127 }
4128 break;
4129 }
4130
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004131 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004132 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004133 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004134 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004135 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004136
4137 if (type == Primitive::kPrimNot) {
4138 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4139 __ MaybeUnpoisonHeapReference(out);
4140 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004141}
4142
4143void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004144 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004145
4146 bool needs_write_barrier =
4147 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004148 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004149
Nicolas Geoffray39468442014-09-02 15:17:15 +01004150 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004151 instruction,
4152 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004153
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004154 locations->SetInAt(0, Location::RequiresRegister());
4155 locations->SetInAt(
4156 1, Location::RegisterOrConstant(instruction->InputAt(1)));
4157 locations->SetInAt(2, Location::RequiresRegister());
4158 if (value_type == Primitive::kPrimLong) {
4159 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
4160 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
4161 locations->SetInAt(2, Location::RequiresFpuRegister());
4162 } else {
4163 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4164 }
4165
4166 if (needs_write_barrier) {
4167 // Temporary registers for the write barrier.
4168 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4169 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004170 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004171}
4172
4173void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4174 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004175 CpuRegister array = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004176 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004177 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004178 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004179 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004180 bool needs_write_barrier =
4181 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004182 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4183 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4184 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004185
4186 switch (value_type) {
4187 case Primitive::kPrimBoolean:
4188 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004189 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4190 Address address = index.IsConstant()
4191 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4192 : Address(array, index.AsRegister<CpuRegister>(), TIMES_1, offset);
4193 if (value.IsRegister()) {
4194 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004195 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004196 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004197 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004198 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004199 break;
4200 }
4201
4202 case Primitive::kPrimShort:
4203 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004204 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4205 Address address = index.IsConstant()
4206 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4207 : Address(array, index.AsRegister<CpuRegister>(), TIMES_2, offset);
4208 if (value.IsRegister()) {
4209 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004210 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004211 DCHECK(value.IsConstant()) << value;
4212 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004213 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004214 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004215 break;
4216 }
4217
4218 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004219 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4220 Address address = index.IsConstant()
4221 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4222 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4223 if (!value.IsRegister()) {
4224 // Just setting null.
4225 DCHECK(instruction->InputAt(2)->IsNullConstant());
4226 DCHECK(value.IsConstant()) << value;
4227 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004228 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004229 DCHECK(!needs_write_barrier);
4230 DCHECK(!may_need_runtime_call);
4231 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004232 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004233
4234 DCHECK(needs_write_barrier);
4235 CpuRegister register_value = value.AsRegister<CpuRegister>();
4236 NearLabel done, not_null, do_put;
4237 SlowPathCode* slow_path = nullptr;
4238 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4239 if (may_need_runtime_call) {
4240 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4241 codegen_->AddSlowPath(slow_path);
4242 if (instruction->GetValueCanBeNull()) {
4243 __ testl(register_value, register_value);
4244 __ j(kNotEqual, &not_null);
4245 __ movl(address, Immediate(0));
4246 codegen_->MaybeRecordImplicitNullCheck(instruction);
4247 __ jmp(&done);
4248 __ Bind(&not_null);
4249 }
4250
4251 __ movl(temp, Address(array, class_offset));
4252 codegen_->MaybeRecordImplicitNullCheck(instruction);
4253 __ MaybeUnpoisonHeapReference(temp);
4254 __ movl(temp, Address(temp, component_offset));
4255 // No need to poison/unpoison, we're comparing two poisoned references.
4256 __ cmpl(temp, Address(register_value, class_offset));
4257 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4258 __ j(kEqual, &do_put);
4259 __ MaybeUnpoisonHeapReference(temp);
4260 __ movl(temp, Address(temp, super_offset));
4261 // No need to unpoison the result, we're comparing against null.
4262 __ testl(temp, temp);
4263 __ j(kNotEqual, slow_path->GetEntryLabel());
4264 __ Bind(&do_put);
4265 } else {
4266 __ j(kNotEqual, slow_path->GetEntryLabel());
4267 }
4268 }
4269
4270 if (kPoisonHeapReferences) {
4271 __ movl(temp, register_value);
4272 __ PoisonHeapReference(temp);
4273 __ movl(address, temp);
4274 } else {
4275 __ movl(address, register_value);
4276 }
4277 if (!may_need_runtime_call) {
4278 codegen_->MaybeRecordImplicitNullCheck(instruction);
4279 }
4280
4281 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4282 codegen_->MarkGCCard(
4283 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4284 __ Bind(&done);
4285
4286 if (slow_path != nullptr) {
4287 __ Bind(slow_path->GetExitLabel());
4288 }
4289
4290 break;
4291 }
4292 case Primitive::kPrimInt: {
4293 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4294 Address address = index.IsConstant()
4295 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4296 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4297 if (value.IsRegister()) {
4298 __ movl(address, value.AsRegister<CpuRegister>());
4299 } else {
4300 DCHECK(value.IsConstant()) << value;
4301 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4302 __ movl(address, Immediate(v));
4303 }
4304 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004305 break;
4306 }
4307
4308 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004309 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4310 Address address = index.IsConstant()
4311 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4312 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4313 if (value.IsRegister()) {
4314 __ movq(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004315 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004316 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4317 DCHECK(IsInt<32>(v));
4318 int32_t v_32 = v;
4319 __ movq(address, Immediate(v_32));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004320 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004321 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004322 break;
4323 }
4324
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004325 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004326 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4327 Address address = index.IsConstant()
4328 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4329 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4330 DCHECK(value.IsFpuRegister());
4331 __ movss(address, value.AsFpuRegister<XmmRegister>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004332 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004333 break;
4334 }
4335
4336 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004337 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4338 Address address = index.IsConstant()
4339 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4340 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4341 DCHECK(value.IsFpuRegister());
4342 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004343 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004344 break;
4345 }
4346
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004347 case Primitive::kPrimVoid:
4348 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004349 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004350 }
4351}
4352
4353void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004354 LocationSummary* locations =
4355 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004356 locations->SetInAt(0, Location::RequiresRegister());
4357 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358}
4359
4360void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4361 LocationSummary* locations = instruction->GetLocations();
4362 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004363 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4364 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004365 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004366 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004367}
4368
4369void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004370 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4371 ? LocationSummary::kCallOnSlowPath
4372 : LocationSummary::kNoCall;
4373 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004374 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004375 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004376 if (instruction->HasUses()) {
4377 locations->SetOut(Location::SameAsFirstInput());
4378 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004379}
4380
4381void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4382 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004383 Location index_loc = locations->InAt(0);
4384 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004385 SlowPathCode* slow_path =
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004386 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004387
Mark Mendell99dbd682015-04-22 16:18:52 -04004388 if (length_loc.IsConstant()) {
4389 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4390 if (index_loc.IsConstant()) {
4391 // BCE will remove the bounds check if we are guarenteed to pass.
4392 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4393 if (index < 0 || index >= length) {
4394 codegen_->AddSlowPath(slow_path);
4395 __ jmp(slow_path->GetEntryLabel());
4396 } else {
4397 // Some optimization after BCE may have generated this, and we should not
4398 // generate a bounds check if it is a valid range.
4399 }
4400 return;
4401 }
4402
4403 // We have to reverse the jump condition because the length is the constant.
4404 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4405 __ cmpl(index_reg, Immediate(length));
4406 codegen_->AddSlowPath(slow_path);
4407 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004408 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004409 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4410 if (index_loc.IsConstant()) {
4411 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4412 __ cmpl(length, Immediate(value));
4413 } else {
4414 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4415 }
4416 codegen_->AddSlowPath(slow_path);
4417 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004418 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004419}
4420
4421void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4422 CpuRegister card,
4423 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004424 CpuRegister value,
4425 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004426 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004427 if (value_can_be_null) {
4428 __ testl(value, value);
4429 __ j(kEqual, &is_null);
4430 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004431 __ gs()->movq(card, Address::Absolute(
4432 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4433 __ movq(temp, object);
4434 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004435 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004436 if (value_can_be_null) {
4437 __ Bind(&is_null);
4438 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004439}
4440
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004441void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4442 temp->SetLocations(nullptr);
4443}
4444
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004445void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004446 // Nothing to do, this is driven by the code generator.
4447}
4448
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004449void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004450 LOG(FATAL) << "Unimplemented";
4451}
4452
4453void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004454 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4455}
4456
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004457void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4458 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4459}
4460
4461void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004462 HBasicBlock* block = instruction->GetBlock();
4463 if (block->GetLoopInformation() != nullptr) {
4464 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4465 // The back edge will generate the suspend check.
4466 return;
4467 }
4468 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4469 // The goto will generate the suspend check.
4470 return;
4471 }
4472 GenerateSuspendCheck(instruction, nullptr);
4473}
4474
4475void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4476 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004477 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004478 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4479 if (slow_path == nullptr) {
4480 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4481 instruction->SetSlowPath(slow_path);
4482 codegen_->AddSlowPath(slow_path);
4483 if (successor != nullptr) {
4484 DCHECK(successor->IsLoopHeader());
4485 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4486 }
4487 } else {
4488 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4489 }
4490
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004491 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004492 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004493 if (successor == nullptr) {
4494 __ j(kNotEqual, slow_path->GetEntryLabel());
4495 __ Bind(slow_path->GetReturnLabel());
4496 } else {
4497 __ j(kEqual, codegen_->GetLabelOf(successor));
4498 __ jmp(slow_path->GetEntryLabel());
4499 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004500}
4501
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004502X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4503 return codegen_->GetAssembler();
4504}
4505
4506void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004507 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004508 Location source = move->GetSource();
4509 Location destination = move->GetDestination();
4510
4511 if (source.IsRegister()) {
4512 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004513 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004514 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004515 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004516 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004517 } else {
4518 DCHECK(destination.IsDoubleStackSlot());
4519 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004520 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004521 }
4522 } else if (source.IsStackSlot()) {
4523 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004524 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004525 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004526 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004527 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004528 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004529 } else {
4530 DCHECK(destination.IsStackSlot());
4531 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4532 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4533 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004534 } else if (source.IsDoubleStackSlot()) {
4535 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004536 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004537 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004538 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004539 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4540 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004541 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004542 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004543 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4544 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4545 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004546 } else if (source.IsConstant()) {
4547 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004548 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4549 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004550 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004551 if (value == 0) {
4552 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4553 } else {
4554 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4555 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004556 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004557 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004558 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004559 }
4560 } else if (constant->IsLongConstant()) {
4561 int64_t value = constant->AsLongConstant()->GetValue();
4562 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004563 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004564 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004565 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004566 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004567 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004568 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004569 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004570 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004571 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004572 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4573 if (value == 0) {
4574 // easy FP 0.0.
4575 __ xorps(dest, dest);
4576 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004577 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004578 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004579 } else {
4580 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004581 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004582 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4583 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004584 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004585 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004586 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004587 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004588 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004589 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4590 if (value == 0) {
4591 __ xorpd(dest, dest);
4592 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004593 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004594 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004595 } else {
4596 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004597 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004598 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004599 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004600 } else if (source.IsFpuRegister()) {
4601 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004602 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004603 } else if (destination.IsStackSlot()) {
4604 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004605 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004606 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004607 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004608 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004609 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004610 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004611 }
4612}
4613
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004614void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004615 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004616 __ movl(Address(CpuRegister(RSP), mem), reg);
4617 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004618}
4619
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004620void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004621 ScratchRegisterScope ensure_scratch(
4622 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4623
4624 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4625 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4626 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4627 Address(CpuRegister(RSP), mem2 + stack_offset));
4628 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4629 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4630 CpuRegister(ensure_scratch.GetRegister()));
4631}
4632
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004633void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4634 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4635 __ movq(Address(CpuRegister(RSP), mem), reg);
4636 __ movq(reg, CpuRegister(TMP));
4637}
4638
4639void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4640 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004641 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004642
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004643 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4644 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4645 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4646 Address(CpuRegister(RSP), mem2 + stack_offset));
4647 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4648 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4649 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004650}
4651
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004652void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4653 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4654 __ movss(Address(CpuRegister(RSP), mem), reg);
4655 __ movd(reg, CpuRegister(TMP));
4656}
4657
4658void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4659 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4660 __ movsd(Address(CpuRegister(RSP), mem), reg);
4661 __ movd(reg, CpuRegister(TMP));
4662}
4663
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004664void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004665 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004666 Location source = move->GetSource();
4667 Location destination = move->GetDestination();
4668
4669 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004670 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004671 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004672 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004673 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004674 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004675 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004676 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4677 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004678 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004679 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004680 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004681 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4682 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004683 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004684 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4685 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4686 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004687 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004688 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004689 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004690 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004691 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004692 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004693 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004694 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004695 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004696 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004697 }
4698}
4699
4700
4701void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4702 __ pushq(CpuRegister(reg));
4703}
4704
4705
4706void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4707 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004708}
4709
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004710void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004711 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004712 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4713 Immediate(mirror::Class::kStatusInitialized));
4714 __ j(kLess, slow_path->GetEntryLabel());
4715 __ Bind(slow_path->GetExitLabel());
4716 // No need for memory fence, thanks to the X86_64 memory model.
4717}
4718
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004719void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004720 InvokeRuntimeCallingConvention calling_convention;
4721 CodeGenerator::CreateLoadClassLocationSummary(
4722 cls,
4723 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4724 Location::RegisterLocation(RAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004725}
4726
4727void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004728 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01004729 if (cls->NeedsAccessCheck()) {
4730 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
4731 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
4732 cls,
4733 cls->GetDexPc(),
4734 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01004735 return;
4736 }
4737
4738 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4739 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
4740 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004741 DCHECK(!cls->CanCallRuntime());
4742 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004743 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004744 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004745 DCHECK(cls->CanCallRuntime());
Vladimir Marko05792b92015-08-03 11:56:49 +01004746 __ movq(out, Address(
4747 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004748 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004749 // TODO: We will need a read barrier here.
Roland Levillain4d027112015-07-01 15:41:14 +01004750
Andreas Gampe85b62f22015-09-09 13:15:38 -07004751 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004752 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4753 codegen_->AddSlowPath(slow_path);
4754 __ testl(out, out);
4755 __ j(kEqual, slow_path->GetEntryLabel());
4756 if (cls->MustGenerateClinitCheck()) {
4757 GenerateClassInitializationCheck(slow_path, out);
4758 } else {
4759 __ Bind(slow_path->GetExitLabel());
4760 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004761 }
4762}
4763
4764void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4765 LocationSummary* locations =
4766 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4767 locations->SetInAt(0, Location::RequiresRegister());
4768 if (check->HasUses()) {
4769 locations->SetOut(Location::SameAsFirstInput());
4770 }
4771}
4772
4773void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004774 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004775 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004776 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004777 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004778 GenerateClassInitializationCheck(slow_path,
4779 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004780}
4781
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004782void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4783 LocationSummary* locations =
4784 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004785 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004786 locations->SetOut(Location::RequiresRegister());
4787}
4788
4789void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004790 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004791 codegen_->AddSlowPath(slow_path);
4792
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004793 LocationSummary* locations = load->GetLocations();
4794 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4795 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004796 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004797 __ movq(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004798 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004799 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004800 __ testl(out, out);
4801 __ j(kEqual, slow_path->GetEntryLabel());
4802 __ Bind(slow_path->GetExitLabel());
4803}
4804
David Brazdilcb1c0552015-08-04 16:22:25 +01004805static Address GetExceptionTlsAddress() {
4806 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4807}
4808
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004809void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4810 LocationSummary* locations =
4811 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4812 locations->SetOut(Location::RequiresRegister());
4813}
4814
4815void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004816 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4817}
4818
4819void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4820 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4821}
4822
4823void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4824 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004825}
4826
4827void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4828 LocationSummary* locations =
4829 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4830 InvokeRuntimeCallingConvention calling_convention;
4831 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4832}
4833
4834void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004835 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4836 instruction,
4837 instruction->GetDexPc(),
4838 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004839}
4840
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004841void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004842 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4843 switch (instruction->GetTypeCheckKind()) {
4844 case TypeCheckKind::kExactCheck:
4845 case TypeCheckKind::kAbstractClassCheck:
4846 case TypeCheckKind::kClassHierarchyCheck:
4847 case TypeCheckKind::kArrayObjectCheck:
4848 call_kind = LocationSummary::kNoCall;
4849 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004850 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004851 case TypeCheckKind::kInterfaceCheck:
4852 call_kind = LocationSummary::kCall;
4853 break;
4854 case TypeCheckKind::kArrayCheck:
4855 call_kind = LocationSummary::kCallOnSlowPath;
4856 break;
4857 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004858 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004859 if (call_kind != LocationSummary::kCall) {
4860 locations->SetInAt(0, Location::RequiresRegister());
4861 locations->SetInAt(1, Location::Any());
4862 // Note that TypeCheckSlowPathX86_64 uses this register too.
4863 locations->SetOut(Location::RequiresRegister());
4864 } else {
4865 InvokeRuntimeCallingConvention calling_convention;
4866 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4867 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4868 locations->SetOut(Location::RegisterLocation(RAX));
4869 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004870}
4871
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004872void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004873 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004874 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004875 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004876 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004877 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004878 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4879 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4880 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004881 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004882 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004883
4884 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004885 // Avoid null check if we know obj is not null.
4886 if (instruction->MustDoNullCheck()) {
4887 __ testl(obj, obj);
4888 __ j(kEqual, &zero);
4889 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004890
Calin Juravle98893e12015-10-02 21:05:03 +01004891 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004892 // This is safe, as the register is caller-save, and the object must be in another
4893 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01004894 CpuRegister target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
4895 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004896 ? obj
4897 : out;
4898 __ movl(target, Address(obj, class_offset));
4899 __ MaybeUnpoisonHeapReference(target);
4900
4901 switch (instruction->GetTypeCheckKind()) {
4902 case TypeCheckKind::kExactCheck: {
4903 if (cls.IsRegister()) {
4904 __ cmpl(out, cls.AsRegister<CpuRegister>());
4905 } else {
4906 DCHECK(cls.IsStackSlot()) << cls;
4907 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4908 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004909 if (zero.IsLinked()) {
4910 // Classes must be equal for the instanceof to succeed.
4911 __ j(kNotEqual, &zero);
4912 __ movl(out, Immediate(1));
4913 __ jmp(&done);
4914 } else {
4915 __ setcc(kEqual, out);
4916 // setcc only sets the low byte.
4917 __ andl(out, Immediate(1));
4918 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004919 break;
4920 }
4921 case TypeCheckKind::kAbstractClassCheck: {
4922 // If the class is abstract, we eagerly fetch the super class of the
4923 // object to avoid doing a comparison we know will fail.
4924 NearLabel loop, success;
4925 __ Bind(&loop);
4926 __ movl(out, Address(out, super_offset));
4927 __ MaybeUnpoisonHeapReference(out);
4928 __ testl(out, out);
4929 // If `out` is null, we use it for the result, and jump to `done`.
4930 __ j(kEqual, &done);
4931 if (cls.IsRegister()) {
4932 __ cmpl(out, cls.AsRegister<CpuRegister>());
4933 } else {
4934 DCHECK(cls.IsStackSlot()) << cls;
4935 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4936 }
4937 __ j(kNotEqual, &loop);
4938 __ movl(out, Immediate(1));
4939 if (zero.IsLinked()) {
4940 __ jmp(&done);
4941 }
4942 break;
4943 }
4944 case TypeCheckKind::kClassHierarchyCheck: {
4945 // Walk over the class hierarchy to find a match.
4946 NearLabel loop, success;
4947 __ Bind(&loop);
4948 if (cls.IsRegister()) {
4949 __ cmpl(out, cls.AsRegister<CpuRegister>());
4950 } else {
4951 DCHECK(cls.IsStackSlot()) << cls;
4952 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4953 }
4954 __ j(kEqual, &success);
4955 __ movl(out, Address(out, super_offset));
4956 __ MaybeUnpoisonHeapReference(out);
4957 __ testl(out, out);
4958 __ j(kNotEqual, &loop);
4959 // If `out` is null, we use it for the result, and jump to `done`.
4960 __ jmp(&done);
4961 __ Bind(&success);
4962 __ movl(out, Immediate(1));
4963 if (zero.IsLinked()) {
4964 __ jmp(&done);
4965 }
4966 break;
4967 }
4968 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004969 // Do an exact check.
4970 NearLabel exact_check;
4971 if (cls.IsRegister()) {
4972 __ cmpl(out, cls.AsRegister<CpuRegister>());
4973 } else {
4974 DCHECK(cls.IsStackSlot()) << cls;
4975 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4976 }
4977 __ j(kEqual, &exact_check);
4978 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004979 __ movl(out, Address(out, component_offset));
4980 __ MaybeUnpoisonHeapReference(out);
4981 __ testl(out, out);
4982 // If `out` is null, we use it for the result, and jump to `done`.
4983 __ j(kEqual, &done);
4984 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
4985 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004986 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004987 __ movl(out, Immediate(1));
4988 __ jmp(&done);
4989 break;
4990 }
4991 case TypeCheckKind::kArrayCheck: {
4992 if (cls.IsRegister()) {
4993 __ cmpl(out, cls.AsRegister<CpuRegister>());
4994 } else {
4995 DCHECK(cls.IsStackSlot()) << cls;
4996 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4997 }
4998 DCHECK(locations->OnlyCallsOnSlowPath());
4999 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
5000 instruction, /* is_fatal */ false);
5001 codegen_->AddSlowPath(slow_path);
5002 __ j(kNotEqual, slow_path->GetEntryLabel());
5003 __ movl(out, Immediate(1));
5004 if (zero.IsLinked()) {
5005 __ jmp(&done);
5006 }
5007 break;
5008 }
Calin Juravle98893e12015-10-02 21:05:03 +01005009 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005010 case TypeCheckKind::kInterfaceCheck:
5011 default: {
5012 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5013 instruction,
5014 instruction->GetDexPc(),
5015 nullptr);
5016 if (zero.IsLinked()) {
5017 __ jmp(&done);
5018 }
5019 break;
5020 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005021 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005022
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005023 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005024 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005025 __ xorl(out, out);
5026 }
5027
5028 if (done.IsLinked()) {
5029 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005030 }
5031
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005032 if (slow_path != nullptr) {
5033 __ Bind(slow_path->GetExitLabel());
5034 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005035}
5036
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005037void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005038 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5039 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5040
5041 switch (instruction->GetTypeCheckKind()) {
5042 case TypeCheckKind::kExactCheck:
5043 case TypeCheckKind::kAbstractClassCheck:
5044 case TypeCheckKind::kClassHierarchyCheck:
5045 case TypeCheckKind::kArrayObjectCheck:
5046 call_kind = throws_into_catch
5047 ? LocationSummary::kCallOnSlowPath
5048 : LocationSummary::kNoCall;
5049 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005050 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005051 case TypeCheckKind::kInterfaceCheck:
5052 call_kind = LocationSummary::kCall;
5053 break;
5054 case TypeCheckKind::kArrayCheck:
5055 call_kind = LocationSummary::kCallOnSlowPath;
5056 break;
5057 }
5058
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005059 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005060 instruction, call_kind);
5061 if (call_kind != LocationSummary::kCall) {
5062 locations->SetInAt(0, Location::RequiresRegister());
5063 locations->SetInAt(1, Location::Any());
5064 // Note that TypeCheckSlowPathX86_64 uses this register too.
5065 locations->AddTemp(Location::RequiresRegister());
5066 } else {
5067 InvokeRuntimeCallingConvention calling_convention;
5068 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5069 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5070 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005071}
5072
5073void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
5074 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005075 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005076 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005077 CpuRegister temp = locations->WillCall()
5078 ? CpuRegister(kNoRegister)
5079 : locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005080
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005081 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5082 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5083 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5084 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5085 SlowPathCode* slow_path = nullptr;
5086
5087 if (!locations->WillCall()) {
5088 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
5089 instruction, !locations->CanCall());
5090 codegen_->AddSlowPath(slow_path);
5091 }
5092
5093 NearLabel done;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005094 // Avoid null check if we know obj is not null.
5095 if (instruction->MustDoNullCheck()) {
5096 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005097 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005098 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005099
5100 if (locations->WillCall()) {
5101 __ movl(obj, Address(obj, class_offset));
5102 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005103 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005104 __ movl(temp, Address(obj, class_offset));
5105 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005106 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005107
5108 switch (instruction->GetTypeCheckKind()) {
5109 case TypeCheckKind::kExactCheck:
5110 case TypeCheckKind::kArrayCheck: {
5111 if (cls.IsRegister()) {
5112 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5113 } else {
5114 DCHECK(cls.IsStackSlot()) << cls;
5115 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5116 }
5117 // Jump to slow path for throwing the exception or doing a
5118 // more involved array check.
5119 __ j(kNotEqual, slow_path->GetEntryLabel());
5120 break;
5121 }
5122 case TypeCheckKind::kAbstractClassCheck: {
5123 // If the class is abstract, we eagerly fetch the super class of the
5124 // object to avoid doing a comparison we know will fail.
5125 NearLabel loop;
5126 __ Bind(&loop);
5127 __ movl(temp, Address(temp, super_offset));
5128 __ MaybeUnpoisonHeapReference(temp);
5129 __ testl(temp, temp);
5130 // Jump to the slow path to throw the exception.
5131 __ j(kEqual, slow_path->GetEntryLabel());
5132 if (cls.IsRegister()) {
5133 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5134 } else {
5135 DCHECK(cls.IsStackSlot()) << cls;
5136 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5137 }
5138 __ j(kNotEqual, &loop);
5139 break;
5140 }
5141 case TypeCheckKind::kClassHierarchyCheck: {
5142 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005143 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005144 __ Bind(&loop);
5145 if (cls.IsRegister()) {
5146 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5147 } else {
5148 DCHECK(cls.IsStackSlot()) << cls;
5149 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5150 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005151 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005152 __ movl(temp, Address(temp, super_offset));
5153 __ MaybeUnpoisonHeapReference(temp);
5154 __ testl(temp, temp);
5155 __ j(kNotEqual, &loop);
5156 // Jump to the slow path to throw the exception.
5157 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005158 break;
5159 }
5160 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005161 // Do an exact check.
5162 if (cls.IsRegister()) {
5163 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5164 } else {
5165 DCHECK(cls.IsStackSlot()) << cls;
5166 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5167 }
5168 __ j(kEqual, &done);
5169 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005170 __ movl(temp, Address(temp, component_offset));
5171 __ MaybeUnpoisonHeapReference(temp);
5172 __ testl(temp, temp);
5173 __ j(kEqual, slow_path->GetEntryLabel());
5174 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5175 __ j(kNotEqual, slow_path->GetEntryLabel());
5176 break;
5177 }
Calin Juravle98893e12015-10-02 21:05:03 +01005178 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005179 case TypeCheckKind::kInterfaceCheck:
5180 default:
5181 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5182 instruction,
5183 instruction->GetDexPc(),
5184 nullptr);
5185 break;
5186 }
5187 __ Bind(&done);
5188
5189 if (slow_path != nullptr) {
5190 __ Bind(slow_path->GetExitLabel());
5191 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005192}
5193
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005194void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
5195 LocationSummary* locations =
5196 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5197 InvokeRuntimeCallingConvention calling_convention;
5198 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5199}
5200
5201void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005202 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5203 : QUICK_ENTRY_POINT(pUnlockObject),
5204 instruction,
5205 instruction->GetDexPc(),
5206 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005207}
5208
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005209void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5210void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5211void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5212
5213void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5214 LocationSummary* locations =
5215 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5216 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5217 || instruction->GetResultType() == Primitive::kPrimLong);
5218 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04005219 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005220 locations->SetOut(Location::SameAsFirstInput());
5221}
5222
5223void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
5224 HandleBitwiseOperation(instruction);
5225}
5226
5227void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
5228 HandleBitwiseOperation(instruction);
5229}
5230
5231void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
5232 HandleBitwiseOperation(instruction);
5233}
5234
5235void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5236 LocationSummary* locations = instruction->GetLocations();
5237 Location first = locations->InAt(0);
5238 Location second = locations->InAt(1);
5239 DCHECK(first.Equals(locations->Out()));
5240
5241 if (instruction->GetResultType() == Primitive::kPrimInt) {
5242 if (second.IsRegister()) {
5243 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005244 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005245 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005246 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005247 } else {
5248 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005249 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005250 }
5251 } else if (second.IsConstant()) {
5252 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
5253 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005254 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005255 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005256 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005257 } else {
5258 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005259 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005260 }
5261 } else {
5262 Address address(CpuRegister(RSP), second.GetStackIndex());
5263 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005264 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005265 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005266 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005267 } else {
5268 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005269 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005270 }
5271 }
5272 } else {
5273 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005274 CpuRegister first_reg = first.AsRegister<CpuRegister>();
5275 bool second_is_constant = false;
5276 int64_t value = 0;
5277 if (second.IsConstant()) {
5278 second_is_constant = true;
5279 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005280 }
Mark Mendell40741f32015-04-20 22:10:34 -04005281 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005282
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005283 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005284 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005285 if (is_int32_value) {
5286 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
5287 } else {
5288 __ andq(first_reg, codegen_->LiteralInt64Address(value));
5289 }
5290 } else if (second.IsDoubleStackSlot()) {
5291 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005292 } else {
5293 __ andq(first_reg, second.AsRegister<CpuRegister>());
5294 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005295 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005296 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005297 if (is_int32_value) {
5298 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
5299 } else {
5300 __ orq(first_reg, codegen_->LiteralInt64Address(value));
5301 }
5302 } else if (second.IsDoubleStackSlot()) {
5303 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005304 } else {
5305 __ orq(first_reg, second.AsRegister<CpuRegister>());
5306 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005307 } else {
5308 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005309 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005310 if (is_int32_value) {
5311 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
5312 } else {
5313 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
5314 }
5315 } else if (second.IsDoubleStackSlot()) {
5316 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005317 } else {
5318 __ xorq(first_reg, second.AsRegister<CpuRegister>());
5319 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005320 }
5321 }
5322}
5323
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005324void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005325 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005326 LOG(FATAL) << "Unreachable";
5327}
5328
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005329void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005330 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005331 LOG(FATAL) << "Unreachable";
5332}
5333
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005334void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
5335 DCHECK(codegen_->IsBaseline());
5336 LocationSummary* locations =
5337 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5338 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5339}
5340
5341void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5342 DCHECK(codegen_->IsBaseline());
5343 // Will be generated at use site.
5344}
5345
Mark Mendellfe57faa2015-09-18 09:26:15 -04005346// Simple implementation of packed switch - generate cascaded compare/jumps.
5347void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5348 LocationSummary* locations =
5349 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5350 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04005351 locations->AddTemp(Location::RequiresRegister());
5352 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04005353}
5354
5355void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5356 int32_t lower_bound = switch_instr->GetStartValue();
5357 int32_t num_entries = switch_instr->GetNumEntries();
5358 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04005359 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
5360 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
5361 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
5362
5363 // Remove the bias, if needed.
5364 Register value_reg_out = value_reg_in.AsRegister();
5365 if (lower_bound != 0) {
5366 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
5367 value_reg_out = temp_reg.AsRegister();
5368 }
5369 CpuRegister value_reg(value_reg_out);
5370
5371 // Is the value in range?
Mark Mendellfe57faa2015-09-18 09:26:15 -04005372 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
Mark Mendell9c86b482015-09-18 13:36:07 -04005373 __ cmpl(value_reg, Immediate(num_entries - 1));
5374 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005375
Mark Mendell9c86b482015-09-18 13:36:07 -04005376 // We are in the range of the table.
5377 // Load the address of the jump table in the constant area.
5378 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005379
Mark Mendell9c86b482015-09-18 13:36:07 -04005380 // Load the (signed) offset from the jump table.
5381 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
5382
5383 // Add the offset to the address of the table base.
5384 __ addq(temp_reg, base_reg);
5385
5386 // And jump.
5387 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04005388}
5389
Mark Mendell92e83bf2015-05-07 11:25:03 -04005390void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
5391 if (value == 0) {
5392 __ xorl(dest, dest);
5393 } else if (value > 0 && IsInt<32>(value)) {
5394 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
5395 __ movl(dest, Immediate(static_cast<int32_t>(value)));
5396 } else {
5397 __ movq(dest, Immediate(value));
5398 }
5399}
5400
Mark Mendellcfa410b2015-05-25 16:02:44 -04005401void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
5402 DCHECK(dest.IsDoubleStackSlot());
5403 if (IsInt<32>(value)) {
5404 // Can move directly as an int32 constant.
5405 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
5406 Immediate(static_cast<int32_t>(value)));
5407 } else {
5408 Load64BitValue(CpuRegister(TMP), value);
5409 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
5410 }
5411}
5412
Mark Mendell9c86b482015-09-18 13:36:07 -04005413/**
5414 * Class to handle late fixup of offsets into constant area.
5415 */
5416class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
5417 public:
5418 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
5419 : codegen_(&codegen), offset_into_constant_area_(offset) {}
5420
5421 protected:
5422 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
5423
5424 CodeGeneratorX86_64* codegen_;
5425
5426 private:
5427 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5428 // Patch the correct offset for the instruction. We use the address of the
5429 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
5430 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
5431 int32_t relative_position = constant_offset - pos;
5432
5433 // Patch in the right value.
5434 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5435 }
5436
5437 // Location in constant area that the fixup refers to.
5438 size_t offset_into_constant_area_;
5439};
5440
5441/**
5442 t * Class to handle late fixup of offsets to a jump table that will be created in the
5443 * constant area.
5444 */
5445class JumpTableRIPFixup : public RIPFixup {
5446 public:
5447 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
5448 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
5449
5450 void CreateJumpTable() {
5451 X86_64Assembler* assembler = codegen_->GetAssembler();
5452
5453 // Ensure that the reference to the jump table has the correct offset.
5454 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
5455 SetOffset(offset_in_constant_table);
5456
5457 // Compute the offset from the start of the function to this jump table.
5458 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
5459
5460 // Populate the jump table with the correct values for the jump table.
5461 int32_t num_entries = switch_instr_->GetNumEntries();
5462 HBasicBlock* block = switch_instr_->GetBlock();
5463 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
5464 // The value that we want is the target offset - the position of the table.
5465 for (int32_t i = 0; i < num_entries; i++) {
5466 HBasicBlock* b = successors[i];
5467 Label* l = codegen_->GetLabelOf(b);
5468 DCHECK(l->IsBound());
5469 int32_t offset_to_block = l->Position() - current_table_offset;
5470 assembler->AppendInt32(offset_to_block);
5471 }
5472 }
5473
5474 private:
5475 const HPackedSwitch* switch_instr_;
5476};
5477
Mark Mendellf55c3e02015-03-26 21:07:46 -04005478void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
5479 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04005480 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04005481 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
5482 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8 byte values.
Mark Mendell39dcf552015-04-09 20:42:42 -04005483 assembler->Align(4, 0);
5484 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04005485
5486 // Populate any jump tables.
5487 for (auto jump_table : fixups_to_jump_tables_) {
5488 jump_table->CreateJumpTable();
5489 }
5490
5491 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04005492 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04005493 }
5494
5495 // And finish up.
5496 CodeGenerator::Finalize(allocator);
5497}
5498
Mark Mendellf55c3e02015-03-26 21:07:46 -04005499Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
5500 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5501 return Address::RIP(fixup);
5502}
5503
5504Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
5505 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5506 return Address::RIP(fixup);
5507}
5508
5509Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
5510 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5511 return Address::RIP(fixup);
5512}
5513
5514Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
5515 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5516 return Address::RIP(fixup);
5517}
5518
Andreas Gampe85b62f22015-09-09 13:15:38 -07005519// TODO: trg as memory.
5520void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5521 if (!trg.IsValid()) {
5522 DCHECK(type == Primitive::kPrimVoid);
5523 return;
5524 }
5525
5526 DCHECK_NE(type, Primitive::kPrimVoid);
5527
5528 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
5529 if (trg.Equals(return_loc)) {
5530 return;
5531 }
5532
5533 // Let the parallel move resolver take care of all of this.
5534 HParallelMove parallel_move(GetGraph()->GetArena());
5535 parallel_move.AddMove(return_loc, trg, type, nullptr);
5536 GetMoveResolver()->EmitNativeCode(&parallel_move);
5537}
5538
Mark Mendell9c86b482015-09-18 13:36:07 -04005539Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
5540 // Create a fixup to be used to create and address the jump table.
5541 JumpTableRIPFixup* table_fixup =
5542 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
5543
5544 // We have to populate the jump tables.
5545 fixups_to_jump_tables_.push_back(table_fixup);
5546 return Address::RIP(table_fixup);
5547}
5548
Roland Levillain4d027112015-07-01 15:41:14 +01005549#undef __
5550
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005551} // namespace x86_64
5552} // namespace art