blob: 5757787f9871ee57e1368e79b69a49c7d2a6d47b [file] [log] [blame]
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_x86_64.h"
18
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010020#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000021#include "compiled_method.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010022#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010023#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080024#include "intrinsics.h"
25#include "intrinsics_x86_64.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070026#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070027#include "mirror/class-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "mirror/object_reference.h"
29#include "thread.h"
30#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010031#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010032#include "utils/x86_64/assembler_x86_64.h"
33#include "utils/x86_64/managed_register_x86_64.h"
34
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010035namespace art {
36
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010037namespace x86_64 {
38
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010039// Some x86_64 instructions require a register to be available as temp.
40static constexpr Register TMP = R11;
41
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010042static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010043static constexpr Register kMethodRegisterArgument = RDI;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010044
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000045static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000046static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010047
Mark Mendell24f2dfa2015-01-14 19:51:45 -050048static constexpr int kC2ConditionMask = 0x400;
49
Roland Levillain62a46b22015-06-01 18:24:13 +010050#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
Calin Juravle175dc732015-08-25 15:42:32 +010051#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010052
Andreas Gampe85b62f22015-09-09 13:15:38 -070053class NullCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010054 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010055 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056
Alexandre Rames2ed20af2015-03-06 13:55:35 +000057 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010058 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000060 if (instruction_->CanThrowIntoCatchBlock()) {
61 // Live registers will be restored in the catch block if caught.
62 SaveLiveRegisters(codegen, instruction_->GetLocations());
63 }
Alexandre Rames8158f282015-08-07 10:26:17 +010064 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
65 instruction_,
66 instruction_->GetDexPc(),
67 this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 }
69
Alexandre Rames8158f282015-08-07 10:26:17 +010070 bool IsFatal() const OVERRIDE { return true; }
71
Alexandre Rames9931f312015-06-19 14:47:01 +010072 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
73
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
77};
78
Andreas Gampe85b62f22015-09-09 13:15:38 -070079class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000080 public:
81 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
82
Alexandre Rames2ed20af2015-03-06 13:55:35 +000083 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010084 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000085 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000086 if (instruction_->CanThrowIntoCatchBlock()) {
87 // Live registers will be restored in the catch block if caught.
88 SaveLiveRegisters(codegen, instruction_->GetLocations());
89 }
Alexandre Rames8158f282015-08-07 10:26:17 +010090 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
91 instruction_,
92 instruction_->GetDexPc(),
93 this);
Calin Juravled0d48522014-11-04 16:40:20 +000094 }
95
Alexandre Rames8158f282015-08-07 10:26:17 +010096 bool IsFatal() const OVERRIDE { return true; }
97
Alexandre Rames9931f312015-06-19 14:47:01 +010098 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
99
Calin Juravled0d48522014-11-04 16:40:20 +0000100 private:
101 HDivZeroCheck* const instruction_;
102 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
103};
104
Andreas Gampe85b62f22015-09-09 13:15:38 -0700105class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000106 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100107 DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
Calin Juravlebacfec32014-11-14 15:54:36 +0000108 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000109
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000110 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000111 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000112 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000113 if (is_div_) {
114 __ negl(cpu_reg_);
115 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400116 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000117 }
118
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000119 } else {
120 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000121 if (is_div_) {
122 __ negq(cpu_reg_);
123 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400124 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 }
Calin Juravled0d48522014-11-04 16:40:20 +0000127 __ jmp(GetExitLabel());
128 }
129
Alexandre Rames9931f312015-06-19 14:47:01 +0100130 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
131
Calin Juravled0d48522014-11-04 16:40:20 +0000132 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000133 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000134 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000135 const bool is_div_;
136 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000137};
138
Andreas Gampe85b62f22015-09-09 13:15:38 -0700139class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100141 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100142 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000144 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100145 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000146 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000147 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100148 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
149 instruction_,
150 instruction_->GetDexPc(),
151 this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000152 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100153 if (successor_ == nullptr) {
154 __ jmp(GetReturnLabel());
155 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100156 __ jmp(x64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100157 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000158 }
159
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100160 Label* GetReturnLabel() {
161 DCHECK(successor_ == nullptr);
162 return &return_label_;
163 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000164
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100165 HBasicBlock* GetSuccessor() const {
166 return successor_;
167 }
168
Alexandre Rames9931f312015-06-19 14:47:01 +0100169 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
170
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000171 private:
172 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100173 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000174 Label return_label_;
175
176 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
177};
178
Andreas Gampe85b62f22015-09-09 13:15:38 -0700179class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100181 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
182 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000184 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100185 LocationSummary* locations = instruction_->GetLocations();
Alexandre Rames8158f282015-08-07 10:26:17 +0100186 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000188 if (instruction_->CanThrowIntoCatchBlock()) {
189 // Live registers will be restored in the catch block if caught.
190 SaveLiveRegisters(codegen, instruction_->GetLocations());
191 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000192 // We're moving two locations to locations that could overlap, so we need a parallel
193 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100194 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000195 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100196 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000197 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100198 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100199 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100200 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
201 Primitive::kPrimInt);
Alexandre Rames8158f282015-08-07 10:26:17 +0100202 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
203 instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100204 }
205
Alexandre Rames8158f282015-08-07 10:26:17 +0100206 bool IsFatal() const OVERRIDE { return true; }
207
Alexandre Rames9931f312015-06-19 14:47:01 +0100208 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
209
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100210 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100211 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100212
213 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
214};
215
Andreas Gampe85b62f22015-09-09 13:15:38 -0700216class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100217 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000218 LoadClassSlowPathX86_64(HLoadClass* cls,
219 HInstruction* at,
220 uint32_t dex_pc,
221 bool do_clinit)
222 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
223 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
224 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100225
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000226 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000227 LocationSummary* locations = at_->GetLocations();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
229 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000231 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000232
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100233 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000234 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100235 x64_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
236 : QUICK_ENTRY_POINT(pInitializeType),
237 at_, dex_pc_, this);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100238
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000239 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000240 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000241 if (out.IsValid()) {
242 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
243 x64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000244 }
245
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000246 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100247 __ jmp(GetExitLabel());
248 }
249
Alexandre Rames9931f312015-06-19 14:47:01 +0100250 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
251
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100252 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000253 // The class this slow path will load.
254 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100255
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000256 // The instruction where this slow path is happening.
257 // (Might be the load class or an initialization check).
258 HInstruction* const at_;
259
260 // The dex PC of `at_`.
261 const uint32_t dex_pc_;
262
263 // Whether to initialize the class.
264 const bool do_clinit_;
265
266 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100267};
268
Andreas Gampe85b62f22015-09-09 13:15:38 -0700269class LoadStringSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000270 public:
271 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
272
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000273 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000274 LocationSummary* locations = instruction_->GetLocations();
275 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
276
277 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
278 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000279 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000280
281 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800282 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000283 Immediate(instruction_->GetStringIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100284 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
285 instruction_,
286 instruction_->GetDexPc(),
287 this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000288 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000289 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000290 __ jmp(GetExitLabel());
291 }
292
Alexandre Rames9931f312015-06-19 14:47:01 +0100293 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
294
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000295 private:
296 HLoadString* const instruction_;
297
298 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
299};
300
Andreas Gampe85b62f22015-09-09 13:15:38 -0700301class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000302 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000303 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
304 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000305
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000306 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000307 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100308 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
309 : locations->Out();
310 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000311 DCHECK(instruction_->IsCheckCast()
312 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313
314 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
315 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000316
317 if (instruction_->IsCheckCast()) {
318 // The codegen for the instruction overwrites `temp`, so put it back in place.
319 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
320 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
321 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
322 __ movl(temp, Address(obj, class_offset));
323 __ MaybeUnpoisonHeapReference(temp);
324 }
325
326 if (!is_fatal_) {
327 SaveLiveRegisters(codegen, locations);
328 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000329
330 // We're moving two locations to locations that could overlap, so we need a parallel
331 // move resolver.
332 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000333 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100334 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000335 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100336 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100337 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100338 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
339 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000341 if (instruction_->IsInstanceOf()) {
Alexandre Rames8158f282015-08-07 10:26:17 +0100342 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
343 instruction_,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100344 dex_pc,
Alexandre Rames8158f282015-08-07 10:26:17 +0100345 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000346 } else {
347 DCHECK(instruction_->IsCheckCast());
Alexandre Rames8158f282015-08-07 10:26:17 +0100348 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
349 instruction_,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100350 dex_pc,
Alexandre Rames8158f282015-08-07 10:26:17 +0100351 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000352 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000353
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000354 if (!is_fatal_) {
355 if (instruction_->IsInstanceOf()) {
356 x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
357 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000358
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000359 RestoreLiveRegisters(codegen, locations);
360 __ jmp(GetExitLabel());
361 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000362 }
363
Alexandre Rames9931f312015-06-19 14:47:01 +0100364 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
365
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000366 bool IsFatal() const OVERRIDE { return is_fatal_; }
367
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000368 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000369 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000370 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000371
372 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
373};
374
Andreas Gampe85b62f22015-09-09 13:15:38 -0700375class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700376 public:
377 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
378 : instruction_(instruction) {}
379
380 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +0100381 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700382 __ Bind(GetEntryLabel());
383 SaveLiveRegisters(codegen, instruction_->GetLocations());
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700384 DCHECK(instruction_->IsDeoptimize());
385 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
Alexandre Rames8158f282015-08-07 10:26:17 +0100386 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
387 deoptimize,
388 deoptimize->GetDexPc(),
389 this);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700390 }
391
Alexandre Rames9931f312015-06-19 14:47:01 +0100392 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
393
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700394 private:
395 HInstruction* const instruction_;
396 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
397};
398
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100399class ArraySetSlowPathX86_64 : public SlowPathCode {
400 public:
401 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : instruction_(instruction) {}
402
403 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
404 LocationSummary* locations = instruction_->GetLocations();
405 __ Bind(GetEntryLabel());
406 SaveLiveRegisters(codegen, locations);
407
408 InvokeRuntimeCallingConvention calling_convention;
409 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
410 parallel_move.AddMove(
411 locations->InAt(0),
412 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
413 Primitive::kPrimNot,
414 nullptr);
415 parallel_move.AddMove(
416 locations->InAt(1),
417 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
418 Primitive::kPrimInt,
419 nullptr);
420 parallel_move.AddMove(
421 locations->InAt(2),
422 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
423 Primitive::kPrimNot,
424 nullptr);
425 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
426
427 CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
428 x64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
429 instruction_,
430 instruction_->GetDexPc(),
431 this);
432 RestoreLiveRegisters(codegen, locations);
433 __ jmp(GetExitLabel());
434 }
435
436 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86_64"; }
437
438 private:
439 HInstruction* const instruction_;
440
441 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
442};
443
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100444#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100445#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100446
Roland Levillain4fa13f62015-07-06 18:11:54 +0100447inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700448 switch (cond) {
449 case kCondEQ: return kEqual;
450 case kCondNE: return kNotEqual;
451 case kCondLT: return kLess;
452 case kCondLE: return kLessEqual;
453 case kCondGT: return kGreater;
454 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700455 case kCondB: return kBelow;
456 case kCondBE: return kBelowEqual;
457 case kCondA: return kAbove;
458 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700459 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100460 LOG(FATAL) << "Unreachable";
461 UNREACHABLE();
462}
463
Aart Bike9f37602015-10-09 11:15:55 -0700464// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100465inline Condition X86_64FPCondition(IfCondition cond) {
466 switch (cond) {
467 case kCondEQ: return kEqual;
468 case kCondNE: return kNotEqual;
469 case kCondLT: return kBelow;
470 case kCondLE: return kBelowEqual;
471 case kCondGT: return kAbove;
472 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700473 default: break; // should not happen
Roland Levillain4fa13f62015-07-06 18:11:54 +0100474 };
475 LOG(FATAL) << "Unreachable";
476 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700477}
478
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800479void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100480 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800481 // All registers are assumed to be correctly set up.
482
Vladimir Marko58155012015-08-19 12:49:41 +0000483 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
484 switch (invoke->GetMethodLoadKind()) {
485 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
486 // temp = thread->string_init_entrypoint
487 __ gs()->movl(temp.AsRegister<CpuRegister>(),
488 Address::Absolute(invoke->GetStringInitOffset(), true));
489 break;
490 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
491 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
492 break;
493 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
494 __ movq(temp.AsRegister<CpuRegister>(), Immediate(invoke->GetMethodAddress()));
495 break;
496 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
497 __ movl(temp.AsRegister<CpuRegister>(), Immediate(0)); // Placeholder.
498 method_patches_.emplace_back(invoke->GetTargetMethod());
499 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
500 break;
501 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
502 pc_rel_dex_cache_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
503 invoke->GetDexCacheArrayOffset());
504 __ movq(temp.AsRegister<CpuRegister>(),
505 Address::Absolute(kDummy32BitOffset, false /* no_rip */));
506 // Bind the label at the end of the "movl" insn.
507 __ Bind(&pc_rel_dex_cache_patches_.back().label);
508 break;
509 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
510 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
511 Register method_reg;
512 CpuRegister reg = temp.AsRegister<CpuRegister>();
513 if (current_method.IsRegister()) {
514 method_reg = current_method.AsRegister<Register>();
515 } else {
516 DCHECK(invoke->GetLocations()->Intrinsified());
517 DCHECK(!current_method.IsValid());
518 method_reg = reg.AsRegister();
519 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
520 }
521 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +0100522 __ movq(reg,
523 Address(CpuRegister(method_reg),
524 ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +0000525 // temp = temp[index_in_cache]
526 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
527 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
528 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +0100529 }
Vladimir Marko58155012015-08-19 12:49:41 +0000530 }
531
532 switch (invoke->GetCodePtrLocation()) {
533 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
534 __ call(&frame_entry_label_);
535 break;
536 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
537 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
538 Label* label = &relative_call_patches_.back().label;
539 __ call(label); // Bind to the patch label, override at link time.
540 __ Bind(label); // Bind the label at the end of the "call" insn.
541 break;
542 }
543 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
544 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
545 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
546 FALLTHROUGH_INTENDED;
547 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
548 // (callee_method + offset_of_quick_compiled_code)()
549 __ call(Address(callee_method.AsRegister<CpuRegister>(),
550 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
551 kX86_64WordSize).SizeValue()));
552 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000553 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800554
555 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800556}
557
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000558void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
559 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
560 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
561 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
562 LocationSummary* locations = invoke->GetLocations();
563 Location receiver = locations->InAt(0);
564 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
565 // temp = object->GetClass();
566 DCHECK(receiver.IsRegister());
567 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
568 MaybeRecordImplicitNullCheck(invoke);
569 __ MaybeUnpoisonHeapReference(temp);
570 // temp = temp->GetMethodAt(method_offset);
571 __ movq(temp, Address(temp, method_offset));
572 // call temp->GetEntryPoint();
573 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
574 kX86_64WordSize).SizeValue()));
575}
576
Vladimir Marko58155012015-08-19 12:49:41 +0000577void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
578 DCHECK(linker_patches->empty());
579 size_t size =
580 method_patches_.size() + relative_call_patches_.size() + pc_rel_dex_cache_patches_.size();
581 linker_patches->reserve(size);
582 for (const MethodPatchInfo<Label>& info : method_patches_) {
583 // The label points to the end of the "movl" instruction but the literal offset for method
584 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
585 uint32_t literal_offset = info.label.Position() - 4;
586 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
587 info.target_method.dex_file,
588 info.target_method.dex_method_index));
589 }
590 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
591 // The label points to the end of the "call" instruction but the literal offset for method
592 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
593 uint32_t literal_offset = info.label.Position() - 4;
594 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
595 info.target_method.dex_file,
596 info.target_method.dex_method_index));
597 }
598 for (const PcRelativeDexCacheAccessInfo& info : pc_rel_dex_cache_patches_) {
599 // The label points to the end of the "mov" instruction but the literal offset for method
600 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
601 uint32_t literal_offset = info.label.Position() - 4;
602 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
603 &info.target_dex_file,
604 info.label.Position(),
605 info.element_offset));
606 }
607}
608
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100609void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100610 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100611}
612
613void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100614 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100615}
616
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100617size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
618 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
619 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100620}
621
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100622size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
623 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
624 return kX86_64WordSize;
625}
626
627size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
628 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
629 return kX86_64WordSize;
630}
631
632size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
633 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
634 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100635}
636
Calin Juravle175dc732015-08-25 15:42:32 +0100637void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
638 HInstruction* instruction,
639 uint32_t dex_pc,
640 SlowPathCode* slow_path) {
641 InvokeRuntime(GetThreadOffset<kX86_64WordSize>(entrypoint).Int32Value(),
642 instruction,
643 dex_pc,
644 slow_path);
645}
646
647void CodeGeneratorX86_64::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100648 HInstruction* instruction,
649 uint32_t dex_pc,
650 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100651 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100652 __ gs()->call(Address::Absolute(entry_point_offset, true));
Alexandre Rames8158f282015-08-07 10:26:17 +0100653 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100654}
655
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000656static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000657// Use a fake return address register to mimic Quick.
658static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400659CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
660 const X86_64InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100661 const CompilerOptions& compiler_options,
662 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000663 : CodeGenerator(graph,
664 kNumberOfCpuRegisters,
665 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000666 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000667 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
668 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000669 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000670 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
671 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100672 compiler_options,
673 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100674 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100675 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000676 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400677 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400678 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000679 constant_area_start_(0),
Vladimir Marko5233f932015-09-29 19:01:15 +0100680 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
681 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
682 pc_rel_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000683 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
684}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100685
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100686InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
687 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100688 : HGraphVisitor(graph),
689 assembler_(codegen->GetAssembler()),
690 codegen_(codegen) {}
691
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100692Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100693 switch (type) {
694 case Primitive::kPrimLong:
695 case Primitive::kPrimByte:
696 case Primitive::kPrimBoolean:
697 case Primitive::kPrimChar:
698 case Primitive::kPrimShort:
699 case Primitive::kPrimInt:
700 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100701 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100702 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100703 }
704
705 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100706 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100707 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100708 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100709 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100710
711 case Primitive::kPrimVoid:
712 LOG(FATAL) << "Unreachable type " << type;
713 }
714
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100715 return Location();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100716}
717
Nicolas Geoffray98893962015-01-21 12:32:32 +0000718void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100719 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100720 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100721
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000722 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100723 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000724
Nicolas Geoffray98893962015-01-21 12:32:32 +0000725 if (is_baseline) {
726 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
727 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
728 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000729 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
730 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
731 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000732 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100733}
734
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100735static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100736 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100737}
David Srbecky9d8606d2015-04-12 09:35:32 +0100738
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100739static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100740 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100741}
742
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100743void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100744 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000745 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100746 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700747 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000748 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100749
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000750 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100751 __ testq(CpuRegister(RAX), Address(
752 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100753 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100754 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +0000755
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000756 if (HasEmptyFrame()) {
757 return;
758 }
759
Nicolas Geoffray98893962015-01-21 12:32:32 +0000760 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000761 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000762 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000763 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100764 __ cfi().AdjustCFAOffset(kX86_64WordSize);
765 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +0000766 }
767 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100768
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100769 int adjust = GetFrameSize() - GetCoreSpillSize();
770 __ subq(CpuRegister(RSP), Immediate(adjust));
771 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000772 uint32_t xmm_spill_location = GetFpuSpillStart();
773 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100774
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000775 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
776 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100777 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
778 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
779 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000780 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100781 }
782
Mathieu Chartiere401d142015-04-22 13:56:20 -0700783 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100784 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100785}
786
787void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100788 __ cfi().RememberState();
789 if (!HasEmptyFrame()) {
790 uint32_t xmm_spill_location = GetFpuSpillStart();
791 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
792 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
793 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
794 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
795 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
796 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
797 }
798 }
799
800 int adjust = GetFrameSize() - GetCoreSpillSize();
801 __ addq(CpuRegister(RSP), Immediate(adjust));
802 __ cfi().AdjustCFAOffset(-adjust);
803
804 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
805 Register reg = kCoreCalleeSaves[i];
806 if (allocated_registers_.ContainsCoreRegister(reg)) {
807 __ popq(CpuRegister(reg));
808 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
809 __ cfi().Restore(DWARFReg(reg));
810 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000811 }
812 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100813 __ ret();
814 __ cfi().RestoreState();
815 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100816}
817
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100818void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
819 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100820}
821
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100822Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
823 switch (load->GetType()) {
824 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100825 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100826 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100827
828 case Primitive::kPrimInt:
829 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100830 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100831 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100832
833 case Primitive::kPrimBoolean:
834 case Primitive::kPrimByte:
835 case Primitive::kPrimChar:
836 case Primitive::kPrimShort:
837 case Primitive::kPrimVoid:
838 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700839 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100840 }
841
842 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700843 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100844}
845
846void CodeGeneratorX86_64::Move(Location destination, Location source) {
847 if (source.Equals(destination)) {
848 return;
849 }
850 if (destination.IsRegister()) {
851 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000852 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100853 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000854 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100855 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000856 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100857 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100858 } else {
859 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000860 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100861 Address(CpuRegister(RSP), source.GetStackIndex()));
862 }
863 } else if (destination.IsFpuRegister()) {
864 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000865 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000867 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100868 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000869 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100870 Address(CpuRegister(RSP), source.GetStackIndex()));
871 } else {
872 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000873 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100874 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100875 }
876 } else if (destination.IsStackSlot()) {
877 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100878 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000879 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100880 } else if (source.IsFpuRegister()) {
881 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000882 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500883 } else if (source.IsConstant()) {
884 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000885 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500886 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100887 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500888 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000889 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
890 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100891 }
892 } else {
893 DCHECK(destination.IsDoubleStackSlot());
894 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100895 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000896 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100897 } else if (source.IsFpuRegister()) {
898 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +0000899 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500900 } else if (source.IsConstant()) {
901 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +0800902 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500903 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +0000904 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -0500905 } else {
906 DCHECK(constant->IsLongConstant());
907 value = constant->AsLongConstant()->GetValue();
908 }
Mark Mendellcfa410b2015-05-25 16:02:44 -0400909 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100910 } else {
911 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000912 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
913 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100914 }
915 }
916}
917
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100918void CodeGeneratorX86_64::Move(HInstruction* instruction,
919 Location location,
920 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000921 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100922 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -0700923 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100924 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000925 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100926 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000927 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000928 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
929 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000930 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000931 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000932 } else if (location.IsStackSlot()) {
933 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
934 } else {
935 DCHECK(location.IsConstant());
936 DCHECK_EQ(location.GetConstant(), const_to_move);
937 }
938 } else if (const_to_move->IsLongConstant()) {
939 int64_t value = const_to_move->AsLongConstant()->GetValue();
940 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400941 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000942 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400943 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000944 } else {
945 DCHECK(location.IsConstant());
946 DCHECK_EQ(location.GetConstant(), const_to_move);
947 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100948 }
Roland Levillain476df552014-10-09 17:51:36 +0100949 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100950 switch (instruction->GetType()) {
951 case Primitive::kPrimBoolean:
952 case Primitive::kPrimByte:
953 case Primitive::kPrimChar:
954 case Primitive::kPrimShort:
955 case Primitive::kPrimInt:
956 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100957 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100958 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
959 break;
960
961 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100962 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +0000963 Move(location,
964 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100965 break;
966
967 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100968 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100969 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000970 } else if (instruction->IsTemporary()) {
971 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
972 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100973 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100974 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100975 switch (instruction->GetType()) {
976 case Primitive::kPrimBoolean:
977 case Primitive::kPrimByte:
978 case Primitive::kPrimChar:
979 case Primitive::kPrimShort:
980 case Primitive::kPrimInt:
981 case Primitive::kPrimNot:
982 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100983 case Primitive::kPrimFloat:
984 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000985 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100986 break;
987
988 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100989 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100990 }
991 }
992}
993
Calin Juravle175dc732015-08-25 15:42:32 +0100994void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
995 DCHECK(location.IsRegister());
996 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
997}
998
Calin Juravlee460d1d2015-09-29 04:52:17 +0100999void CodeGeneratorX86_64::MoveLocation(
1000 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
1001 Move(dst, src);
1002}
1003
1004void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1005 if (location.IsRegister()) {
1006 locations->AddTemp(location);
1007 } else {
1008 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1009 }
1010}
1011
David Brazdilfc6a86a2015-06-26 10:33:45 +00001012void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001013 DCHECK(!successor->IsExitBlock());
1014
1015 HBasicBlock* block = got->GetBlock();
1016 HInstruction* previous = got->GetPrevious();
1017
1018 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001019 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001020 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1021 return;
1022 }
1023
1024 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1025 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1026 }
1027 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001028 __ jmp(codegen_->GetLabelOf(successor));
1029 }
1030}
1031
David Brazdilfc6a86a2015-06-26 10:33:45 +00001032void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1033 got->SetLocations(nullptr);
1034}
1035
1036void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1037 HandleGoto(got, got->GetSuccessor());
1038}
1039
1040void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1041 try_boundary->SetLocations(nullptr);
1042}
1043
1044void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1045 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1046 if (!successor->IsExitBlock()) {
1047 HandleGoto(try_boundary, successor);
1048 }
1049}
1050
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001051void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1052 exit->SetLocations(nullptr);
1053}
1054
1055void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001056 UNUSED(exit);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001057}
1058
Mark Mendellc4701932015-04-10 13:18:51 -04001059void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
1060 Label* true_label,
1061 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001062 if (cond->IsFPConditionTrueIfNaN()) {
1063 __ j(kUnordered, true_label);
1064 } else if (cond->IsFPConditionFalseIfNaN()) {
1065 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001066 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001067 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001068}
1069
1070void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
1071 HCondition* condition,
1072 Label* true_target,
1073 Label* false_target,
1074 Label* always_true_target) {
1075 LocationSummary* locations = condition->GetLocations();
1076 Location left = locations->InAt(0);
1077 Location right = locations->InAt(1);
1078
1079 // We don't want true_target as a nullptr.
1080 if (true_target == nullptr) {
1081 true_target = always_true_target;
1082 }
1083 bool falls_through = (false_target == nullptr);
1084
1085 // FP compares don't like null false_targets.
1086 if (false_target == nullptr) {
1087 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1088 }
1089
1090 Primitive::Type type = condition->InputAt(0)->GetType();
1091 switch (type) {
1092 case Primitive::kPrimLong: {
1093 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1094 if (right.IsConstant()) {
1095 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1096 if (IsInt<32>(value)) {
1097 if (value == 0) {
1098 __ testq(left_reg, left_reg);
1099 } else {
1100 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1101 }
1102 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001103 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -04001104 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
1105 }
1106 } else if (right.IsDoubleStackSlot()) {
1107 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1108 } else {
1109 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1110 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001111 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -04001112 break;
1113 }
1114 case Primitive::kPrimFloat: {
1115 if (right.IsFpuRegister()) {
1116 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1117 } else if (right.IsConstant()) {
1118 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1119 codegen_->LiteralFloatAddress(
1120 right.GetConstant()->AsFloatConstant()->GetValue()));
1121 } else {
1122 DCHECK(right.IsStackSlot());
1123 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1124 Address(CpuRegister(RSP), right.GetStackIndex()));
1125 }
1126 GenerateFPJumps(condition, true_target, false_target);
1127 break;
1128 }
1129 case Primitive::kPrimDouble: {
1130 if (right.IsFpuRegister()) {
1131 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1132 } else if (right.IsConstant()) {
1133 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1134 codegen_->LiteralDoubleAddress(
1135 right.GetConstant()->AsDoubleConstant()->GetValue()));
1136 } else {
1137 DCHECK(right.IsDoubleStackSlot());
1138 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1139 Address(CpuRegister(RSP), right.GetStackIndex()));
1140 }
1141 GenerateFPJumps(condition, true_target, false_target);
1142 break;
1143 }
1144 default:
1145 LOG(FATAL) << "Unexpected condition type " << type;
1146 }
1147
1148 if (!falls_through) {
1149 __ jmp(false_target);
1150 }
1151}
1152
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001153void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
1154 Label* true_target,
1155 Label* false_target,
1156 Label* always_true_target) {
1157 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001158 if (cond->IsIntConstant()) {
1159 // Constant condition, statically compared against 1.
1160 int32_t cond_value = cond->AsIntConstant()->GetValue();
1161 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001162 if (always_true_target != nullptr) {
1163 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001164 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001165 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001166 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001167 DCHECK_EQ(cond_value, 0);
1168 }
1169 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001170 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001171 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1172 // Moves do not affect the eflags register, so if the condition is
1173 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001174 // again. We can't use the eflags on FP conditions if they are
1175 // materialized due to the complex branching.
1176 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001177 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001178 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
1179 && !Primitive::IsFloatingPointType(type);
1180
Roland Levillain4fa13f62015-07-06 18:11:54 +01001181 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001182 if (!eflags_set) {
1183 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001184 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001185 if (lhs.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001186 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001187 } else {
1188 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
1189 Immediate(0));
1190 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001191 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001192 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001193 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001194 }
1195 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001196 // Condition has not been materialized, use its inputs as the
1197 // comparison and its condition as the branch condition.
1198
Mark Mendellc4701932015-04-10 13:18:51 -04001199 // Is this a long or FP comparison that has been folded into the HCondition?
1200 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001201 // Generate the comparison directly.
Mark Mendellc4701932015-04-10 13:18:51 -04001202 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1203 true_target, false_target, always_true_target);
1204 return;
1205 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001206
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001207 Location lhs = cond->GetLocations()->InAt(0);
1208 Location rhs = cond->GetLocations()->InAt(1);
1209 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001210 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001211 } else if (rhs.IsConstant()) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001212 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00001213 if (constant == 0) {
1214 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1215 } else {
1216 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1217 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001218 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001219 __ cmpl(lhs.AsRegister<CpuRegister>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001220 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1221 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001222 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001223 }
Dave Allison20dfc792014-06-16 20:44:29 -07001224 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001225 if (false_target != nullptr) {
1226 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001227 }
1228}
1229
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001230void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
1231 LocationSummary* locations =
1232 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1233 HInstruction* cond = if_instr->InputAt(0);
1234 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1235 locations->SetInAt(0, Location::Any());
1236 }
1237}
1238
1239void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
1240 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1241 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1242 Label* always_true_target = true_target;
1243 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1244 if_instr->IfTrueSuccessor())) {
1245 always_true_target = nullptr;
1246 }
1247 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1248 if_instr->IfFalseSuccessor())) {
1249 false_target = nullptr;
1250 }
1251 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1252}
1253
1254void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1255 LocationSummary* locations = new (GetGraph()->GetArena())
1256 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1257 HInstruction* cond = deoptimize->InputAt(0);
1258 DCHECK(cond->IsCondition());
1259 if (cond->AsCondition()->NeedsMaterialization()) {
1260 locations->SetInAt(0, Location::Any());
1261 }
1262}
1263
1264void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001265 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001266 DeoptimizationSlowPathX86_64(deoptimize);
1267 codegen_->AddSlowPath(slow_path);
1268 Label* slow_path_entry = slow_path->GetEntryLabel();
1269 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1270}
1271
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001272void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1273 local->SetLocations(nullptr);
1274}
1275
1276void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1277 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1278}
1279
1280void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1281 local->SetLocations(nullptr);
1282}
1283
1284void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
1285 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001286 UNUSED(load);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001287}
1288
1289void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001290 LocationSummary* locations =
1291 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001292 switch (store->InputAt(1)->GetType()) {
1293 case Primitive::kPrimBoolean:
1294 case Primitive::kPrimByte:
1295 case Primitive::kPrimChar:
1296 case Primitive::kPrimShort:
1297 case Primitive::kPrimInt:
1298 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001299 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001300 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1301 break;
1302
1303 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001304 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001305 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1306 break;
1307
1308 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001309 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001310 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001311}
1312
1313void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001314 UNUSED(store);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001315}
1316
Roland Levillain0d37cd02015-05-27 16:39:19 +01001317void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001318 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001319 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001320 // Handle the long/FP comparisons made in instruction simplification.
1321 switch (cond->InputAt(0)->GetType()) {
1322 case Primitive::kPrimLong:
1323 locations->SetInAt(0, Location::RequiresRegister());
1324 locations->SetInAt(1, Location::Any());
1325 break;
1326 case Primitive::kPrimFloat:
1327 case Primitive::kPrimDouble:
1328 locations->SetInAt(0, Location::RequiresFpuRegister());
1329 locations->SetInAt(1, Location::Any());
1330 break;
1331 default:
1332 locations->SetInAt(0, Location::RequiresRegister());
1333 locations->SetInAt(1, Location::Any());
1334 break;
1335 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001336 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001337 locations->SetOut(Location::RequiresRegister());
1338 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001339}
1340
Roland Levillain0d37cd02015-05-27 16:39:19 +01001341void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001342 if (!cond->NeedsMaterialization()) {
1343 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001344 }
Mark Mendellc4701932015-04-10 13:18:51 -04001345
1346 LocationSummary* locations = cond->GetLocations();
1347 Location lhs = locations->InAt(0);
1348 Location rhs = locations->InAt(1);
1349 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1350 Label true_label, false_label;
1351
1352 switch (cond->InputAt(0)->GetType()) {
1353 default:
1354 // Integer case.
1355
1356 // Clear output register: setcc only sets the low byte.
1357 __ xorl(reg, reg);
1358
1359 if (rhs.IsRegister()) {
1360 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1361 } else if (rhs.IsConstant()) {
1362 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1363 if (constant == 0) {
1364 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1365 } else {
1366 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1367 }
1368 } else {
1369 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1370 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001371 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001372 return;
1373 case Primitive::kPrimLong:
1374 // Clear output register: setcc only sets the low byte.
1375 __ xorl(reg, reg);
1376
1377 if (rhs.IsRegister()) {
1378 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1379 } else if (rhs.IsConstant()) {
1380 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1381 if (IsInt<32>(value)) {
1382 if (value == 0) {
1383 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1384 } else {
1385 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1386 }
1387 } else {
1388 // Value won't fit in an int.
1389 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1390 }
1391 } else {
1392 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1393 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001394 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001395 return;
1396 case Primitive::kPrimFloat: {
1397 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1398 if (rhs.IsConstant()) {
1399 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1400 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1401 } else if (rhs.IsStackSlot()) {
1402 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1403 } else {
1404 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1405 }
1406 GenerateFPJumps(cond, &true_label, &false_label);
1407 break;
1408 }
1409 case Primitive::kPrimDouble: {
1410 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1411 if (rhs.IsConstant()) {
1412 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1413 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1414 } else if (rhs.IsDoubleStackSlot()) {
1415 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1416 } else {
1417 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1418 }
1419 GenerateFPJumps(cond, &true_label, &false_label);
1420 break;
1421 }
1422 }
1423
1424 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001425 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001426
Roland Levillain4fa13f62015-07-06 18:11:54 +01001427 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001428 __ Bind(&false_label);
1429 __ xorl(reg, reg);
1430 __ jmp(&done_label);
1431
Roland Levillain4fa13f62015-07-06 18:11:54 +01001432 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001433 __ Bind(&true_label);
1434 __ movl(reg, Immediate(1));
1435 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001436}
1437
1438void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1439 VisitCondition(comp);
1440}
1441
1442void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1443 VisitCondition(comp);
1444}
1445
1446void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1447 VisitCondition(comp);
1448}
1449
1450void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1451 VisitCondition(comp);
1452}
1453
1454void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1455 VisitCondition(comp);
1456}
1457
1458void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1459 VisitCondition(comp);
1460}
1461
1462void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1463 VisitCondition(comp);
1464}
1465
1466void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1467 VisitCondition(comp);
1468}
1469
1470void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1471 VisitCondition(comp);
1472}
1473
1474void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1475 VisitCondition(comp);
1476}
1477
1478void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1479 VisitCondition(comp);
1480}
1481
1482void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1483 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001484}
1485
Aart Bike9f37602015-10-09 11:15:55 -07001486void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
1487 VisitCondition(comp);
1488}
1489
1490void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
1491 VisitCondition(comp);
1492}
1493
1494void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1495 VisitCondition(comp);
1496}
1497
1498void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1499 VisitCondition(comp);
1500}
1501
1502void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
1503 VisitCondition(comp);
1504}
1505
1506void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
1507 VisitCondition(comp);
1508}
1509
1510void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1511 VisitCondition(comp);
1512}
1513
1514void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1515 VisitCondition(comp);
1516}
1517
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001518void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001519 LocationSummary* locations =
1520 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001521 switch (compare->InputAt(0)->GetType()) {
1522 case Primitive::kPrimLong: {
1523 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001524 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001525 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1526 break;
1527 }
1528 case Primitive::kPrimFloat:
1529 case Primitive::kPrimDouble: {
1530 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001531 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001532 locations->SetOut(Location::RequiresRegister());
1533 break;
1534 }
1535 default:
1536 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1537 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001538}
1539
1540void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001541 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001542 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001543 Location left = locations->InAt(0);
1544 Location right = locations->InAt(1);
1545
Mark Mendell0c9497d2015-08-21 09:30:05 -04001546 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00001547 Primitive::Type type = compare->InputAt(0)->GetType();
1548 switch (type) {
1549 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001550 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1551 if (right.IsConstant()) {
1552 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001553 if (IsInt<32>(value)) {
1554 if (value == 0) {
1555 __ testq(left_reg, left_reg);
1556 } else {
1557 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1558 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001559 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001560 // Value won't fit in an int.
1561 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001562 }
Mark Mendell40741f32015-04-20 22:10:34 -04001563 } else if (right.IsDoubleStackSlot()) {
1564 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001565 } else {
1566 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1567 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001568 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001569 }
1570 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001571 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1572 if (right.IsConstant()) {
1573 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1574 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1575 } else if (right.IsStackSlot()) {
1576 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1577 } else {
1578 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1579 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001580 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1581 break;
1582 }
1583 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001584 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1585 if (right.IsConstant()) {
1586 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1587 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1588 } else if (right.IsDoubleStackSlot()) {
1589 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1590 } else {
1591 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1592 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001593 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1594 break;
1595 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001596 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001597 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001598 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001599 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001600 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001601 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001602
Calin Juravle91debbc2014-11-26 19:01:09 +00001603 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001604 __ movl(out, Immediate(1));
1605 __ jmp(&done);
1606
1607 __ Bind(&less);
1608 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001609
1610 __ Bind(&done);
1611}
1612
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001613void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001614 LocationSummary* locations =
1615 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001616 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001617}
1618
1619void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001620 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001621 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001622}
1623
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001624void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1625 LocationSummary* locations =
1626 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1627 locations->SetOut(Location::ConstantLocation(constant));
1628}
1629
1630void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
1631 // Will be generated at use site.
1632 UNUSED(constant);
1633}
1634
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001635void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001636 LocationSummary* locations =
1637 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001638 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001639}
1640
1641void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001642 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001643 UNUSED(constant);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001644}
1645
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001646void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1647 LocationSummary* locations =
1648 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1649 locations->SetOut(Location::ConstantLocation(constant));
1650}
1651
1652void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
1653 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001654 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001655}
1656
1657void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1658 LocationSummary* locations =
1659 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1660 locations->SetOut(Location::ConstantLocation(constant));
1661}
1662
1663void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1664 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001665 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001666}
1667
Calin Juravle27df7582015-04-17 19:12:31 +01001668void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1669 memory_barrier->SetLocations(nullptr);
1670}
1671
1672void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1673 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1674}
1675
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001676void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1677 ret->SetLocations(nullptr);
1678}
1679
1680void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001681 UNUSED(ret);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001682 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001683}
1684
1685void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001686 LocationSummary* locations =
1687 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001688 switch (ret->InputAt(0)->GetType()) {
1689 case Primitive::kPrimBoolean:
1690 case Primitive::kPrimByte:
1691 case Primitive::kPrimChar:
1692 case Primitive::kPrimShort:
1693 case Primitive::kPrimInt:
1694 case Primitive::kPrimNot:
1695 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001696 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001697 break;
1698
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001699 case Primitive::kPrimFloat:
1700 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001701 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001702 break;
1703
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001704 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001705 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001706 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001707}
1708
1709void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1710 if (kIsDebugBuild) {
1711 switch (ret->InputAt(0)->GetType()) {
1712 case Primitive::kPrimBoolean:
1713 case Primitive::kPrimByte:
1714 case Primitive::kPrimChar:
1715 case Primitive::kPrimShort:
1716 case Primitive::kPrimInt:
1717 case Primitive::kPrimNot:
1718 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001719 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001720 break;
1721
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001722 case Primitive::kPrimFloat:
1723 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001724 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001725 XMM0);
1726 break;
1727
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001728 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001729 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001730 }
1731 }
1732 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001733}
1734
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001735Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1736 switch (type) {
1737 case Primitive::kPrimBoolean:
1738 case Primitive::kPrimByte:
1739 case Primitive::kPrimChar:
1740 case Primitive::kPrimShort:
1741 case Primitive::kPrimInt:
1742 case Primitive::kPrimNot:
1743 case Primitive::kPrimLong:
1744 return Location::RegisterLocation(RAX);
1745
1746 case Primitive::kPrimVoid:
1747 return Location::NoLocation();
1748
1749 case Primitive::kPrimDouble:
1750 case Primitive::kPrimFloat:
1751 return Location::FpuRegisterLocation(XMM0);
1752 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001753
1754 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001755}
1756
1757Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
1758 return Location::RegisterLocation(kMethodRegisterArgument);
1759}
1760
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001761Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001762 switch (type) {
1763 case Primitive::kPrimBoolean:
1764 case Primitive::kPrimByte:
1765 case Primitive::kPrimChar:
1766 case Primitive::kPrimShort:
1767 case Primitive::kPrimInt:
1768 case Primitive::kPrimNot: {
1769 uint32_t index = gp_index_++;
1770 stack_index_++;
1771 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001772 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001773 } else {
1774 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1775 }
1776 }
1777
1778 case Primitive::kPrimLong: {
1779 uint32_t index = gp_index_;
1780 stack_index_ += 2;
1781 if (index < calling_convention.GetNumberOfRegisters()) {
1782 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001783 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001784 } else {
1785 gp_index_ += 2;
1786 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1787 }
1788 }
1789
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001790 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001791 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001792 stack_index_++;
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::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1797 }
1798 }
1799
1800 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001801 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001802 stack_index_ += 2;
1803 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001804 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001805 } else {
1806 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1807 }
1808 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001809
1810 case Primitive::kPrimVoid:
1811 LOG(FATAL) << "Unexpected parameter type " << type;
1812 break;
1813 }
1814 return Location();
1815}
1816
Calin Juravle175dc732015-08-25 15:42:32 +01001817void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1818 // The trampoline uses the same calling convention as dex calling conventions,
1819 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1820 // the method_idx.
1821 HandleInvoke(invoke);
1822}
1823
1824void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1825 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1826}
1827
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001828void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001829 // When we do not run baseline, explicit clinit checks triggered by static
1830 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1831 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001832
Mark Mendellfb8d2792015-03-31 22:16:59 -04001833 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001834 if (intrinsic.TryDispatch(invoke)) {
1835 return;
1836 }
1837
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001838 HandleInvoke(invoke);
1839}
1840
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001841static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
1842 if (invoke->GetLocations()->Intrinsified()) {
1843 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
1844 intrinsic.Dispatch(invoke);
1845 return true;
1846 }
1847 return false;
1848}
1849
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001850void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001851 // When we do not run baseline, explicit clinit checks triggered by static
1852 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1853 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001854
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001855 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1856 return;
1857 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001858
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001859 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001860 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001861 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001862 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001863}
1864
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001865void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001866 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001867 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001868}
1869
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001870void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001871 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001872 if (intrinsic.TryDispatch(invoke)) {
1873 return;
1874 }
1875
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001876 HandleInvoke(invoke);
1877}
1878
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001879void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001880 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1881 return;
1882 }
1883
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001884 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001885
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001886 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001887 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001888}
1889
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001890void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1891 HandleInvoke(invoke);
1892 // Add the hidden argument.
1893 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
1894}
1895
1896void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
1897 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001898 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001899 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1900 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001901 LocationSummary* locations = invoke->GetLocations();
1902 Location receiver = locations->InAt(0);
1903 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
1904
1905 // Set the hidden argument.
Mark Mendell92e83bf2015-05-07 11:25:03 -04001906 CpuRegister hidden_reg = invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>();
1907 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001908
1909 // temp = object->GetClass();
1910 if (receiver.IsStackSlot()) {
1911 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
1912 __ movl(temp, Address(temp, class_offset));
1913 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001914 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001915 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001916 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001917 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001918 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001919 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001920 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001921 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001922 kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001923
1924 DCHECK(!codegen_->IsLeafMethod());
1925 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1926}
1927
Roland Levillain88cb1752014-10-20 16:36:47 +01001928void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
1929 LocationSummary* locations =
1930 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1931 switch (neg->GetResultType()) {
1932 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001933 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001934 locations->SetInAt(0, Location::RequiresRegister());
1935 locations->SetOut(Location::SameAsFirstInput());
1936 break;
1937
Roland Levillain88cb1752014-10-20 16:36:47 +01001938 case Primitive::kPrimFloat:
1939 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001940 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001941 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00001942 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001943 break;
1944
1945 default:
1946 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1947 }
1948}
1949
1950void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
1951 LocationSummary* locations = neg->GetLocations();
1952 Location out = locations->Out();
1953 Location in = locations->InAt(0);
1954 switch (neg->GetResultType()) {
1955 case Primitive::kPrimInt:
1956 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001957 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001958 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001959 break;
1960
1961 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001962 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001963 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001964 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001965 break;
1966
Roland Levillain5368c212014-11-27 15:03:41 +00001967 case Primitive::kPrimFloat: {
1968 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001969 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001970 // Implement float negation with an exclusive or with value
1971 // 0x80000000 (mask for bit 31, representing the sign of a
1972 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001973 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001974 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001975 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001976 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001977
Roland Levillain5368c212014-11-27 15:03:41 +00001978 case Primitive::kPrimDouble: {
1979 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04001980 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001981 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00001982 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00001983 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04001984 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001985 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001986 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001987 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001988
1989 default:
1990 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1991 }
1992}
1993
Roland Levillaindff1f282014-11-05 14:15:05 +00001994void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
1995 LocationSummary* locations =
1996 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1997 Primitive::Type result_type = conversion->GetResultType();
1998 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001999 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00002000
David Brazdilb2bd1c52015-03-25 11:17:37 +00002001 // The Java language does not allow treating boolean as an integral type but
2002 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002003
Roland Levillaindff1f282014-11-05 14:15:05 +00002004 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002005 case Primitive::kPrimByte:
2006 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002007 case Primitive::kPrimBoolean:
2008 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002009 case Primitive::kPrimShort:
2010 case Primitive::kPrimInt:
2011 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002012 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002013 locations->SetInAt(0, Location::Any());
2014 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2015 break;
2016
2017 default:
2018 LOG(FATAL) << "Unexpected type conversion from " << input_type
2019 << " to " << result_type;
2020 }
2021 break;
2022
Roland Levillain01a8d712014-11-14 16:27:39 +00002023 case Primitive::kPrimShort:
2024 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002025 case Primitive::kPrimBoolean:
2026 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002027 case Primitive::kPrimByte:
2028 case Primitive::kPrimInt:
2029 case Primitive::kPrimChar:
2030 // Processing a Dex `int-to-short' instruction.
2031 locations->SetInAt(0, Location::Any());
2032 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2033 break;
2034
2035 default:
2036 LOG(FATAL) << "Unexpected type conversion from " << input_type
2037 << " to " << result_type;
2038 }
2039 break;
2040
Roland Levillain946e1432014-11-11 17:35:19 +00002041 case Primitive::kPrimInt:
2042 switch (input_type) {
2043 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002044 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002045 locations->SetInAt(0, Location::Any());
2046 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2047 break;
2048
2049 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002050 // Processing a Dex `float-to-int' instruction.
2051 locations->SetInAt(0, Location::RequiresFpuRegister());
2052 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002053 break;
2054
Roland Levillain946e1432014-11-11 17:35:19 +00002055 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002056 // Processing a Dex `double-to-int' instruction.
2057 locations->SetInAt(0, Location::RequiresFpuRegister());
2058 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002059 break;
2060
2061 default:
2062 LOG(FATAL) << "Unexpected type conversion from " << input_type
2063 << " to " << result_type;
2064 }
2065 break;
2066
Roland Levillaindff1f282014-11-05 14:15:05 +00002067 case Primitive::kPrimLong:
2068 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002069 case Primitive::kPrimBoolean:
2070 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002071 case Primitive::kPrimByte:
2072 case Primitive::kPrimShort:
2073 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002074 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002075 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002076 // TODO: We would benefit from a (to-be-implemented)
2077 // Location::RegisterOrStackSlot requirement for this input.
2078 locations->SetInAt(0, Location::RequiresRegister());
2079 locations->SetOut(Location::RequiresRegister());
2080 break;
2081
2082 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002083 // Processing a Dex `float-to-long' instruction.
2084 locations->SetInAt(0, Location::RequiresFpuRegister());
2085 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002086 break;
2087
Roland Levillaindff1f282014-11-05 14:15:05 +00002088 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002089 // Processing a Dex `double-to-long' instruction.
2090 locations->SetInAt(0, Location::RequiresFpuRegister());
2091 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002092 break;
2093
2094 default:
2095 LOG(FATAL) << "Unexpected type conversion from " << input_type
2096 << " to " << result_type;
2097 }
2098 break;
2099
Roland Levillain981e4542014-11-14 11:47:14 +00002100 case Primitive::kPrimChar:
2101 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002102 case Primitive::kPrimBoolean:
2103 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002104 case Primitive::kPrimByte:
2105 case Primitive::kPrimShort:
2106 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002107 // Processing a Dex `int-to-char' instruction.
2108 locations->SetInAt(0, Location::Any());
2109 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2110 break;
2111
2112 default:
2113 LOG(FATAL) << "Unexpected type conversion from " << input_type
2114 << " to " << result_type;
2115 }
2116 break;
2117
Roland Levillaindff1f282014-11-05 14:15:05 +00002118 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002119 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002120 case Primitive::kPrimBoolean:
2121 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002122 case Primitive::kPrimByte:
2123 case Primitive::kPrimShort:
2124 case Primitive::kPrimInt:
2125 case Primitive::kPrimChar:
2126 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002127 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002128 locations->SetOut(Location::RequiresFpuRegister());
2129 break;
2130
2131 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002132 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002133 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002134 locations->SetOut(Location::RequiresFpuRegister());
2135 break;
2136
Roland Levillaincff13742014-11-17 14:32:17 +00002137 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002138 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002139 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002140 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002141 break;
2142
2143 default:
2144 LOG(FATAL) << "Unexpected type conversion from " << input_type
2145 << " to " << result_type;
2146 };
2147 break;
2148
Roland Levillaindff1f282014-11-05 14:15:05 +00002149 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002150 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002151 case Primitive::kPrimBoolean:
2152 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002153 case Primitive::kPrimByte:
2154 case Primitive::kPrimShort:
2155 case Primitive::kPrimInt:
2156 case Primitive::kPrimChar:
2157 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002158 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002159 locations->SetOut(Location::RequiresFpuRegister());
2160 break;
2161
2162 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002163 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002164 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002165 locations->SetOut(Location::RequiresFpuRegister());
2166 break;
2167
Roland Levillaincff13742014-11-17 14:32:17 +00002168 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002169 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002170 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002171 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002172 break;
2173
2174 default:
2175 LOG(FATAL) << "Unexpected type conversion from " << input_type
2176 << " to " << result_type;
2177 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002178 break;
2179
2180 default:
2181 LOG(FATAL) << "Unexpected type conversion from " << input_type
2182 << " to " << result_type;
2183 }
2184}
2185
2186void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2187 LocationSummary* locations = conversion->GetLocations();
2188 Location out = locations->Out();
2189 Location in = locations->InAt(0);
2190 Primitive::Type result_type = conversion->GetResultType();
2191 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002192 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002193 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002194 case Primitive::kPrimByte:
2195 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002196 case Primitive::kPrimBoolean:
2197 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002198 case Primitive::kPrimShort:
2199 case Primitive::kPrimInt:
2200 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002201 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002202 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002203 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002204 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002205 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002206 Address(CpuRegister(RSP), in.GetStackIndex()));
2207 } else {
2208 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002209 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002210 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2211 }
2212 break;
2213
2214 default:
2215 LOG(FATAL) << "Unexpected type conversion from " << input_type
2216 << " to " << result_type;
2217 }
2218 break;
2219
Roland Levillain01a8d712014-11-14 16:27:39 +00002220 case Primitive::kPrimShort:
2221 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002222 case Primitive::kPrimBoolean:
2223 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002224 case Primitive::kPrimByte:
2225 case Primitive::kPrimInt:
2226 case Primitive::kPrimChar:
2227 // Processing a Dex `int-to-short' instruction.
2228 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002229 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002230 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002231 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002232 Address(CpuRegister(RSP), in.GetStackIndex()));
2233 } else {
2234 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002235 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002236 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2237 }
2238 break;
2239
2240 default:
2241 LOG(FATAL) << "Unexpected type conversion from " << input_type
2242 << " to " << result_type;
2243 }
2244 break;
2245
Roland Levillain946e1432014-11-11 17:35:19 +00002246 case Primitive::kPrimInt:
2247 switch (input_type) {
2248 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002249 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002250 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002251 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002252 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002253 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002254 Address(CpuRegister(RSP), in.GetStackIndex()));
2255 } else {
2256 DCHECK(in.IsConstant());
2257 DCHECK(in.GetConstant()->IsLongConstant());
2258 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002259 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002260 }
2261 break;
2262
Roland Levillain3f8f9362014-12-02 17:45:01 +00002263 case Primitive::kPrimFloat: {
2264 // Processing a Dex `float-to-int' instruction.
2265 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2266 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002267 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002268
2269 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002270 // if input >= (float)INT_MAX goto done
2271 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002272 __ j(kAboveEqual, &done);
2273 // if input == NaN goto nan
2274 __ j(kUnordered, &nan);
2275 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002276 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002277 __ jmp(&done);
2278 __ Bind(&nan);
2279 // output = 0
2280 __ xorl(output, output);
2281 __ Bind(&done);
2282 break;
2283 }
2284
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002285 case Primitive::kPrimDouble: {
2286 // Processing a Dex `double-to-int' instruction.
2287 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2288 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002289 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002290
2291 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002292 // if input >= (double)INT_MAX goto done
2293 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002294 __ j(kAboveEqual, &done);
2295 // if input == NaN goto nan
2296 __ j(kUnordered, &nan);
2297 // output = double-to-int-truncate(input)
2298 __ cvttsd2si(output, input);
2299 __ jmp(&done);
2300 __ Bind(&nan);
2301 // output = 0
2302 __ xorl(output, output);
2303 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002304 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002305 }
Roland Levillain946e1432014-11-11 17:35:19 +00002306
2307 default:
2308 LOG(FATAL) << "Unexpected type conversion from " << input_type
2309 << " to " << result_type;
2310 }
2311 break;
2312
Roland Levillaindff1f282014-11-05 14:15:05 +00002313 case Primitive::kPrimLong:
2314 switch (input_type) {
2315 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002316 case Primitive::kPrimBoolean:
2317 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002318 case Primitive::kPrimByte:
2319 case Primitive::kPrimShort:
2320 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002321 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002322 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002323 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002324 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002325 break;
2326
Roland Levillain624279f2014-12-04 11:54:28 +00002327 case Primitive::kPrimFloat: {
2328 // Processing a Dex `float-to-long' instruction.
2329 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2330 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002331 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002332
Mark Mendell92e83bf2015-05-07 11:25:03 -04002333 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002334 // if input >= (float)LONG_MAX goto done
2335 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002336 __ j(kAboveEqual, &done);
2337 // if input == NaN goto nan
2338 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002339 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002340 __ cvttss2si(output, input, true);
2341 __ jmp(&done);
2342 __ Bind(&nan);
2343 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002344 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002345 __ Bind(&done);
2346 break;
2347 }
2348
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002349 case Primitive::kPrimDouble: {
2350 // Processing a Dex `double-to-long' instruction.
2351 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2352 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002353 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002354
Mark Mendell92e83bf2015-05-07 11:25:03 -04002355 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002356 // if input >= (double)LONG_MAX goto done
2357 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002358 __ j(kAboveEqual, &done);
2359 // if input == NaN goto nan
2360 __ j(kUnordered, &nan);
2361 // output = double-to-long-truncate(input)
2362 __ cvttsd2si(output, input, true);
2363 __ jmp(&done);
2364 __ Bind(&nan);
2365 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002366 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002367 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002368 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002369 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002370
2371 default:
2372 LOG(FATAL) << "Unexpected type conversion from " << input_type
2373 << " to " << result_type;
2374 }
2375 break;
2376
Roland Levillain981e4542014-11-14 11:47:14 +00002377 case Primitive::kPrimChar:
2378 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002379 case Primitive::kPrimBoolean:
2380 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002381 case Primitive::kPrimByte:
2382 case Primitive::kPrimShort:
2383 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002384 // Processing a Dex `int-to-char' instruction.
2385 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002386 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002387 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002388 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002389 Address(CpuRegister(RSP), in.GetStackIndex()));
2390 } else {
2391 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002392 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002393 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2394 }
2395 break;
2396
2397 default:
2398 LOG(FATAL) << "Unexpected type conversion from " << input_type
2399 << " to " << result_type;
2400 }
2401 break;
2402
Roland Levillaindff1f282014-11-05 14:15:05 +00002403 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002404 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002405 case Primitive::kPrimBoolean:
2406 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002407 case Primitive::kPrimByte:
2408 case Primitive::kPrimShort:
2409 case Primitive::kPrimInt:
2410 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002411 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002412 if (in.IsRegister()) {
2413 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2414 } else if (in.IsConstant()) {
2415 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2416 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2417 if (v == 0) {
2418 __ xorps(dest, dest);
2419 } else {
2420 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2421 }
2422 } else {
2423 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2424 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2425 }
Roland Levillaincff13742014-11-17 14:32:17 +00002426 break;
2427
2428 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002429 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002430 if (in.IsRegister()) {
2431 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2432 } else if (in.IsConstant()) {
2433 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2434 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2435 if (v == 0) {
2436 __ xorps(dest, dest);
2437 } else {
2438 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2439 }
2440 } else {
2441 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2442 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2443 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002444 break;
2445
Roland Levillaincff13742014-11-17 14:32:17 +00002446 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002447 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002448 if (in.IsFpuRegister()) {
2449 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2450 } else if (in.IsConstant()) {
2451 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2452 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2453 if (bit_cast<int64_t, double>(v) == 0) {
2454 __ xorps(dest, dest);
2455 } else {
2456 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2457 }
2458 } else {
2459 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2460 Address(CpuRegister(RSP), in.GetStackIndex()));
2461 }
Roland Levillaincff13742014-11-17 14:32:17 +00002462 break;
2463
2464 default:
2465 LOG(FATAL) << "Unexpected type conversion from " << input_type
2466 << " to " << result_type;
2467 };
2468 break;
2469
Roland Levillaindff1f282014-11-05 14:15:05 +00002470 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002471 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002472 case Primitive::kPrimBoolean:
2473 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002474 case Primitive::kPrimByte:
2475 case Primitive::kPrimShort:
2476 case Primitive::kPrimInt:
2477 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002478 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002479 if (in.IsRegister()) {
2480 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2481 } else if (in.IsConstant()) {
2482 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2483 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2484 if (v == 0) {
2485 __ xorpd(dest, dest);
2486 } else {
2487 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2488 }
2489 } else {
2490 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2491 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2492 }
Roland Levillaincff13742014-11-17 14:32:17 +00002493 break;
2494
2495 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002496 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002497 if (in.IsRegister()) {
2498 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2499 } else if (in.IsConstant()) {
2500 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2501 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2502 if (v == 0) {
2503 __ xorpd(dest, dest);
2504 } else {
2505 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2506 }
2507 } else {
2508 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2509 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2510 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002511 break;
2512
Roland Levillaincff13742014-11-17 14:32:17 +00002513 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002514 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002515 if (in.IsFpuRegister()) {
2516 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2517 } else if (in.IsConstant()) {
2518 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2519 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2520 if (bit_cast<int32_t, float>(v) == 0) {
2521 __ xorpd(dest, dest);
2522 } else {
2523 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2524 }
2525 } else {
2526 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2527 Address(CpuRegister(RSP), in.GetStackIndex()));
2528 }
Roland Levillaincff13742014-11-17 14:32:17 +00002529 break;
2530
2531 default:
2532 LOG(FATAL) << "Unexpected type conversion from " << input_type
2533 << " to " << result_type;
2534 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002535 break;
2536
2537 default:
2538 LOG(FATAL) << "Unexpected type conversion from " << input_type
2539 << " to " << result_type;
2540 }
2541}
2542
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002543void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002544 LocationSummary* locations =
2545 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002546 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002547 case Primitive::kPrimInt: {
2548 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002549 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2550 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002551 break;
2552 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002553
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002554 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002555 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002556 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002557 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002558 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002559 break;
2560 }
2561
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002562 case Primitive::kPrimDouble:
2563 case Primitive::kPrimFloat: {
2564 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002565 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002566 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002567 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002568 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002569
2570 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002571 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002572 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002573}
2574
2575void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2576 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002577 Location first = locations->InAt(0);
2578 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002579 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002580
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002581 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002582 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002583 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002584 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2585 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002586 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2587 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002588 } else {
2589 __ leal(out.AsRegister<CpuRegister>(), Address(
2590 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2591 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002592 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002593 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2594 __ addl(out.AsRegister<CpuRegister>(),
2595 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2596 } else {
2597 __ leal(out.AsRegister<CpuRegister>(), Address(
2598 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2599 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002600 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002601 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002602 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002603 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002604 break;
2605 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002606
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002607 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002608 if (second.IsRegister()) {
2609 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2610 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002611 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2612 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002613 } else {
2614 __ leaq(out.AsRegister<CpuRegister>(), Address(
2615 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2616 }
2617 } else {
2618 DCHECK(second.IsConstant());
2619 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2620 int32_t int32_value = Low32Bits(value);
2621 DCHECK_EQ(int32_value, value);
2622 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2623 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2624 } else {
2625 __ leaq(out.AsRegister<CpuRegister>(), Address(
2626 first.AsRegister<CpuRegister>(), int32_value));
2627 }
2628 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002629 break;
2630 }
2631
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002632 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002633 if (second.IsFpuRegister()) {
2634 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2635 } else if (second.IsConstant()) {
2636 __ addss(first.AsFpuRegister<XmmRegister>(),
2637 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2638 } else {
2639 DCHECK(second.IsStackSlot());
2640 __ addss(first.AsFpuRegister<XmmRegister>(),
2641 Address(CpuRegister(RSP), second.GetStackIndex()));
2642 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002643 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002644 }
2645
2646 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002647 if (second.IsFpuRegister()) {
2648 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2649 } else if (second.IsConstant()) {
2650 __ addsd(first.AsFpuRegister<XmmRegister>(),
2651 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2652 } else {
2653 DCHECK(second.IsDoubleStackSlot());
2654 __ addsd(first.AsFpuRegister<XmmRegister>(),
2655 Address(CpuRegister(RSP), second.GetStackIndex()));
2656 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002657 break;
2658 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002659
2660 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002661 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002662 }
2663}
2664
2665void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002666 LocationSummary* locations =
2667 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002668 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002669 case Primitive::kPrimInt: {
2670 locations->SetInAt(0, Location::RequiresRegister());
2671 locations->SetInAt(1, Location::Any());
2672 locations->SetOut(Location::SameAsFirstInput());
2673 break;
2674 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002675 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002676 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002677 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002678 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002679 break;
2680 }
Calin Juravle11351682014-10-23 15:38:15 +01002681 case Primitive::kPrimFloat:
2682 case Primitive::kPrimDouble: {
2683 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002684 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002685 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002686 break;
Calin Juravle11351682014-10-23 15:38:15 +01002687 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002688 default:
Calin Juravle11351682014-10-23 15:38:15 +01002689 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002690 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002691}
2692
2693void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2694 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002695 Location first = locations->InAt(0);
2696 Location second = locations->InAt(1);
2697 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002698 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002699 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002700 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002701 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002702 } else if (second.IsConstant()) {
2703 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002704 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002705 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002706 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002707 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002708 break;
2709 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002710 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002711 if (second.IsConstant()) {
2712 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2713 DCHECK(IsInt<32>(value));
2714 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2715 } else {
2716 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2717 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002718 break;
2719 }
2720
Calin Juravle11351682014-10-23 15:38:15 +01002721 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002722 if (second.IsFpuRegister()) {
2723 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2724 } else if (second.IsConstant()) {
2725 __ subss(first.AsFpuRegister<XmmRegister>(),
2726 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2727 } else {
2728 DCHECK(second.IsStackSlot());
2729 __ subss(first.AsFpuRegister<XmmRegister>(),
2730 Address(CpuRegister(RSP), second.GetStackIndex()));
2731 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002732 break;
Calin Juravle11351682014-10-23 15:38:15 +01002733 }
2734
2735 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002736 if (second.IsFpuRegister()) {
2737 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2738 } else if (second.IsConstant()) {
2739 __ subsd(first.AsFpuRegister<XmmRegister>(),
2740 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2741 } else {
2742 DCHECK(second.IsDoubleStackSlot());
2743 __ subsd(first.AsFpuRegister<XmmRegister>(),
2744 Address(CpuRegister(RSP), second.GetStackIndex()));
2745 }
Calin Juravle11351682014-10-23 15:38:15 +01002746 break;
2747 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002748
2749 default:
Calin Juravle11351682014-10-23 15:38:15 +01002750 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002751 }
2752}
2753
Calin Juravle34bacdf2014-10-07 20:23:36 +01002754void LocationsBuilderX86_64::VisitMul(HMul* mul) {
2755 LocationSummary* locations =
2756 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2757 switch (mul->GetResultType()) {
2758 case Primitive::kPrimInt: {
2759 locations->SetInAt(0, Location::RequiresRegister());
2760 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002761 if (mul->InputAt(1)->IsIntConstant()) {
2762 // Can use 3 operand multiply.
2763 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2764 } else {
2765 locations->SetOut(Location::SameAsFirstInput());
2766 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002767 break;
2768 }
2769 case Primitive::kPrimLong: {
2770 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002771 locations->SetInAt(1, Location::Any());
2772 if (mul->InputAt(1)->IsLongConstant() &&
2773 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002774 // Can use 3 operand multiply.
2775 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2776 } else {
2777 locations->SetOut(Location::SameAsFirstInput());
2778 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002779 break;
2780 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002781 case Primitive::kPrimFloat:
2782 case Primitive::kPrimDouble: {
2783 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002784 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002785 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002786 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002787 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002788
2789 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002790 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002791 }
2792}
2793
2794void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
2795 LocationSummary* locations = mul->GetLocations();
2796 Location first = locations->InAt(0);
2797 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002798 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002799 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002800 case Primitive::kPrimInt:
2801 // The constant may have ended up in a register, so test explicitly to avoid
2802 // problems where the output may not be the same as the first operand.
2803 if (mul->InputAt(1)->IsIntConstant()) {
2804 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2805 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
2806 } else if (second.IsRegister()) {
2807 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002808 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002809 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002810 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002811 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00002812 __ imull(first.AsRegister<CpuRegister>(),
2813 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002814 }
2815 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002816 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002817 // The constant may have ended up in a register, so test explicitly to avoid
2818 // problems where the output may not be the same as the first operand.
2819 if (mul->InputAt(1)->IsLongConstant()) {
2820 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
2821 if (IsInt<32>(value)) {
2822 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
2823 Immediate(static_cast<int32_t>(value)));
2824 } else {
2825 // Have to use the constant area.
2826 DCHECK(first.Equals(out));
2827 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
2828 }
2829 } else if (second.IsRegister()) {
2830 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002831 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002832 } else {
2833 DCHECK(second.IsDoubleStackSlot());
2834 DCHECK(first.Equals(out));
2835 __ imulq(first.AsRegister<CpuRegister>(),
2836 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002837 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002838 break;
2839 }
2840
Calin Juravleb5bfa962014-10-21 18:02:24 +01002841 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002842 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002843 if (second.IsFpuRegister()) {
2844 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2845 } else if (second.IsConstant()) {
2846 __ mulss(first.AsFpuRegister<XmmRegister>(),
2847 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2848 } else {
2849 DCHECK(second.IsStackSlot());
2850 __ mulss(first.AsFpuRegister<XmmRegister>(),
2851 Address(CpuRegister(RSP), second.GetStackIndex()));
2852 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002853 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002854 }
2855
2856 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002857 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04002858 if (second.IsFpuRegister()) {
2859 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2860 } else if (second.IsConstant()) {
2861 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2862 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2863 } else {
2864 DCHECK(second.IsDoubleStackSlot());
2865 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2866 Address(CpuRegister(RSP), second.GetStackIndex()));
2867 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002868 break;
2869 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002870
2871 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002872 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002873 }
2874}
2875
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002876void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
2877 uint32_t stack_adjustment, bool is_float) {
2878 if (source.IsStackSlot()) {
2879 DCHECK(is_float);
2880 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2881 } else if (source.IsDoubleStackSlot()) {
2882 DCHECK(!is_float);
2883 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
2884 } else {
2885 // Write the value to the temporary location on the stack and load to FP stack.
2886 if (is_float) {
2887 Location stack_temp = Location::StackSlot(temp_offset);
2888 codegen_->Move(stack_temp, source);
2889 __ flds(Address(CpuRegister(RSP), temp_offset));
2890 } else {
2891 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2892 codegen_->Move(stack_temp, source);
2893 __ fldl(Address(CpuRegister(RSP), temp_offset));
2894 }
2895 }
2896}
2897
2898void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
2899 Primitive::Type type = rem->GetResultType();
2900 bool is_float = type == Primitive::kPrimFloat;
2901 size_t elem_size = Primitive::ComponentSize(type);
2902 LocationSummary* locations = rem->GetLocations();
2903 Location first = locations->InAt(0);
2904 Location second = locations->InAt(1);
2905 Location out = locations->Out();
2906
2907 // Create stack space for 2 elements.
2908 // TODO: enhance register allocator to ask for stack temporaries.
2909 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
2910
2911 // Load the values to the FP stack in reverse order, using temporaries if needed.
2912 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2913 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2914
2915 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002916 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002917 __ Bind(&retry);
2918 __ fprem();
2919
2920 // Move FP status to AX.
2921 __ fstsw();
2922
2923 // And see if the argument reduction is complete. This is signaled by the
2924 // C2 FPU flag bit set to 0.
2925 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
2926 __ j(kNotEqual, &retry);
2927
2928 // We have settled on the final value. Retrieve it into an XMM register.
2929 // Store FP top of stack to real stack.
2930 if (is_float) {
2931 __ fsts(Address(CpuRegister(RSP), 0));
2932 } else {
2933 __ fstl(Address(CpuRegister(RSP), 0));
2934 }
2935
2936 // Pop the 2 items from the FP stack.
2937 __ fucompp();
2938
2939 // Load the value from the stack into an XMM register.
2940 DCHECK(out.IsFpuRegister()) << out;
2941 if (is_float) {
2942 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2943 } else {
2944 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
2945 }
2946
2947 // And remove the temporary stack space we allocated.
2948 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
2949}
2950
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002951void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2952 DCHECK(instruction->IsDiv() || instruction->IsRem());
2953
2954 LocationSummary* locations = instruction->GetLocations();
2955 Location second = locations->InAt(1);
2956 DCHECK(second.IsConstant());
2957
2958 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2959 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002960 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002961
2962 DCHECK(imm == 1 || imm == -1);
2963
2964 switch (instruction->GetResultType()) {
2965 case Primitive::kPrimInt: {
2966 if (instruction->IsRem()) {
2967 __ xorl(output_register, output_register);
2968 } else {
2969 __ movl(output_register, input_register);
2970 if (imm == -1) {
2971 __ negl(output_register);
2972 }
2973 }
2974 break;
2975 }
2976
2977 case Primitive::kPrimLong: {
2978 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04002979 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002980 } else {
2981 __ movq(output_register, input_register);
2982 if (imm == -1) {
2983 __ negq(output_register);
2984 }
2985 }
2986 break;
2987 }
2988
2989 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002990 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002991 }
2992}
2993
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002994void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002995 LocationSummary* locations = instruction->GetLocations();
2996 Location second = locations->InAt(1);
2997
2998 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
2999 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3000
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003001 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003002
3003 DCHECK(IsPowerOfTwo(std::abs(imm)));
3004
3005 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3006
3007 if (instruction->GetResultType() == Primitive::kPrimInt) {
3008 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
3009 __ testl(numerator, numerator);
3010 __ cmov(kGreaterEqual, tmp, numerator);
3011 int shift = CTZ(imm);
3012 __ sarl(tmp, Immediate(shift));
3013
3014 if (imm < 0) {
3015 __ negl(tmp);
3016 }
3017
3018 __ movl(output_register, tmp);
3019 } else {
3020 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3021 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3022
Mark Mendell92e83bf2015-05-07 11:25:03 -04003023 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003024 __ addq(rdx, numerator);
3025 __ testq(numerator, numerator);
3026 __ cmov(kGreaterEqual, rdx, numerator);
3027 int shift = CTZ(imm);
3028 __ sarq(rdx, Immediate(shift));
3029
3030 if (imm < 0) {
3031 __ negq(rdx);
3032 }
3033
3034 __ movq(output_register, rdx);
3035 }
3036}
3037
3038void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3039 DCHECK(instruction->IsDiv() || instruction->IsRem());
3040
3041 LocationSummary* locations = instruction->GetLocations();
3042 Location second = locations->InAt(1);
3043
3044 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3045 : locations->GetTemp(0).AsRegister<CpuRegister>();
3046 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3047 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3048 : locations->Out().AsRegister<CpuRegister>();
3049 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3050
3051 DCHECK_EQ(RAX, eax.AsRegister());
3052 DCHECK_EQ(RDX, edx.AsRegister());
3053 if (instruction->IsDiv()) {
3054 DCHECK_EQ(RAX, out.AsRegister());
3055 } else {
3056 DCHECK_EQ(RDX, out.AsRegister());
3057 }
3058
3059 int64_t magic;
3060 int shift;
3061
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003062 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003063 if (instruction->GetResultType() == Primitive::kPrimInt) {
3064 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3065
3066 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3067
3068 __ movl(numerator, eax);
3069
Mark Mendell0c9497d2015-08-21 09:30:05 -04003070 NearLabel no_div;
3071 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003072 __ testl(eax, eax);
3073 __ j(kNotEqual, &no_div);
3074
3075 __ xorl(out, out);
3076 __ jmp(&end);
3077
3078 __ Bind(&no_div);
3079
3080 __ movl(eax, Immediate(magic));
3081 __ imull(numerator);
3082
3083 if (imm > 0 && magic < 0) {
3084 __ addl(edx, numerator);
3085 } else if (imm < 0 && magic > 0) {
3086 __ subl(edx, numerator);
3087 }
3088
3089 if (shift != 0) {
3090 __ sarl(edx, Immediate(shift));
3091 }
3092
3093 __ movl(eax, edx);
3094 __ shrl(edx, Immediate(31));
3095 __ addl(edx, eax);
3096
3097 if (instruction->IsRem()) {
3098 __ movl(eax, numerator);
3099 __ imull(edx, Immediate(imm));
3100 __ subl(eax, edx);
3101 __ movl(edx, eax);
3102 } else {
3103 __ movl(eax, edx);
3104 }
3105 __ Bind(&end);
3106 } else {
3107 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3108
3109 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3110
3111 CpuRegister rax = eax;
3112 CpuRegister rdx = edx;
3113
3114 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3115
3116 // Save the numerator.
3117 __ movq(numerator, rax);
3118
3119 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003120 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003121
3122 // RDX:RAX = magic * numerator
3123 __ imulq(numerator);
3124
3125 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003126 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003127 __ addq(rdx, numerator);
3128 } else if (imm < 0 && magic > 0) {
3129 // RDX -= numerator
3130 __ subq(rdx, numerator);
3131 }
3132
3133 // Shift if needed.
3134 if (shift != 0) {
3135 __ sarq(rdx, Immediate(shift));
3136 }
3137
3138 // RDX += 1 if RDX < 0
3139 __ movq(rax, rdx);
3140 __ shrq(rdx, Immediate(63));
3141 __ addq(rdx, rax);
3142
3143 if (instruction->IsRem()) {
3144 __ movq(rax, numerator);
3145
3146 if (IsInt<32>(imm)) {
3147 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3148 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003149 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003150 }
3151
3152 __ subq(rax, rdx);
3153 __ movq(rdx, rax);
3154 } else {
3155 __ movq(rax, rdx);
3156 }
3157 }
3158}
3159
Calin Juravlebacfec32014-11-14 15:54:36 +00003160void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3161 DCHECK(instruction->IsDiv() || instruction->IsRem());
3162 Primitive::Type type = instruction->GetResultType();
3163 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3164
3165 bool is_div = instruction->IsDiv();
3166 LocationSummary* locations = instruction->GetLocations();
3167
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003168 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3169 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003170
Roland Levillain271ab9c2014-11-27 15:23:57 +00003171 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003172 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003173
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003174 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003175 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003176
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003177 if (imm == 0) {
3178 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3179 } else if (imm == 1 || imm == -1) {
3180 DivRemOneOrMinusOne(instruction);
3181 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003182 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003183 } else {
3184 DCHECK(imm <= -2 || imm >= 2);
3185 GenerateDivRemWithAnyConstant(instruction);
3186 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003187 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003188 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003189 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3190 out.AsRegister(), type, is_div);
3191 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003192
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003193 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3194 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3195 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3196 // so it's safe to just use negl instead of more complex comparisons.
3197 if (type == Primitive::kPrimInt) {
3198 __ cmpl(second_reg, Immediate(-1));
3199 __ j(kEqual, slow_path->GetEntryLabel());
3200 // edx:eax <- sign-extended of eax
3201 __ cdq();
3202 // eax = quotient, edx = remainder
3203 __ idivl(second_reg);
3204 } else {
3205 __ cmpq(second_reg, Immediate(-1));
3206 __ j(kEqual, slow_path->GetEntryLabel());
3207 // rdx:rax <- sign-extended of rax
3208 __ cqo();
3209 // rax = quotient, rdx = remainder
3210 __ idivq(second_reg);
3211 }
3212 __ Bind(slow_path->GetExitLabel());
3213 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003214}
3215
Calin Juravle7c4954d2014-10-28 16:57:40 +00003216void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3217 LocationSummary* locations =
3218 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3219 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003220 case Primitive::kPrimInt:
3221 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003222 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003223 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003224 locations->SetOut(Location::SameAsFirstInput());
3225 // Intel uses edx:eax as the dividend.
3226 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003227 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3228 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3229 // output and request another temp.
3230 if (div->InputAt(1)->IsConstant()) {
3231 locations->AddTemp(Location::RequiresRegister());
3232 }
Calin Juravled0d48522014-11-04 16:40:20 +00003233 break;
3234 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003235
Calin Juravle7c4954d2014-10-28 16:57:40 +00003236 case Primitive::kPrimFloat:
3237 case Primitive::kPrimDouble: {
3238 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003239 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003240 locations->SetOut(Location::SameAsFirstInput());
3241 break;
3242 }
3243
3244 default:
3245 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3246 }
3247}
3248
3249void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3250 LocationSummary* locations = div->GetLocations();
3251 Location first = locations->InAt(0);
3252 Location second = locations->InAt(1);
3253 DCHECK(first.Equals(locations->Out()));
3254
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003255 Primitive::Type type = div->GetResultType();
3256 switch (type) {
3257 case Primitive::kPrimInt:
3258 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003259 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003260 break;
3261 }
3262
Calin Juravle7c4954d2014-10-28 16:57:40 +00003263 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003264 if (second.IsFpuRegister()) {
3265 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3266 } else if (second.IsConstant()) {
3267 __ divss(first.AsFpuRegister<XmmRegister>(),
3268 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3269 } else {
3270 DCHECK(second.IsStackSlot());
3271 __ divss(first.AsFpuRegister<XmmRegister>(),
3272 Address(CpuRegister(RSP), second.GetStackIndex()));
3273 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003274 break;
3275 }
3276
3277 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003278 if (second.IsFpuRegister()) {
3279 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3280 } else if (second.IsConstant()) {
3281 __ divsd(first.AsFpuRegister<XmmRegister>(),
3282 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3283 } else {
3284 DCHECK(second.IsDoubleStackSlot());
3285 __ divsd(first.AsFpuRegister<XmmRegister>(),
3286 Address(CpuRegister(RSP), second.GetStackIndex()));
3287 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003288 break;
3289 }
3290
3291 default:
3292 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3293 }
3294}
3295
Calin Juravlebacfec32014-11-14 15:54:36 +00003296void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003297 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003298 LocationSummary* locations =
3299 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003300
3301 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003302 case Primitive::kPrimInt:
3303 case Primitive::kPrimLong: {
3304 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003305 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003306 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3307 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003308 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3309 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3310 // output and request another temp.
3311 if (rem->InputAt(1)->IsConstant()) {
3312 locations->AddTemp(Location::RequiresRegister());
3313 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003314 break;
3315 }
3316
3317 case Primitive::kPrimFloat:
3318 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003319 locations->SetInAt(0, Location::Any());
3320 locations->SetInAt(1, Location::Any());
3321 locations->SetOut(Location::RequiresFpuRegister());
3322 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003323 break;
3324 }
3325
3326 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003327 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003328 }
3329}
3330
3331void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3332 Primitive::Type type = rem->GetResultType();
3333 switch (type) {
3334 case Primitive::kPrimInt:
3335 case Primitive::kPrimLong: {
3336 GenerateDivRemIntegral(rem);
3337 break;
3338 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003339 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003340 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003341 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003342 break;
3343 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003344 default:
3345 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3346 }
3347}
3348
Calin Juravled0d48522014-11-04 16:40:20 +00003349void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003350 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3351 ? LocationSummary::kCallOnSlowPath
3352 : LocationSummary::kNoCall;
3353 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled0d48522014-11-04 16:40:20 +00003354 locations->SetInAt(0, Location::Any());
3355 if (instruction->HasUses()) {
3356 locations->SetOut(Location::SameAsFirstInput());
3357 }
3358}
3359
3360void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003361 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003362 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3363 codegen_->AddSlowPath(slow_path);
3364
3365 LocationSummary* locations = instruction->GetLocations();
3366 Location value = locations->InAt(0);
3367
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003368 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003369 case Primitive::kPrimByte:
3370 case Primitive::kPrimChar:
3371 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003372 case Primitive::kPrimInt: {
3373 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003374 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003375 __ j(kEqual, slow_path->GetEntryLabel());
3376 } else if (value.IsStackSlot()) {
3377 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3378 __ j(kEqual, slow_path->GetEntryLabel());
3379 } else {
3380 DCHECK(value.IsConstant()) << value;
3381 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3382 __ jmp(slow_path->GetEntryLabel());
3383 }
3384 }
3385 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003386 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003387 case Primitive::kPrimLong: {
3388 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003389 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003390 __ j(kEqual, slow_path->GetEntryLabel());
3391 } else if (value.IsDoubleStackSlot()) {
3392 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3393 __ j(kEqual, slow_path->GetEntryLabel());
3394 } else {
3395 DCHECK(value.IsConstant()) << value;
3396 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3397 __ jmp(slow_path->GetEntryLabel());
3398 }
3399 }
3400 break;
3401 }
3402 default:
3403 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003404 }
Calin Juravled0d48522014-11-04 16:40:20 +00003405}
3406
Calin Juravle9aec02f2014-11-18 23:06:35 +00003407void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3408 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3409
3410 LocationSummary* locations =
3411 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3412
3413 switch (op->GetResultType()) {
3414 case Primitive::kPrimInt:
3415 case Primitive::kPrimLong: {
3416 locations->SetInAt(0, Location::RequiresRegister());
3417 // The shift count needs to be in CL.
3418 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3419 locations->SetOut(Location::SameAsFirstInput());
3420 break;
3421 }
3422 default:
3423 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3424 }
3425}
3426
3427void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3428 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3429
3430 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003431 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003432 Location second = locations->InAt(1);
3433
3434 switch (op->GetResultType()) {
3435 case Primitive::kPrimInt: {
3436 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003437 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003438 if (op->IsShl()) {
3439 __ shll(first_reg, second_reg);
3440 } else if (op->IsShr()) {
3441 __ sarl(first_reg, second_reg);
3442 } else {
3443 __ shrl(first_reg, second_reg);
3444 }
3445 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003446 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003447 if (op->IsShl()) {
3448 __ shll(first_reg, imm);
3449 } else if (op->IsShr()) {
3450 __ sarl(first_reg, imm);
3451 } else {
3452 __ shrl(first_reg, imm);
3453 }
3454 }
3455 break;
3456 }
3457 case Primitive::kPrimLong: {
3458 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003459 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003460 if (op->IsShl()) {
3461 __ shlq(first_reg, second_reg);
3462 } else if (op->IsShr()) {
3463 __ sarq(first_reg, second_reg);
3464 } else {
3465 __ shrq(first_reg, second_reg);
3466 }
3467 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003468 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003469 if (op->IsShl()) {
3470 __ shlq(first_reg, imm);
3471 } else if (op->IsShr()) {
3472 __ sarq(first_reg, imm);
3473 } else {
3474 __ shrq(first_reg, imm);
3475 }
3476 }
3477 break;
3478 }
3479 default:
3480 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3481 }
3482}
3483
3484void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3485 HandleShift(shl);
3486}
3487
3488void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3489 HandleShift(shl);
3490}
3491
3492void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3493 HandleShift(shr);
3494}
3495
3496void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3497 HandleShift(shr);
3498}
3499
3500void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3501 HandleShift(ushr);
3502}
3503
3504void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3505 HandleShift(ushr);
3506}
3507
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003508void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003509 LocationSummary* locations =
3510 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003511 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003512 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003513 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003514 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003515}
3516
3517void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
3518 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003519 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3520 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003521 // Note: if heap poisoning is enabled, the entry point takes cares
3522 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01003523
Calin Juravle175dc732015-08-25 15:42:32 +01003524 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3525 instruction,
3526 instruction->GetDexPc(),
3527 nullptr);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003528
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003529 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003530}
3531
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003532void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3533 LocationSummary* locations =
3534 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3535 InvokeRuntimeCallingConvention calling_convention;
3536 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003537 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003538 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003539 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003540}
3541
3542void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3543 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003544 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3545 instruction->GetTypeIndex());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003546
Roland Levillain4d027112015-07-01 15:41:14 +01003547 // Note: if heap poisoning is enabled, the entry point takes cares
3548 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003549 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3550 instruction,
3551 instruction->GetDexPc(),
3552 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003553
3554 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003555}
3556
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003557void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003558 LocationSummary* locations =
3559 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003560 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3561 if (location.IsStackSlot()) {
3562 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3563 } else if (location.IsDoubleStackSlot()) {
3564 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3565 }
3566 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003567}
3568
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003569void InstructionCodeGeneratorX86_64::VisitParameterValue(
3570 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003571 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003572}
3573
3574void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3575 LocationSummary* locations =
3576 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3577 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3578}
3579
3580void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3581 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3582 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003583}
3584
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003585void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003586 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003587 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003588 locations->SetInAt(0, Location::RequiresRegister());
3589 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003590}
3591
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003592void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3593 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003594 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3595 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003596 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003597 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003598 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003599 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003600 break;
3601
3602 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003604 break;
3605
3606 default:
3607 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3608 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003609}
3610
David Brazdil66d126e2015-04-03 16:02:44 +01003611void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3612 LocationSummary* locations =
3613 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3614 locations->SetInAt(0, Location::RequiresRegister());
3615 locations->SetOut(Location::SameAsFirstInput());
3616}
3617
3618void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003619 LocationSummary* locations = bool_not->GetLocations();
3620 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3621 locations->Out().AsRegister<CpuRegister>().AsRegister());
3622 Location out = locations->Out();
3623 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3624}
3625
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003626void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003627 LocationSummary* locations =
3628 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003629 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3630 locations->SetInAt(i, Location::Any());
3631 }
3632 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003633}
3634
3635void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003636 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003637 LOG(FATAL) << "Unimplemented";
3638}
3639
Calin Juravle52c48962014-12-16 17:02:57 +00003640void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3641 /*
3642 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3643 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3644 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3645 */
3646 switch (kind) {
3647 case MemBarrierKind::kAnyAny: {
3648 __ mfence();
3649 break;
3650 }
3651 case MemBarrierKind::kAnyStore:
3652 case MemBarrierKind::kLoadAny:
3653 case MemBarrierKind::kStoreStore: {
3654 // nop
3655 break;
3656 }
3657 default:
3658 LOG(FATAL) << "Unexpected memory barier " << kind;
3659 }
3660}
3661
3662void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3663 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3664
Nicolas Geoffray39468442014-09-02 15:17:15 +01003665 LocationSummary* locations =
3666 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003667 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003668 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3669 locations->SetOut(Location::RequiresFpuRegister());
3670 } else {
3671 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3672 }
Calin Juravle52c48962014-12-16 17:02:57 +00003673}
3674
3675void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3676 const FieldInfo& field_info) {
3677 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3678
3679 LocationSummary* locations = instruction->GetLocations();
3680 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3681 Location out = locations->Out();
3682 bool is_volatile = field_info.IsVolatile();
3683 Primitive::Type field_type = field_info.GetFieldType();
3684 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3685
3686 switch (field_type) {
3687 case Primitive::kPrimBoolean: {
3688 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3689 break;
3690 }
3691
3692 case Primitive::kPrimByte: {
3693 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3694 break;
3695 }
3696
3697 case Primitive::kPrimShort: {
3698 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3699 break;
3700 }
3701
3702 case Primitive::kPrimChar: {
3703 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3704 break;
3705 }
3706
3707 case Primitive::kPrimInt:
3708 case Primitive::kPrimNot: {
3709 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3710 break;
3711 }
3712
3713 case Primitive::kPrimLong: {
3714 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3715 break;
3716 }
3717
3718 case Primitive::kPrimFloat: {
3719 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3720 break;
3721 }
3722
3723 case Primitive::kPrimDouble: {
3724 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3725 break;
3726 }
3727
3728 case Primitive::kPrimVoid:
3729 LOG(FATAL) << "Unreachable type " << field_type;
3730 UNREACHABLE();
3731 }
3732
Calin Juravle77520bc2015-01-12 18:45:46 +00003733 codegen_->MaybeRecordImplicitNullCheck(instruction);
3734
Calin Juravle52c48962014-12-16 17:02:57 +00003735 if (is_volatile) {
3736 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3737 }
Roland Levillain4d027112015-07-01 15:41:14 +01003738
3739 if (field_type == Primitive::kPrimNot) {
3740 __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
3741 }
Calin Juravle52c48962014-12-16 17:02:57 +00003742}
3743
3744void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
3745 const FieldInfo& field_info) {
3746 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3747
3748 LocationSummary* locations =
3749 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01003750 Primitive::Type field_type = field_info.GetFieldType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003751 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01003752 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003753
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003754 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003755 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
3756 locations->SetInAt(1, Location::RequiresFpuRegister());
3757 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04003758 locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003759 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003760 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003761 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003762 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003763 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01003764 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3765 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003766 locations->AddTemp(Location::RequiresRegister());
3767 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003768}
3769
Calin Juravle52c48962014-12-16 17:02:57 +00003770void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003771 const FieldInfo& field_info,
3772 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003773 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3774
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003775 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003776 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
3777 Location value = locations->InAt(1);
3778 bool is_volatile = field_info.IsVolatile();
3779 Primitive::Type field_type = field_info.GetFieldType();
3780 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3781
3782 if (is_volatile) {
3783 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3784 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003785
3786 switch (field_type) {
3787 case Primitive::kPrimBoolean:
3788 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04003789 if (value.IsConstant()) {
3790 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3791 __ movb(Address(base, offset), Immediate(v));
3792 } else {
3793 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
3794 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003795 break;
3796 }
3797
3798 case Primitive::kPrimShort:
3799 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04003800 if (value.IsConstant()) {
3801 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
3802 __ movw(Address(base, offset), Immediate(v));
3803 } else {
3804 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
3805 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003806 break;
3807 }
3808
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003809 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003810 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04003811 if (value.IsConstant()) {
3812 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01003813 // `field_type == Primitive::kPrimNot` implies `v == 0`.
3814 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
3815 // Note: if heap poisoning is enabled, no need to poison
3816 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01003817 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003818 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01003819 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
3820 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3821 __ movl(temp, value.AsRegister<CpuRegister>());
3822 __ PoisonHeapReference(temp);
3823 __ movl(Address(base, offset), temp);
3824 } else {
3825 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
3826 }
Mark Mendell40741f32015-04-20 22:10:34 -04003827 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003828 break;
3829 }
3830
3831 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04003832 if (value.IsConstant()) {
3833 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
3834 DCHECK(IsInt<32>(v));
3835 int32_t v_32 = v;
3836 __ movq(Address(base, offset), Immediate(v_32));
3837 } else {
3838 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
3839 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003840 break;
3841 }
3842
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003843 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003844 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003845 break;
3846 }
3847
3848 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003849 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003850 break;
3851 }
3852
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003853 case Primitive::kPrimVoid:
3854 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003855 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003856 }
Calin Juravle52c48962014-12-16 17:02:57 +00003857
Calin Juravle77520bc2015-01-12 18:45:46 +00003858 codegen_->MaybeRecordImplicitNullCheck(instruction);
3859
3860 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3861 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
3862 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003863 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003864 }
3865
Calin Juravle52c48962014-12-16 17:02:57 +00003866 if (is_volatile) {
3867 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3868 }
3869}
3870
3871void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3872 HandleFieldSet(instruction, instruction->GetFieldInfo());
3873}
3874
3875void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003876 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003877}
3878
3879void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003880 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003881}
3882
3883void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00003884 HandleFieldGet(instruction, instruction->GetFieldInfo());
3885}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003886
Calin Juravle52c48962014-12-16 17:02:57 +00003887void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3888 HandleFieldGet(instruction);
3889}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003890
Calin Juravle52c48962014-12-16 17:02:57 +00003891void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3892 HandleFieldGet(instruction, instruction->GetFieldInfo());
3893}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003894
Calin Juravle52c48962014-12-16 17:02:57 +00003895void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3896 HandleFieldSet(instruction, instruction->GetFieldInfo());
3897}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003898
Calin Juravle52c48962014-12-16 17:02:57 +00003899void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003900 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003901}
3902
Calin Juravlee460d1d2015-09-29 04:52:17 +01003903void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
3904 HUnresolvedInstanceFieldGet* instruction) {
3905 FieldAccessCallingConventionX86_64 calling_convention;
3906 codegen_->CreateUnresolvedFieldLocationSummary(
3907 instruction, instruction->GetFieldType(), calling_convention);
3908}
3909
3910void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
3911 HUnresolvedInstanceFieldGet* instruction) {
3912 FieldAccessCallingConventionX86_64 calling_convention;
3913 codegen_->GenerateUnresolvedFieldAccess(instruction,
3914 instruction->GetFieldType(),
3915 instruction->GetFieldIndex(),
3916 instruction->GetDexPc(),
3917 calling_convention);
3918}
3919
3920void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
3921 HUnresolvedInstanceFieldSet* instruction) {
3922 FieldAccessCallingConventionX86_64 calling_convention;
3923 codegen_->CreateUnresolvedFieldLocationSummary(
3924 instruction, instruction->GetFieldType(), calling_convention);
3925}
3926
3927void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
3928 HUnresolvedInstanceFieldSet* instruction) {
3929 FieldAccessCallingConventionX86_64 calling_convention;
3930 codegen_->GenerateUnresolvedFieldAccess(instruction,
3931 instruction->GetFieldType(),
3932 instruction->GetFieldIndex(),
3933 instruction->GetDexPc(),
3934 calling_convention);
3935}
3936
3937void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
3938 HUnresolvedStaticFieldGet* instruction) {
3939 FieldAccessCallingConventionX86_64 calling_convention;
3940 codegen_->CreateUnresolvedFieldLocationSummary(
3941 instruction, instruction->GetFieldType(), calling_convention);
3942}
3943
3944void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
3945 HUnresolvedStaticFieldGet* instruction) {
3946 FieldAccessCallingConventionX86_64 calling_convention;
3947 codegen_->GenerateUnresolvedFieldAccess(instruction,
3948 instruction->GetFieldType(),
3949 instruction->GetFieldIndex(),
3950 instruction->GetDexPc(),
3951 calling_convention);
3952}
3953
3954void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
3955 HUnresolvedStaticFieldSet* instruction) {
3956 FieldAccessCallingConventionX86_64 calling_convention;
3957 codegen_->CreateUnresolvedFieldLocationSummary(
3958 instruction, instruction->GetFieldType(), calling_convention);
3959}
3960
3961void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
3962 HUnresolvedStaticFieldSet* instruction) {
3963 FieldAccessCallingConventionX86_64 calling_convention;
3964 codegen_->GenerateUnresolvedFieldAccess(instruction,
3965 instruction->GetFieldType(),
3966 instruction->GetFieldIndex(),
3967 instruction->GetDexPc(),
3968 calling_convention);
3969}
3970
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003971void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003972 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3973 ? LocationSummary::kCallOnSlowPath
3974 : LocationSummary::kNoCall;
3975 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3976 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003977 ? Location::RequiresRegister()
3978 : Location::Any();
3979 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003980 if (instruction->HasUses()) {
3981 locations->SetOut(Location::SameAsFirstInput());
3982 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003983}
3984
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003985void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003986 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3987 return;
3988 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003989 LocationSummary* locations = instruction->GetLocations();
3990 Location obj = locations->InAt(0);
3991
3992 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
3993 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3994}
3995
3996void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003997 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003998 codegen_->AddSlowPath(slow_path);
3999
4000 LocationSummary* locations = instruction->GetLocations();
4001 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004002
4003 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004004 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004005 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004006 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004007 } else {
4008 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004009 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004010 __ jmp(slow_path->GetEntryLabel());
4011 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004012 }
4013 __ j(kEqual, slow_path->GetEntryLabel());
4014}
4015
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004016void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004017 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004018 GenerateImplicitNullCheck(instruction);
4019 } else {
4020 GenerateExplicitNullCheck(instruction);
4021 }
4022}
4023
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004024void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004025 LocationSummary* locations =
4026 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004027 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004028 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004029 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4030 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4031 } else {
4032 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4033 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004034}
4035
4036void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4037 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004038 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004039 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004040 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004041
Roland Levillain4d027112015-07-01 15:41:14 +01004042 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004043 case Primitive::kPrimBoolean: {
4044 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004045 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004046 if (index.IsConstant()) {
4047 __ movzxb(out, Address(obj,
4048 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4049 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004050 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004051 }
4052 break;
4053 }
4054
4055 case Primitive::kPrimByte: {
4056 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004057 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004058 if (index.IsConstant()) {
4059 __ movsxb(out, Address(obj,
4060 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4061 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004062 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004063 }
4064 break;
4065 }
4066
4067 case Primitive::kPrimShort: {
4068 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004069 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004070 if (index.IsConstant()) {
4071 __ movsxw(out, Address(obj,
4072 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4073 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004074 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004075 }
4076 break;
4077 }
4078
4079 case Primitive::kPrimChar: {
4080 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004081 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004082 if (index.IsConstant()) {
4083 __ movzxw(out, Address(obj,
4084 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4085 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004086 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004087 }
4088 break;
4089 }
4090
4091 case Primitive::kPrimInt:
4092 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01004093 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4094 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004095 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004096 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004097 if (index.IsConstant()) {
4098 __ movl(out, Address(obj,
4099 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4100 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004101 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004102 }
4103 break;
4104 }
4105
4106 case Primitive::kPrimLong: {
4107 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004108 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004109 if (index.IsConstant()) {
4110 __ movq(out, Address(obj,
4111 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4112 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004113 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004114 }
4115 break;
4116 }
4117
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004118 case Primitive::kPrimFloat: {
4119 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004120 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004121 if (index.IsConstant()) {
4122 __ movss(out, Address(obj,
4123 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4124 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004125 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004126 }
4127 break;
4128 }
4129
4130 case Primitive::kPrimDouble: {
4131 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004132 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004133 if (index.IsConstant()) {
4134 __ movsd(out, Address(obj,
4135 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4136 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004137 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004138 }
4139 break;
4140 }
4141
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004142 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004143 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004144 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004145 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004146 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004147
4148 if (type == Primitive::kPrimNot) {
4149 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4150 __ MaybeUnpoisonHeapReference(out);
4151 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004152}
4153
4154void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004155 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004156
4157 bool needs_write_barrier =
4158 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004159 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004160
Nicolas Geoffray39468442014-09-02 15:17:15 +01004161 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004162 instruction,
4163 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004164
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004165 locations->SetInAt(0, Location::RequiresRegister());
4166 locations->SetInAt(
4167 1, Location::RegisterOrConstant(instruction->InputAt(1)));
4168 locations->SetInAt(2, Location::RequiresRegister());
4169 if (value_type == Primitive::kPrimLong) {
4170 locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
4171 } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
4172 locations->SetInAt(2, Location::RequiresFpuRegister());
4173 } else {
4174 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4175 }
4176
4177 if (needs_write_barrier) {
4178 // Temporary registers for the write barrier.
4179 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4180 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004181 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004182}
4183
4184void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4185 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004186 CpuRegister array = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004187 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004188 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004189 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004190 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004191 bool needs_write_barrier =
4192 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004193 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4194 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4195 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004196
4197 switch (value_type) {
4198 case Primitive::kPrimBoolean:
4199 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004200 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4201 Address address = index.IsConstant()
4202 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4203 : Address(array, index.AsRegister<CpuRegister>(), TIMES_1, offset);
4204 if (value.IsRegister()) {
4205 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004206 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004207 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004208 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004209 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004210 break;
4211 }
4212
4213 case Primitive::kPrimShort:
4214 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004215 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4216 Address address = index.IsConstant()
4217 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4218 : Address(array, index.AsRegister<CpuRegister>(), TIMES_2, offset);
4219 if (value.IsRegister()) {
4220 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004221 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004222 DCHECK(value.IsConstant()) << value;
4223 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004224 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004225 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004226 break;
4227 }
4228
4229 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004230 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4231 Address address = index.IsConstant()
4232 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4233 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4234 if (!value.IsRegister()) {
4235 // Just setting null.
4236 DCHECK(instruction->InputAt(2)->IsNullConstant());
4237 DCHECK(value.IsConstant()) << value;
4238 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004239 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004240 DCHECK(!needs_write_barrier);
4241 DCHECK(!may_need_runtime_call);
4242 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004243 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004244
4245 DCHECK(needs_write_barrier);
4246 CpuRegister register_value = value.AsRegister<CpuRegister>();
4247 NearLabel done, not_null, do_put;
4248 SlowPathCode* slow_path = nullptr;
4249 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4250 if (may_need_runtime_call) {
4251 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4252 codegen_->AddSlowPath(slow_path);
4253 if (instruction->GetValueCanBeNull()) {
4254 __ testl(register_value, register_value);
4255 __ j(kNotEqual, &not_null);
4256 __ movl(address, Immediate(0));
4257 codegen_->MaybeRecordImplicitNullCheck(instruction);
4258 __ jmp(&done);
4259 __ Bind(&not_null);
4260 }
4261
4262 __ movl(temp, Address(array, class_offset));
4263 codegen_->MaybeRecordImplicitNullCheck(instruction);
4264 __ MaybeUnpoisonHeapReference(temp);
4265 __ movl(temp, Address(temp, component_offset));
4266 // No need to poison/unpoison, we're comparing two poisoned references.
4267 __ cmpl(temp, Address(register_value, class_offset));
4268 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4269 __ j(kEqual, &do_put);
4270 __ MaybeUnpoisonHeapReference(temp);
4271 __ movl(temp, Address(temp, super_offset));
4272 // No need to unpoison the result, we're comparing against null.
4273 __ testl(temp, temp);
4274 __ j(kNotEqual, slow_path->GetEntryLabel());
4275 __ Bind(&do_put);
4276 } else {
4277 __ j(kNotEqual, slow_path->GetEntryLabel());
4278 }
4279 }
4280
4281 if (kPoisonHeapReferences) {
4282 __ movl(temp, register_value);
4283 __ PoisonHeapReference(temp);
4284 __ movl(address, temp);
4285 } else {
4286 __ movl(address, register_value);
4287 }
4288 if (!may_need_runtime_call) {
4289 codegen_->MaybeRecordImplicitNullCheck(instruction);
4290 }
4291
4292 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4293 codegen_->MarkGCCard(
4294 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4295 __ Bind(&done);
4296
4297 if (slow_path != nullptr) {
4298 __ Bind(slow_path->GetExitLabel());
4299 }
4300
4301 break;
4302 }
4303 case Primitive::kPrimInt: {
4304 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4305 Address address = index.IsConstant()
4306 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4307 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4308 if (value.IsRegister()) {
4309 __ movl(address, value.AsRegister<CpuRegister>());
4310 } else {
4311 DCHECK(value.IsConstant()) << value;
4312 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4313 __ movl(address, Immediate(v));
4314 }
4315 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004316 break;
4317 }
4318
4319 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004320 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4321 Address address = index.IsConstant()
4322 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4323 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4324 if (value.IsRegister()) {
4325 __ movq(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004326 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004327 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
4328 DCHECK(IsInt<32>(v));
4329 int32_t v_32 = v;
4330 __ movq(address, Immediate(v_32));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004331 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004332 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004333 break;
4334 }
4335
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004336 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004337 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4338 Address address = index.IsConstant()
4339 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4340 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4341 DCHECK(value.IsFpuRegister());
4342 __ movss(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
4347 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004348 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4349 Address address = index.IsConstant()
4350 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4351 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4352 DCHECK(value.IsFpuRegister());
4353 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004354 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004355 break;
4356 }
4357
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358 case Primitive::kPrimVoid:
4359 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004360 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004361 }
4362}
4363
4364void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004365 LocationSummary* locations =
4366 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004367 locations->SetInAt(0, Location::RequiresRegister());
4368 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004369}
4370
4371void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4372 LocationSummary* locations = instruction->GetLocations();
4373 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004374 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4375 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004376 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004377 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004378}
4379
4380void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004381 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4382 ? LocationSummary::kCallOnSlowPath
4383 : LocationSummary::kNoCall;
4384 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004385 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004386 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004387 if (instruction->HasUses()) {
4388 locations->SetOut(Location::SameAsFirstInput());
4389 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004390}
4391
4392void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4393 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004394 Location index_loc = locations->InAt(0);
4395 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004396 SlowPathCode* slow_path =
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004397 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004398
Mark Mendell99dbd682015-04-22 16:18:52 -04004399 if (length_loc.IsConstant()) {
4400 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4401 if (index_loc.IsConstant()) {
4402 // BCE will remove the bounds check if we are guarenteed to pass.
4403 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4404 if (index < 0 || index >= length) {
4405 codegen_->AddSlowPath(slow_path);
4406 __ jmp(slow_path->GetEntryLabel());
4407 } else {
4408 // Some optimization after BCE may have generated this, and we should not
4409 // generate a bounds check if it is a valid range.
4410 }
4411 return;
4412 }
4413
4414 // We have to reverse the jump condition because the length is the constant.
4415 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4416 __ cmpl(index_reg, Immediate(length));
4417 codegen_->AddSlowPath(slow_path);
4418 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004419 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004420 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4421 if (index_loc.IsConstant()) {
4422 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4423 __ cmpl(length, Immediate(value));
4424 } else {
4425 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4426 }
4427 codegen_->AddSlowPath(slow_path);
4428 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004429 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004430}
4431
4432void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4433 CpuRegister card,
4434 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004435 CpuRegister value,
4436 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004437 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004438 if (value_can_be_null) {
4439 __ testl(value, value);
4440 __ j(kEqual, &is_null);
4441 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004442 __ gs()->movq(card, Address::Absolute(
4443 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4444 __ movq(temp, object);
4445 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004446 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004447 if (value_can_be_null) {
4448 __ Bind(&is_null);
4449 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004450}
4451
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004452void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4453 temp->SetLocations(nullptr);
4454}
4455
4456void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
4457 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004458 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004459}
4460
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004461void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004462 UNUSED(instruction);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004463 LOG(FATAL) << "Unimplemented";
4464}
4465
4466void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004467 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4468}
4469
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004470void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4471 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4472}
4473
4474void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004475 HBasicBlock* block = instruction->GetBlock();
4476 if (block->GetLoopInformation() != nullptr) {
4477 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4478 // The back edge will generate the suspend check.
4479 return;
4480 }
4481 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4482 // The goto will generate the suspend check.
4483 return;
4484 }
4485 GenerateSuspendCheck(instruction, nullptr);
4486}
4487
4488void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4489 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004490 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004491 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4492 if (slow_path == nullptr) {
4493 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4494 instruction->SetSlowPath(slow_path);
4495 codegen_->AddSlowPath(slow_path);
4496 if (successor != nullptr) {
4497 DCHECK(successor->IsLoopHeader());
4498 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4499 }
4500 } else {
4501 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4502 }
4503
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004504 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004505 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004506 if (successor == nullptr) {
4507 __ j(kNotEqual, slow_path->GetEntryLabel());
4508 __ Bind(slow_path->GetReturnLabel());
4509 } else {
4510 __ j(kEqual, codegen_->GetLabelOf(successor));
4511 __ jmp(slow_path->GetEntryLabel());
4512 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004513}
4514
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004515X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4516 return codegen_->GetAssembler();
4517}
4518
4519void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004520 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004521 Location source = move->GetSource();
4522 Location destination = move->GetDestination();
4523
4524 if (source.IsRegister()) {
4525 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004526 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004527 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004528 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004529 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004530 } else {
4531 DCHECK(destination.IsDoubleStackSlot());
4532 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004533 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004534 }
4535 } else if (source.IsStackSlot()) {
4536 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004537 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004538 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004539 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004540 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004541 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004542 } else {
4543 DCHECK(destination.IsStackSlot());
4544 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4545 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4546 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004547 } else if (source.IsDoubleStackSlot()) {
4548 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004549 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004550 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004551 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004552 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4553 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004554 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004555 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004556 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4557 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4558 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004559 } else if (source.IsConstant()) {
4560 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004561 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4562 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004563 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004564 if (value == 0) {
4565 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4566 } else {
4567 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4568 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004569 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004570 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004571 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004572 }
4573 } else if (constant->IsLongConstant()) {
4574 int64_t value = constant->AsLongConstant()->GetValue();
4575 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004576 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004577 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004578 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004579 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004580 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004581 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004582 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004583 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004584 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004585 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4586 if (value == 0) {
4587 // easy FP 0.0.
4588 __ xorps(dest, dest);
4589 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004590 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004591 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004592 } else {
4593 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004594 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004595 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4596 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004597 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004598 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004599 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004600 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004601 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004602 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4603 if (value == 0) {
4604 __ xorpd(dest, dest);
4605 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004606 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004607 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004608 } else {
4609 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004610 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004611 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004612 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004613 } else if (source.IsFpuRegister()) {
4614 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004615 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004616 } else if (destination.IsStackSlot()) {
4617 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004618 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004619 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00004620 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004621 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004622 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004623 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004624 }
4625}
4626
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004627void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004628 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004629 __ movl(Address(CpuRegister(RSP), mem), reg);
4630 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004631}
4632
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004633void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004634 ScratchRegisterScope ensure_scratch(
4635 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
4636
4637 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4638 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4639 __ movl(CpuRegister(ensure_scratch.GetRegister()),
4640 Address(CpuRegister(RSP), mem2 + stack_offset));
4641 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4642 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
4643 CpuRegister(ensure_scratch.GetRegister()));
4644}
4645
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004646void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
4647 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4648 __ movq(Address(CpuRegister(RSP), mem), reg);
4649 __ movq(reg, CpuRegister(TMP));
4650}
4651
4652void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
4653 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004654 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004655
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004656 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
4657 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
4658 __ movq(CpuRegister(ensure_scratch.GetRegister()),
4659 Address(CpuRegister(RSP), mem2 + stack_offset));
4660 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
4661 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
4662 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004663}
4664
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004665void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
4666 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4667 __ movss(Address(CpuRegister(RSP), mem), reg);
4668 __ movd(reg, CpuRegister(TMP));
4669}
4670
4671void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
4672 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
4673 __ movsd(Address(CpuRegister(RSP), mem), reg);
4674 __ movd(reg, CpuRegister(TMP));
4675}
4676
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004677void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004678 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004679 Location source = move->GetSource();
4680 Location destination = move->GetDestination();
4681
4682 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004683 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004684 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004685 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004686 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004687 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004688 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004689 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
4690 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004691 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004692 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004693 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004694 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
4695 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004696 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004697 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
4698 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4699 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004700 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004701 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004702 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004703 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004704 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004705 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004706 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004707 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004708 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004709 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004710 }
4711}
4712
4713
4714void ParallelMoveResolverX86_64::SpillScratch(int reg) {
4715 __ pushq(CpuRegister(reg));
4716}
4717
4718
4719void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
4720 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004721}
4722
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004723void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004724 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004725 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4726 Immediate(mirror::Class::kStatusInitialized));
4727 __ j(kLess, slow_path->GetEntryLabel());
4728 __ Bind(slow_path->GetExitLabel());
4729 // No need for memory fence, thanks to the X86_64 memory model.
4730}
4731
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004732void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004733 InvokeRuntimeCallingConvention calling_convention;
4734 CodeGenerator::CreateLoadClassLocationSummary(
4735 cls,
4736 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4737 Location::RegisterLocation(RAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004738}
4739
4740void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004741 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01004742 if (cls->NeedsAccessCheck()) {
4743 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
4744 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
4745 cls,
4746 cls->GetDexPc(),
4747 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01004748 return;
4749 }
4750
4751 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4752 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
4753 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004754 DCHECK(!cls->CanCallRuntime());
4755 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004756 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004757 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004758 DCHECK(cls->CanCallRuntime());
Vladimir Marko05792b92015-08-03 11:56:49 +01004759 __ movq(out, Address(
4760 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004761 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004762 // TODO: We will need a read barrier here.
Roland Levillain4d027112015-07-01 15:41:14 +01004763
Andreas Gampe85b62f22015-09-09 13:15:38 -07004764 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004765 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4766 codegen_->AddSlowPath(slow_path);
4767 __ testl(out, out);
4768 __ j(kEqual, slow_path->GetEntryLabel());
4769 if (cls->MustGenerateClinitCheck()) {
4770 GenerateClassInitializationCheck(slow_path, out);
4771 } else {
4772 __ Bind(slow_path->GetExitLabel());
4773 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004774 }
4775}
4776
4777void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
4778 LocationSummary* locations =
4779 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4780 locations->SetInAt(0, Location::RequiresRegister());
4781 if (check->HasUses()) {
4782 locations->SetOut(Location::SameAsFirstInput());
4783 }
4784}
4785
4786void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004787 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004788 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004789 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004790 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004791 GenerateClassInitializationCheck(slow_path,
4792 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004793}
4794
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004795void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
4796 LocationSummary* locations =
4797 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004798 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004799 locations->SetOut(Location::RequiresRegister());
4800}
4801
4802void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004803 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004804 codegen_->AddSlowPath(slow_path);
4805
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004806 LocationSummary* locations = load->GetLocations();
4807 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4808 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004809 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004810 __ movq(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004811 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004812 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004813 __ testl(out, out);
4814 __ j(kEqual, slow_path->GetEntryLabel());
4815 __ Bind(slow_path->GetExitLabel());
4816}
4817
David Brazdilcb1c0552015-08-04 16:22:25 +01004818static Address GetExceptionTlsAddress() {
4819 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
4820}
4821
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004822void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
4823 LocationSummary* locations =
4824 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4825 locations->SetOut(Location::RequiresRegister());
4826}
4827
4828void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004829 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
4830}
4831
4832void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
4833 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4834}
4835
4836void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4837 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004838}
4839
4840void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
4841 LocationSummary* locations =
4842 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4843 InvokeRuntimeCallingConvention calling_convention;
4844 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4845}
4846
4847void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004848 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4849 instruction,
4850 instruction->GetDexPc(),
4851 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004852}
4853
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004854void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004855 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4856 switch (instruction->GetTypeCheckKind()) {
4857 case TypeCheckKind::kExactCheck:
4858 case TypeCheckKind::kAbstractClassCheck:
4859 case TypeCheckKind::kClassHierarchyCheck:
4860 case TypeCheckKind::kArrayObjectCheck:
4861 call_kind = LocationSummary::kNoCall;
4862 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004863 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004864 case TypeCheckKind::kInterfaceCheck:
4865 call_kind = LocationSummary::kCall;
4866 break;
4867 case TypeCheckKind::kArrayCheck:
4868 call_kind = LocationSummary::kCallOnSlowPath;
4869 break;
4870 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004871 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004872 if (call_kind != LocationSummary::kCall) {
4873 locations->SetInAt(0, Location::RequiresRegister());
4874 locations->SetInAt(1, Location::Any());
4875 // Note that TypeCheckSlowPathX86_64 uses this register too.
4876 locations->SetOut(Location::RequiresRegister());
4877 } else {
4878 InvokeRuntimeCallingConvention calling_convention;
4879 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4880 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4881 locations->SetOut(Location::RegisterLocation(RAX));
4882 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004883}
4884
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004885void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004886 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004887 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004888 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004889 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004890 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004891 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4892 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4893 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004894 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004895 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004896
4897 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004898 // Avoid null check if we know obj is not null.
4899 if (instruction->MustDoNullCheck()) {
4900 __ testl(obj, obj);
4901 __ j(kEqual, &zero);
4902 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004903
Calin Juravle98893e12015-10-02 21:05:03 +01004904 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004905 // This is safe, as the register is caller-save, and the object must be in another
4906 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01004907 CpuRegister target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
4908 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004909 ? obj
4910 : out;
4911 __ movl(target, Address(obj, class_offset));
4912 __ MaybeUnpoisonHeapReference(target);
4913
4914 switch (instruction->GetTypeCheckKind()) {
4915 case TypeCheckKind::kExactCheck: {
4916 if (cls.IsRegister()) {
4917 __ cmpl(out, cls.AsRegister<CpuRegister>());
4918 } else {
4919 DCHECK(cls.IsStackSlot()) << cls;
4920 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4921 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004922 if (zero.IsLinked()) {
4923 // Classes must be equal for the instanceof to succeed.
4924 __ j(kNotEqual, &zero);
4925 __ movl(out, Immediate(1));
4926 __ jmp(&done);
4927 } else {
4928 __ setcc(kEqual, out);
4929 // setcc only sets the low byte.
4930 __ andl(out, Immediate(1));
4931 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004932 break;
4933 }
4934 case TypeCheckKind::kAbstractClassCheck: {
4935 // If the class is abstract, we eagerly fetch the super class of the
4936 // object to avoid doing a comparison we know will fail.
4937 NearLabel loop, success;
4938 __ Bind(&loop);
4939 __ movl(out, Address(out, super_offset));
4940 __ MaybeUnpoisonHeapReference(out);
4941 __ testl(out, out);
4942 // If `out` is null, we use it for the result, and jump to `done`.
4943 __ j(kEqual, &done);
4944 if (cls.IsRegister()) {
4945 __ cmpl(out, cls.AsRegister<CpuRegister>());
4946 } else {
4947 DCHECK(cls.IsStackSlot()) << cls;
4948 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4949 }
4950 __ j(kNotEqual, &loop);
4951 __ movl(out, Immediate(1));
4952 if (zero.IsLinked()) {
4953 __ jmp(&done);
4954 }
4955 break;
4956 }
4957 case TypeCheckKind::kClassHierarchyCheck: {
4958 // Walk over the class hierarchy to find a match.
4959 NearLabel loop, success;
4960 __ Bind(&loop);
4961 if (cls.IsRegister()) {
4962 __ cmpl(out, cls.AsRegister<CpuRegister>());
4963 } else {
4964 DCHECK(cls.IsStackSlot()) << cls;
4965 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4966 }
4967 __ j(kEqual, &success);
4968 __ movl(out, Address(out, super_offset));
4969 __ MaybeUnpoisonHeapReference(out);
4970 __ testl(out, out);
4971 __ j(kNotEqual, &loop);
4972 // If `out` is null, we use it for the result, and jump to `done`.
4973 __ jmp(&done);
4974 __ Bind(&success);
4975 __ movl(out, Immediate(1));
4976 if (zero.IsLinked()) {
4977 __ jmp(&done);
4978 }
4979 break;
4980 }
4981 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004982 // Do an exact check.
4983 NearLabel exact_check;
4984 if (cls.IsRegister()) {
4985 __ cmpl(out, cls.AsRegister<CpuRegister>());
4986 } else {
4987 DCHECK(cls.IsStackSlot()) << cls;
4988 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
4989 }
4990 __ j(kEqual, &exact_check);
4991 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004992 __ movl(out, Address(out, component_offset));
4993 __ MaybeUnpoisonHeapReference(out);
4994 __ testl(out, out);
4995 // If `out` is null, we use it for the result, and jump to `done`.
4996 __ j(kEqual, &done);
4997 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
4998 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004999 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005000 __ movl(out, Immediate(1));
5001 __ jmp(&done);
5002 break;
5003 }
5004 case TypeCheckKind::kArrayCheck: {
5005 if (cls.IsRegister()) {
5006 __ cmpl(out, cls.AsRegister<CpuRegister>());
5007 } else {
5008 DCHECK(cls.IsStackSlot()) << cls;
5009 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5010 }
5011 DCHECK(locations->OnlyCallsOnSlowPath());
5012 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
5013 instruction, /* is_fatal */ false);
5014 codegen_->AddSlowPath(slow_path);
5015 __ j(kNotEqual, slow_path->GetEntryLabel());
5016 __ movl(out, Immediate(1));
5017 if (zero.IsLinked()) {
5018 __ jmp(&done);
5019 }
5020 break;
5021 }
Calin Juravle98893e12015-10-02 21:05:03 +01005022 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005023 case TypeCheckKind::kInterfaceCheck:
5024 default: {
5025 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5026 instruction,
5027 instruction->GetDexPc(),
5028 nullptr);
5029 if (zero.IsLinked()) {
5030 __ jmp(&done);
5031 }
5032 break;
5033 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005034 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005035
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005036 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005037 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005038 __ xorl(out, out);
5039 }
5040
5041 if (done.IsLinked()) {
5042 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005043 }
5044
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005045 if (slow_path != nullptr) {
5046 __ Bind(slow_path->GetExitLabel());
5047 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005048}
5049
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005050void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005051 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5052 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5053
5054 switch (instruction->GetTypeCheckKind()) {
5055 case TypeCheckKind::kExactCheck:
5056 case TypeCheckKind::kAbstractClassCheck:
5057 case TypeCheckKind::kClassHierarchyCheck:
5058 case TypeCheckKind::kArrayObjectCheck:
5059 call_kind = throws_into_catch
5060 ? LocationSummary::kCallOnSlowPath
5061 : LocationSummary::kNoCall;
5062 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005063 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005064 case TypeCheckKind::kInterfaceCheck:
5065 call_kind = LocationSummary::kCall;
5066 break;
5067 case TypeCheckKind::kArrayCheck:
5068 call_kind = LocationSummary::kCallOnSlowPath;
5069 break;
5070 }
5071
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005072 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005073 instruction, call_kind);
5074 if (call_kind != LocationSummary::kCall) {
5075 locations->SetInAt(0, Location::RequiresRegister());
5076 locations->SetInAt(1, Location::Any());
5077 // Note that TypeCheckSlowPathX86_64 uses this register too.
5078 locations->AddTemp(Location::RequiresRegister());
5079 } else {
5080 InvokeRuntimeCallingConvention calling_convention;
5081 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5082 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5083 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005084}
5085
5086void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
5087 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005088 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005089 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005090 CpuRegister temp = locations->WillCall()
5091 ? CpuRegister(kNoRegister)
5092 : locations->GetTemp(0).AsRegister<CpuRegister>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005093
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005094 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5095 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5096 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5097 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5098 SlowPathCode* slow_path = nullptr;
5099
5100 if (!locations->WillCall()) {
5101 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
5102 instruction, !locations->CanCall());
5103 codegen_->AddSlowPath(slow_path);
5104 }
5105
5106 NearLabel done;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005107 // Avoid null check if we know obj is not null.
5108 if (instruction->MustDoNullCheck()) {
5109 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005110 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005111 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005112
5113 if (locations->WillCall()) {
5114 __ movl(obj, Address(obj, class_offset));
5115 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005116 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005117 __ movl(temp, Address(obj, class_offset));
5118 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005119 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005120
5121 switch (instruction->GetTypeCheckKind()) {
5122 case TypeCheckKind::kExactCheck:
5123 case TypeCheckKind::kArrayCheck: {
5124 if (cls.IsRegister()) {
5125 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5126 } else {
5127 DCHECK(cls.IsStackSlot()) << cls;
5128 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5129 }
5130 // Jump to slow path for throwing the exception or doing a
5131 // more involved array check.
5132 __ j(kNotEqual, slow_path->GetEntryLabel());
5133 break;
5134 }
5135 case TypeCheckKind::kAbstractClassCheck: {
5136 // If the class is abstract, we eagerly fetch the super class of the
5137 // object to avoid doing a comparison we know will fail.
5138 NearLabel loop;
5139 __ Bind(&loop);
5140 __ movl(temp, Address(temp, super_offset));
5141 __ MaybeUnpoisonHeapReference(temp);
5142 __ testl(temp, temp);
5143 // Jump to the slow path to throw the exception.
5144 __ j(kEqual, slow_path->GetEntryLabel());
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 }
5151 __ j(kNotEqual, &loop);
5152 break;
5153 }
5154 case TypeCheckKind::kClassHierarchyCheck: {
5155 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005156 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005157 __ Bind(&loop);
5158 if (cls.IsRegister()) {
5159 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5160 } else {
5161 DCHECK(cls.IsStackSlot()) << cls;
5162 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5163 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005164 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005165 __ movl(temp, Address(temp, super_offset));
5166 __ MaybeUnpoisonHeapReference(temp);
5167 __ testl(temp, temp);
5168 __ j(kNotEqual, &loop);
5169 // Jump to the slow path to throw the exception.
5170 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005171 break;
5172 }
5173 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005174 // Do an exact check.
5175 if (cls.IsRegister()) {
5176 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5177 } else {
5178 DCHECK(cls.IsStackSlot()) << cls;
5179 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5180 }
5181 __ j(kEqual, &done);
5182 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005183 __ movl(temp, Address(temp, component_offset));
5184 __ MaybeUnpoisonHeapReference(temp);
5185 __ testl(temp, temp);
5186 __ j(kEqual, slow_path->GetEntryLabel());
5187 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5188 __ j(kNotEqual, slow_path->GetEntryLabel());
5189 break;
5190 }
Calin Juravle98893e12015-10-02 21:05:03 +01005191 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005192 case TypeCheckKind::kInterfaceCheck:
5193 default:
5194 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5195 instruction,
5196 instruction->GetDexPc(),
5197 nullptr);
5198 break;
5199 }
5200 __ Bind(&done);
5201
5202 if (slow_path != nullptr) {
5203 __ Bind(slow_path->GetExitLabel());
5204 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005205}
5206
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005207void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
5208 LocationSummary* locations =
5209 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5210 InvokeRuntimeCallingConvention calling_convention;
5211 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5212}
5213
5214void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005215 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5216 : QUICK_ENTRY_POINT(pUnlockObject),
5217 instruction,
5218 instruction->GetDexPc(),
5219 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005220}
5221
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005222void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5223void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5224void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5225
5226void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5227 LocationSummary* locations =
5228 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5229 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5230 || instruction->GetResultType() == Primitive::kPrimLong);
5231 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04005232 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005233 locations->SetOut(Location::SameAsFirstInput());
5234}
5235
5236void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
5237 HandleBitwiseOperation(instruction);
5238}
5239
5240void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
5241 HandleBitwiseOperation(instruction);
5242}
5243
5244void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
5245 HandleBitwiseOperation(instruction);
5246}
5247
5248void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5249 LocationSummary* locations = instruction->GetLocations();
5250 Location first = locations->InAt(0);
5251 Location second = locations->InAt(1);
5252 DCHECK(first.Equals(locations->Out()));
5253
5254 if (instruction->GetResultType() == Primitive::kPrimInt) {
5255 if (second.IsRegister()) {
5256 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005257 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005258 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005259 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005260 } else {
5261 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005262 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005263 }
5264 } else if (second.IsConstant()) {
5265 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
5266 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005267 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005268 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005269 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005270 } else {
5271 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005272 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005273 }
5274 } else {
5275 Address address(CpuRegister(RSP), second.GetStackIndex());
5276 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005277 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005278 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005279 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005280 } else {
5281 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005282 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005283 }
5284 }
5285 } else {
5286 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005287 CpuRegister first_reg = first.AsRegister<CpuRegister>();
5288 bool second_is_constant = false;
5289 int64_t value = 0;
5290 if (second.IsConstant()) {
5291 second_is_constant = true;
5292 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005293 }
Mark Mendell40741f32015-04-20 22:10:34 -04005294 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005295
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005296 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005297 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005298 if (is_int32_value) {
5299 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
5300 } else {
5301 __ andq(first_reg, codegen_->LiteralInt64Address(value));
5302 }
5303 } else if (second.IsDoubleStackSlot()) {
5304 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005305 } else {
5306 __ andq(first_reg, second.AsRegister<CpuRegister>());
5307 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005308 } else if (instruction->IsOr()) {
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 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
5312 } else {
5313 __ orq(first_reg, codegen_->LiteralInt64Address(value));
5314 }
5315 } else if (second.IsDoubleStackSlot()) {
5316 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005317 } else {
5318 __ orq(first_reg, second.AsRegister<CpuRegister>());
5319 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005320 } else {
5321 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005322 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005323 if (is_int32_value) {
5324 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
5325 } else {
5326 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
5327 }
5328 } else if (second.IsDoubleStackSlot()) {
5329 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005330 } else {
5331 __ xorq(first_reg, second.AsRegister<CpuRegister>());
5332 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005333 }
5334 }
5335}
5336
Calin Juravleb1498f62015-02-16 13:13:29 +00005337void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction) {
5338 // Nothing to do, this should be removed during prepare for register allocator.
5339 UNUSED(instruction);
5340 LOG(FATAL) << "Unreachable";
5341}
5342
5343void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction) {
5344 // Nothing to do, this should be removed during prepare for register allocator.
5345 UNUSED(instruction);
5346 LOG(FATAL) << "Unreachable";
5347}
5348
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005349void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
5350 DCHECK(codegen_->IsBaseline());
5351 LocationSummary* locations =
5352 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5353 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5354}
5355
5356void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5357 DCHECK(codegen_->IsBaseline());
5358 // Will be generated at use site.
5359}
5360
Mark Mendellfe57faa2015-09-18 09:26:15 -04005361// Simple implementation of packed switch - generate cascaded compare/jumps.
5362void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5363 LocationSummary* locations =
5364 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5365 locations->SetInAt(0, Location::RequiresRegister());
5366}
5367
5368void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5369 int32_t lower_bound = switch_instr->GetStartValue();
5370 int32_t num_entries = switch_instr->GetNumEntries();
5371 LocationSummary* locations = switch_instr->GetLocations();
5372 CpuRegister value_reg = locations->InAt(0).AsRegister<CpuRegister>();
5373 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5374
5375 // Create a series of compare/jumps.
5376 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5377 for (int i = 0; i < num_entries; i++) {
5378 int32_t case_value = lower_bound + i;
5379 if (case_value == 0) {
5380 __ testl(value_reg, value_reg);
5381 } else {
5382 __ cmpl(value_reg, Immediate(case_value));
5383 }
Vladimir Markoec7802a2015-10-01 20:57:57 +01005384 __ j(kEqual, codegen_->GetLabelOf(successors[i]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005385 }
5386
5387 // And the default for any other value.
5388 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5389 __ jmp(codegen_->GetLabelOf(default_block));
5390 }
5391}
5392
Mark Mendell92e83bf2015-05-07 11:25:03 -04005393void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
5394 if (value == 0) {
5395 __ xorl(dest, dest);
5396 } else if (value > 0 && IsInt<32>(value)) {
5397 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
5398 __ movl(dest, Immediate(static_cast<int32_t>(value)));
5399 } else {
5400 __ movq(dest, Immediate(value));
5401 }
5402}
5403
Mark Mendellcfa410b2015-05-25 16:02:44 -04005404void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
5405 DCHECK(dest.IsDoubleStackSlot());
5406 if (IsInt<32>(value)) {
5407 // Can move directly as an int32 constant.
5408 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
5409 Immediate(static_cast<int32_t>(value)));
5410 } else {
5411 Load64BitValue(CpuRegister(TMP), value);
5412 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
5413 }
5414}
5415
Mark Mendellf55c3e02015-03-26 21:07:46 -04005416void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
5417 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04005418 X86_64Assembler* assembler = GetAssembler();
5419 if (!assembler->IsConstantAreaEmpty()) {
Mark Mendellf55c3e02015-03-26 21:07:46 -04005420 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5421 // byte values. If used for vectors at a later time, this will need to be
5422 // updated to 16 bytes with the appropriate offset.
Mark Mendell39dcf552015-04-09 20:42:42 -04005423 assembler->Align(4, 0);
5424 constant_area_start_ = assembler->CodeSize();
5425 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04005426 }
5427
5428 // And finish up.
5429 CodeGenerator::Finalize(allocator);
5430}
5431
5432/**
5433 * Class to handle late fixup of offsets into constant area.
5434 */
Vladimir Marko5233f932015-09-29 19:01:15 +01005435class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendellf55c3e02015-03-26 21:07:46 -04005436 public:
Mark Mendell39dcf552015-04-09 20:42:42 -04005437 RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
Mark Mendellf55c3e02015-03-26 21:07:46 -04005438 : codegen_(codegen), offset_into_constant_area_(offset) {}
5439
5440 private:
5441 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5442 // Patch the correct offset for the instruction. We use the address of the
5443 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
5444 int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
5445 int relative_position = constant_offset - pos;
5446
5447 // Patch in the right value.
5448 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5449 }
5450
Mark Mendell39dcf552015-04-09 20:42:42 -04005451 const CodeGeneratorX86_64& codegen_;
Mark Mendellf55c3e02015-03-26 21:07:46 -04005452
5453 // Location in constant area that the fixup refers to.
5454 int offset_into_constant_area_;
5455};
5456
5457Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
5458 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5459 return Address::RIP(fixup);
5460}
5461
5462Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
5463 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5464 return Address::RIP(fixup);
5465}
5466
5467Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
5468 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5469 return Address::RIP(fixup);
5470}
5471
5472Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
5473 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5474 return Address::RIP(fixup);
5475}
5476
Andreas Gampe85b62f22015-09-09 13:15:38 -07005477// TODO: trg as memory.
5478void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5479 if (!trg.IsValid()) {
5480 DCHECK(type == Primitive::kPrimVoid);
5481 return;
5482 }
5483
5484 DCHECK_NE(type, Primitive::kPrimVoid);
5485
5486 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
5487 if (trg.Equals(return_loc)) {
5488 return;
5489 }
5490
5491 // Let the parallel move resolver take care of all of this.
5492 HParallelMove parallel_move(GetGraph()->GetArena());
5493 parallel_move.AddMove(return_loc, trg, type, nullptr);
5494 GetMoveResolver()->EmitNativeCode(&parallel_move);
5495}
5496
Roland Levillain4d027112015-07-01 15:41:14 +01005497#undef __
5498
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005499} // namespace x86_64
5500} // namespace art