blob: 8cb404787de23081e70968f9dab5434049262e52 [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
Roland Levillain0d5a2812015-11-13 10:07:31 +000037template<class MirrorType>
38class GcRoot;
39
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010040namespace x86_64 {
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 {
Roland Levillain0d5a2812015-11-13 10:07:31 +000058 CodeGeneratorX86_64* x86_64_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 }
Roland Levillain0d5a2812015-11-13 10:07:31 +000064 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
65 instruction_,
66 instruction_->GetDexPc(),
67 this);
Roland Levillain888d0672015-11-23 18:53:50 +000068 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069 }
70
Alexandre Rames8158f282015-08-07 10:26:17 +010071 bool IsFatal() const OVERRIDE { return true; }
72
Alexandre Rames9931f312015-06-19 14:47:01 +010073 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
74
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
78};
79
Andreas Gampe85b62f22015-09-09 13:15:38 -070080class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000081 public:
82 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
83
Alexandre Rames2ed20af2015-03-06 13:55:35 +000084 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +000085 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000086 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000087 if (instruction_->CanThrowIntoCatchBlock()) {
88 // Live registers will be restored in the catch block if caught.
89 SaveLiveRegisters(codegen, instruction_->GetLocations());
90 }
Roland Levillain0d5a2812015-11-13 10:07:31 +000091 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
92 instruction_,
93 instruction_->GetDexPc(),
94 this);
Roland Levillain888d0672015-11-23 18:53:50 +000095 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +000096 }
97
Alexandre Rames8158f282015-08-07 10:26:17 +010098 bool IsFatal() const OVERRIDE { return true; }
99
Alexandre Rames9931f312015-06-19 14:47:01 +0100100 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
101
Calin Juravled0d48522014-11-04 16:40:20 +0000102 private:
103 HDivZeroCheck* const instruction_;
104 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
105};
106
Andreas Gampe85b62f22015-09-09 13:15:38 -0700107class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000108 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100109 DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
Calin Juravlebacfec32014-11-14 15:54:36 +0000110 : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000111
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000112 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000113 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000114 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000115 if (is_div_) {
116 __ negl(cpu_reg_);
117 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400118 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000119 }
120
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000121 } else {
122 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000123 if (is_div_) {
124 __ negq(cpu_reg_);
125 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400126 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000127 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000128 }
Calin Juravled0d48522014-11-04 16:40:20 +0000129 __ jmp(GetExitLabel());
130 }
131
Alexandre Rames9931f312015-06-19 14:47:01 +0100132 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
133
Calin Juravled0d48522014-11-04 16:40:20 +0000134 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000135 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000136 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000137 const bool is_div_;
138 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000139};
140
Andreas Gampe85b62f22015-09-09 13:15:38 -0700141class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000142 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100143 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100144 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000145
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000146 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000147 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000149 SaveLiveRegisters(codegen, instruction_->GetLocations());
Roland Levillain0d5a2812015-11-13 10:07:31 +0000150 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
151 instruction_,
152 instruction_->GetDexPc(),
153 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000154 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000155 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100156 if (successor_ == nullptr) {
157 __ jmp(GetReturnLabel());
158 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000159 __ jmp(x86_64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100160 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000161 }
162
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100163 Label* GetReturnLabel() {
164 DCHECK(successor_ == nullptr);
165 return &return_label_;
166 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000167
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100168 HBasicBlock* GetSuccessor() const {
169 return successor_;
170 }
171
Alexandre Rames9931f312015-06-19 14:47:01 +0100172 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
173
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000174 private:
175 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100176 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000177 Label return_label_;
178
179 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
180};
181
Andreas Gampe85b62f22015-09-09 13:15:38 -0700182class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100184 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
185 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100186
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000187 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100188 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000189 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100190 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000191 if (instruction_->CanThrowIntoCatchBlock()) {
192 // Live registers will be restored in the catch block if caught.
193 SaveLiveRegisters(codegen, instruction_->GetLocations());
194 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000195 // We're moving two locations to locations that could overlap, so we need a parallel
196 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100197 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000198 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100199 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000200 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100201 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100202 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100203 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
204 Primitive::kPrimInt);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000205 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
206 instruction_,
207 instruction_->GetDexPc(),
208 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000209 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100210 }
211
Alexandre Rames8158f282015-08-07 10:26:17 +0100212 bool IsFatal() const OVERRIDE { return true; }
213
Alexandre Rames9931f312015-06-19 14:47:01 +0100214 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
215
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100216 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100217 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100218
219 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
220};
221
Andreas Gampe85b62f22015-09-09 13:15:38 -0700222class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100223 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224 LoadClassSlowPathX86_64(HLoadClass* cls,
225 HInstruction* at,
226 uint32_t dex_pc,
227 bool do_clinit)
228 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
229 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
230 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100231
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000232 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000233 LocationSummary* locations = at_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000234 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100236
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000237 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000238
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100239 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000240 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000241 x86_64_codegen->InvokeRuntime(do_clinit_ ?
242 QUICK_ENTRY_POINT(pInitializeStaticStorage) :
243 QUICK_ENTRY_POINT(pInitializeType),
244 at_,
245 dex_pc_,
246 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000247 if (do_clinit_) {
248 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
249 } else {
250 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
251 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100252
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000253 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000254 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000255 if (out.IsValid()) {
256 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000257 x86_64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000258 }
259
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000260 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100261 __ jmp(GetExitLabel());
262 }
263
Alexandre Rames9931f312015-06-19 14:47:01 +0100264 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
265
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100266 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000267 // The class this slow path will load.
268 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100269
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000270 // The instruction where this slow path is happening.
271 // (Might be the load class or an initialization check).
272 HInstruction* const at_;
273
274 // The dex PC of `at_`.
275 const uint32_t dex_pc_;
276
277 // Whether to initialize the class.
278 const bool do_clinit_;
279
280 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100281};
282
Andreas Gampe85b62f22015-09-09 13:15:38 -0700283class LoadStringSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000284 public:
285 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
286
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000287 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000288 LocationSummary* locations = instruction_->GetLocations();
289 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
290
Roland Levillain0d5a2812015-11-13 10:07:31 +0000291 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000292 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000293 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000294
295 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800296 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000297 Immediate(instruction_->GetStringIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000298 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
299 instruction_,
300 instruction_->GetDexPc(),
301 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000302 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000303 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000304 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000305 __ jmp(GetExitLabel());
306 }
307
Alexandre Rames9931f312015-06-19 14:47:01 +0100308 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
309
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000310 private:
311 HLoadString* const instruction_;
312
313 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
314};
315
Andreas Gampe85b62f22015-09-09 13:15:38 -0700316class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000317 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000318 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
319 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000320
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000321 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000322 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100323 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
324 : locations->Out();
325 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000326 DCHECK(instruction_->IsCheckCast()
327 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000328
Roland Levillain0d5a2812015-11-13 10:07:31 +0000329 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000330 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000331
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000332 if (!is_fatal_) {
333 SaveLiveRegisters(codegen, locations);
334 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000335
336 // We're moving two locations to locations that could overlap, so we need a parallel
337 // move resolver.
338 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000339 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100340 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000341 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100342 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100343 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100344 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
345 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000346
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000347 if (instruction_->IsInstanceOf()) {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000348 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
349 instruction_,
350 dex_pc,
351 this);
352 CheckEntrypointTypes<
353 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000354 } else {
355 DCHECK(instruction_->IsCheckCast());
Roland Levillain0d5a2812015-11-13 10:07:31 +0000356 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
357 instruction_,
358 dex_pc,
359 this);
360 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000361 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000362
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000363 if (!is_fatal_) {
364 if (instruction_->IsInstanceOf()) {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000365 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000366 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000367
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000368 RestoreLiveRegisters(codegen, locations);
369 __ jmp(GetExitLabel());
370 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000371 }
372
Alexandre Rames9931f312015-06-19 14:47:01 +0100373 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
374
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000375 bool IsFatal() const OVERRIDE { return is_fatal_; }
376
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000377 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000378 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000379 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000380
381 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
382};
383
Andreas Gampe85b62f22015-09-09 13:15:38 -0700384class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700385 public:
386 explicit DeoptimizationSlowPathX86_64(HInstruction* instruction)
387 : instruction_(instruction) {}
388
389 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000390 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700391 __ Bind(GetEntryLabel());
392 SaveLiveRegisters(codegen, instruction_->GetLocations());
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700393 DCHECK(instruction_->IsDeoptimize());
394 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000395 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
396 deoptimize,
397 deoptimize->GetDexPc(),
398 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000399 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700400 }
401
Alexandre Rames9931f312015-06-19 14:47:01 +0100402 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
403
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700404 private:
405 HInstruction* const instruction_;
406 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
407};
408
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100409class ArraySetSlowPathX86_64 : public SlowPathCode {
410 public:
411 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : instruction_(instruction) {}
412
413 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
414 LocationSummary* locations = instruction_->GetLocations();
415 __ Bind(GetEntryLabel());
416 SaveLiveRegisters(codegen, locations);
417
418 InvokeRuntimeCallingConvention calling_convention;
419 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
420 parallel_move.AddMove(
421 locations->InAt(0),
422 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
423 Primitive::kPrimNot,
424 nullptr);
425 parallel_move.AddMove(
426 locations->InAt(1),
427 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
428 Primitive::kPrimInt,
429 nullptr);
430 parallel_move.AddMove(
431 locations->InAt(2),
432 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
433 Primitive::kPrimNot,
434 nullptr);
435 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
436
Roland Levillain0d5a2812015-11-13 10:07:31 +0000437 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
438 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
439 instruction_,
440 instruction_->GetDexPc(),
441 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000442 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100443 RestoreLiveRegisters(codegen, locations);
444 __ jmp(GetExitLabel());
445 }
446
447 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86_64"; }
448
449 private:
450 HInstruction* const instruction_;
451
452 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
453};
454
Roland Levillain0d5a2812015-11-13 10:07:31 +0000455// Slow path generating a read barrier for a heap reference.
456class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
457 public:
458 ReadBarrierForHeapReferenceSlowPathX86_64(HInstruction* instruction,
459 Location out,
460 Location ref,
461 Location obj,
462 uint32_t offset,
463 Location index)
464 : instruction_(instruction),
465 out_(out),
466 ref_(ref),
467 obj_(obj),
468 offset_(offset),
469 index_(index) {
470 DCHECK(kEmitCompilerReadBarrier);
471 // If `obj` is equal to `out` or `ref`, it means the initial
472 // object has been overwritten by (or after) the heap object
473 // reference load to be instrumented, e.g.:
474 //
475 // __ movl(out, Address(out, offset));
476 // codegen_->GenerateReadBarrier(instruction, out_loc, out_loc, out_loc, offset);
477 //
478 // In that case, we have lost the information about the original
479 // object, and the emitted read barrier cannot work properly.
480 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
481 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
482}
483
484 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
485 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
486 LocationSummary* locations = instruction_->GetLocations();
487 CpuRegister reg_out = out_.AsRegister<CpuRegister>();
488 DCHECK(locations->CanCall());
489 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_;
490 DCHECK(!instruction_->IsInvoke() ||
491 (instruction_->IsInvokeStaticOrDirect() &&
492 instruction_->GetLocations()->Intrinsified()));
493
494 __ Bind(GetEntryLabel());
495 SaveLiveRegisters(codegen, locations);
496
497 // We may have to change the index's value, but as `index_` is a
498 // constant member (like other "inputs" of this slow path),
499 // introduce a copy of it, `index`.
500 Location index = index_;
501 if (index_.IsValid()) {
502 // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
503 if (instruction_->IsArrayGet()) {
504 // Compute real offset and store it in index_.
505 Register index_reg = index_.AsRegister<CpuRegister>().AsRegister();
506 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
507 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
508 // We are about to change the value of `index_reg` (see the
509 // calls to art::x86_64::X86_64Assembler::shll and
510 // art::x86_64::X86_64Assembler::AddImmediate below), but it
511 // has not been saved by the previous call to
512 // art::SlowPathCode::SaveLiveRegisters, as it is a
513 // callee-save register --
514 // art::SlowPathCode::SaveLiveRegisters does not consider
515 // callee-save registers, as it has been designed with the
516 // assumption that callee-save registers are supposed to be
517 // handled by the called function. So, as a callee-save
518 // register, `index_reg` _would_ eventually be saved onto
519 // the stack, but it would be too late: we would have
520 // changed its value earlier. Therefore, we manually save
521 // it here into another freely available register,
522 // `free_reg`, chosen of course among the caller-save
523 // registers (as a callee-save `free_reg` register would
524 // exhibit the same problem).
525 //
526 // Note we could have requested a temporary register from
527 // the register allocator instead; but we prefer not to, as
528 // this is a slow path, and we know we can find a
529 // caller-save register that is available.
530 Register free_reg = FindAvailableCallerSaveRegister(codegen).AsRegister();
531 __ movl(CpuRegister(free_reg), CpuRegister(index_reg));
532 index_reg = free_reg;
533 index = Location::RegisterLocation(index_reg);
534 } else {
535 // The initial register stored in `index_` has already been
536 // saved in the call to art::SlowPathCode::SaveLiveRegisters
537 // (as it is not a callee-save register), so we can freely
538 // use it.
539 }
540 // Shifting the index value contained in `index_reg` by the
541 // scale factor (2) cannot overflow in practice, as the
542 // runtime is unable to allocate object arrays with a size
543 // larger than 2^26 - 1 (that is, 2^28 - 4 bytes).
544 __ shll(CpuRegister(index_reg), Immediate(TIMES_4));
545 static_assert(
546 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
547 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
548 __ AddImmediate(CpuRegister(index_reg), Immediate(offset_));
549 } else {
550 DCHECK(instruction_->IsInvoke());
551 DCHECK(instruction_->GetLocations()->Intrinsified());
552 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
553 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
554 << instruction_->AsInvoke()->GetIntrinsic();
555 DCHECK_EQ(offset_, 0U);
556 DCHECK(index_.IsRegister());
557 }
558 }
559
560 // We're moving two or three locations to locations that could
561 // overlap, so we need a parallel move resolver.
562 InvokeRuntimeCallingConvention calling_convention;
563 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
564 parallel_move.AddMove(ref_,
565 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
566 Primitive::kPrimNot,
567 nullptr);
568 parallel_move.AddMove(obj_,
569 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
570 Primitive::kPrimNot,
571 nullptr);
572 if (index.IsValid()) {
573 parallel_move.AddMove(index,
574 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
575 Primitive::kPrimInt,
576 nullptr);
577 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
578 } else {
579 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
580 __ movl(CpuRegister(calling_convention.GetRegisterAt(2)), Immediate(offset_));
581 }
582 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
583 instruction_,
584 instruction_->GetDexPc(),
585 this);
586 CheckEntrypointTypes<
587 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
588 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
589
590 RestoreLiveRegisters(codegen, locations);
591 __ jmp(GetExitLabel());
592 }
593
594 const char* GetDescription() const OVERRIDE {
595 return "ReadBarrierForHeapReferenceSlowPathX86_64";
596 }
597
598 private:
599 CpuRegister FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
600 size_t ref = static_cast<int>(ref_.AsRegister<CpuRegister>().AsRegister());
601 size_t obj = static_cast<int>(obj_.AsRegister<CpuRegister>().AsRegister());
602 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
603 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
604 return static_cast<CpuRegister>(i);
605 }
606 }
607 // We shall never fail to find a free caller-save register, as
608 // there are more than two core caller-save registers on x86-64
609 // (meaning it is possible to find one which is different from
610 // `ref` and `obj`).
611 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
612 LOG(FATAL) << "Could not find a free caller-save register";
613 UNREACHABLE();
614 }
615
616 HInstruction* const instruction_;
617 const Location out_;
618 const Location ref_;
619 const Location obj_;
620 const uint32_t offset_;
621 // An additional location containing an index to an array.
622 // Only used for HArrayGet and the UnsafeGetObject &
623 // UnsafeGetObjectVolatile intrinsics.
624 const Location index_;
625
626 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86_64);
627};
628
629// Slow path generating a read barrier for a GC root.
630class ReadBarrierForRootSlowPathX86_64 : public SlowPathCode {
631 public:
632 ReadBarrierForRootSlowPathX86_64(HInstruction* instruction, Location out, Location root)
633 : instruction_(instruction), out_(out), root_(root) {}
634
635 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
636 LocationSummary* locations = instruction_->GetLocations();
637 DCHECK(locations->CanCall());
638 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
639 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString());
640
641 __ Bind(GetEntryLabel());
642 SaveLiveRegisters(codegen, locations);
643
644 InvokeRuntimeCallingConvention calling_convention;
645 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
646 x86_64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
647 x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
648 instruction_,
649 instruction_->GetDexPc(),
650 this);
651 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
652 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
653
654 RestoreLiveRegisters(codegen, locations);
655 __ jmp(GetExitLabel());
656 }
657
658 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathX86_64"; }
659
660 private:
661 HInstruction* const instruction_;
662 const Location out_;
663 const Location root_;
664
665 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86_64);
666};
667
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100668#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100669#define __ down_cast<X86_64Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100670
Roland Levillain4fa13f62015-07-06 18:11:54 +0100671inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700672 switch (cond) {
673 case kCondEQ: return kEqual;
674 case kCondNE: return kNotEqual;
675 case kCondLT: return kLess;
676 case kCondLE: return kLessEqual;
677 case kCondGT: return kGreater;
678 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700679 case kCondB: return kBelow;
680 case kCondBE: return kBelowEqual;
681 case kCondA: return kAbove;
682 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700683 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100684 LOG(FATAL) << "Unreachable";
685 UNREACHABLE();
686}
687
Aart Bike9f37602015-10-09 11:15:55 -0700688// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100689inline Condition X86_64FPCondition(IfCondition cond) {
690 switch (cond) {
691 case kCondEQ: return kEqual;
692 case kCondNE: return kNotEqual;
693 case kCondLT: return kBelow;
694 case kCondLE: return kBelowEqual;
695 case kCondGT: return kAbove;
696 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700697 default: break; // should not happen
Roland Levillain4fa13f62015-07-06 18:11:54 +0100698 };
699 LOG(FATAL) << "Unreachable";
700 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700701}
702
Vladimir Markodc151b22015-10-15 18:02:30 +0100703HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
704 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
705 MethodReference target_method ATTRIBUTE_UNUSED) {
706 switch (desired_dispatch_info.code_ptr_location) {
707 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
708 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
709 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
710 return HInvokeStaticOrDirect::DispatchInfo {
711 desired_dispatch_info.method_load_kind,
712 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
713 desired_dispatch_info.method_load_data,
714 0u
715 };
716 default:
717 return desired_dispatch_info;
718 }
719}
720
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800721void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
Nicolas Geoffray38207af2015-06-01 15:46:22 +0100722 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800723 // All registers are assumed to be correctly set up.
724
Vladimir Marko58155012015-08-19 12:49:41 +0000725 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
726 switch (invoke->GetMethodLoadKind()) {
727 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
728 // temp = thread->string_init_entrypoint
729 __ gs()->movl(temp.AsRegister<CpuRegister>(),
730 Address::Absolute(invoke->GetStringInitOffset(), true));
731 break;
732 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +0000733 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +0000734 break;
735 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
736 __ movq(temp.AsRegister<CpuRegister>(), Immediate(invoke->GetMethodAddress()));
737 break;
738 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
739 __ movl(temp.AsRegister<CpuRegister>(), Immediate(0)); // Placeholder.
740 method_patches_.emplace_back(invoke->GetTargetMethod());
741 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
742 break;
743 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000744 pc_relative_dex_cache_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
745 invoke->GetDexCacheArrayOffset());
Vladimir Marko58155012015-08-19 12:49:41 +0000746 __ movq(temp.AsRegister<CpuRegister>(),
747 Address::Absolute(kDummy32BitOffset, false /* no_rip */));
748 // Bind the label at the end of the "movl" insn.
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000749 __ Bind(&pc_relative_dex_cache_patches_.back().label);
Vladimir Marko58155012015-08-19 12:49:41 +0000750 break;
751 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +0000752 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +0000753 Register method_reg;
754 CpuRegister reg = temp.AsRegister<CpuRegister>();
755 if (current_method.IsRegister()) {
756 method_reg = current_method.AsRegister<Register>();
757 } else {
758 DCHECK(invoke->GetLocations()->Intrinsified());
759 DCHECK(!current_method.IsValid());
760 method_reg = reg.AsRegister();
761 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
762 }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000763 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +0100764 __ movq(reg,
765 Address(CpuRegister(method_reg),
766 ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +0000767 // temp = temp[index_in_cache]
768 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
769 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
770 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +0100771 }
Vladimir Marko58155012015-08-19 12:49:41 +0000772 }
773
774 switch (invoke->GetCodePtrLocation()) {
775 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
776 __ call(&frame_entry_label_);
777 break;
778 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
779 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
780 Label* label = &relative_call_patches_.back().label;
781 __ call(label); // Bind to the patch label, override at link time.
782 __ Bind(label); // Bind the label at the end of the "call" insn.
783 break;
784 }
785 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
786 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
Vladimir Markodc151b22015-10-15 18:02:30 +0100787 // Filtered out by GetSupportedInvokeStaticOrDirectDispatch().
788 LOG(FATAL) << "Unsupported";
789 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +0000790 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
791 // (callee_method + offset_of_quick_compiled_code)()
792 __ call(Address(callee_method.AsRegister<CpuRegister>(),
793 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
794 kX86_64WordSize).SizeValue()));
795 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000796 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800797
798 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800799}
800
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000801void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
802 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
803 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
804 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
805 LocationSummary* locations = invoke->GetLocations();
806 Location receiver = locations->InAt(0);
807 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000808 DCHECK(receiver.IsRegister());
Roland Levillain0d5a2812015-11-13 10:07:31 +0000809 // /* HeapReference<Class> */ temp = receiver->klass_
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000810 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
811 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000812 // Instead of simply (possibly) unpoisoning `temp` here, we should
813 // emit a read barrier for the previous class reference load.
814 // However this is not required in practice, as this is an
815 // intermediate/temporary reference and because the current
816 // concurrent copying collector keeps the from-space memory
817 // intact/accessible until the end of the marking phase (the
818 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000819 __ MaybeUnpoisonHeapReference(temp);
820 // temp = temp->GetMethodAt(method_offset);
821 __ movq(temp, Address(temp, method_offset));
822 // call temp->GetEntryPoint();
823 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
824 kX86_64WordSize).SizeValue()));
825}
826
Vladimir Marko58155012015-08-19 12:49:41 +0000827void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
828 DCHECK(linker_patches->empty());
829 size_t size =
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000830 method_patches_.size() +
831 relative_call_patches_.size() +
832 pc_relative_dex_cache_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +0000833 linker_patches->reserve(size);
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000834 // The label points to the end of the "movl" insn but the literal offset for method
835 // patch needs to point to the embedded constant which occupies the last 4 bytes.
836 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
Vladimir Marko58155012015-08-19 12:49:41 +0000837 for (const MethodPatchInfo<Label>& info : method_patches_) {
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000838 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000839 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
840 info.target_method.dex_file,
841 info.target_method.dex_method_index));
842 }
843 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000844 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000845 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
846 info.target_method.dex_file,
847 info.target_method.dex_method_index));
848 }
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000849 for (const PcRelativeDexCacheAccessInfo& info : pc_relative_dex_cache_patches_) {
850 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000851 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
852 &info.target_dex_file,
853 info.label.Position(),
854 info.element_offset));
855 }
856}
857
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100858void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100859 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100860}
861
862void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100863 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100864}
865
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100866size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
867 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
868 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100869}
870
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100871size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
872 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
873 return kX86_64WordSize;
874}
875
876size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
877 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
878 return kX86_64WordSize;
879}
880
881size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
882 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
883 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100884}
885
Calin Juravle175dc732015-08-25 15:42:32 +0100886void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
887 HInstruction* instruction,
888 uint32_t dex_pc,
889 SlowPathCode* slow_path) {
890 InvokeRuntime(GetThreadOffset<kX86_64WordSize>(entrypoint).Int32Value(),
891 instruction,
892 dex_pc,
893 slow_path);
894}
895
896void CodeGeneratorX86_64::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100897 HInstruction* instruction,
898 uint32_t dex_pc,
899 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100900 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100901 __ gs()->call(Address::Absolute(entry_point_offset, true));
Alexandre Rames8158f282015-08-07 10:26:17 +0100902 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100903}
904
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000905static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000906// Use a fake return address register to mimic Quick.
907static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400908CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000909 const X86_64InstructionSetFeatures& isa_features,
910 const CompilerOptions& compiler_options,
911 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000912 : CodeGenerator(graph,
913 kNumberOfCpuRegisters,
914 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000915 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000916 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
917 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000918 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000919 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
920 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100921 compiler_options,
922 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100923 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100924 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000925 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400926 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400927 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000928 constant_area_start_(0),
Vladimir Marko5233f932015-09-29 19:01:15 +0100929 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
930 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000931 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Mark Mendell9c86b482015-09-18 13:36:07 -0400932 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000933 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
934}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100935
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100936InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
937 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100938 : HGraphVisitor(graph),
939 assembler_(codegen->GetAssembler()),
940 codegen_(codegen) {}
941
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100942Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943 switch (type) {
944 case Primitive::kPrimLong:
945 case Primitive::kPrimByte:
946 case Primitive::kPrimBoolean:
947 case Primitive::kPrimChar:
948 case Primitive::kPrimShort:
949 case Primitive::kPrimInt:
950 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100951 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100952 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100953 }
954
955 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100956 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100957 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100958 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100959 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100960
961 case Primitive::kPrimVoid:
962 LOG(FATAL) << "Unreachable type " << type;
963 }
964
Roland Levillain0d5a2812015-11-13 10:07:31 +0000965 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100966}
967
Nicolas Geoffray98893962015-01-21 12:32:32 +0000968void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100969 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100970 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100971
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000972 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100973 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000974
Nicolas Geoffray98893962015-01-21 12:32:32 +0000975 if (is_baseline) {
976 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
977 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
978 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000979 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
980 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
981 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000982 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100983}
984
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100985static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100986 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100987}
David Srbecky9d8606d2015-04-12 09:35:32 +0100988
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100989static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100990 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100991}
992
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100993void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100994 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000995 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100996 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -0700997 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000998 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +0100999
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001000 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001001 __ testq(CpuRegister(RAX), Address(
1002 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001003 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001004 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +00001005
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001006 if (HasEmptyFrame()) {
1007 return;
1008 }
1009
Nicolas Geoffray98893962015-01-21 12:32:32 +00001010 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001011 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001012 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001013 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001014 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1015 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +00001016 }
1017 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001018
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001019 int adjust = GetFrameSize() - GetCoreSpillSize();
1020 __ subq(CpuRegister(RSP), Immediate(adjust));
1021 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001022 uint32_t xmm_spill_location = GetFpuSpillStart();
1023 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001024
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001025 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1026 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001027 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1028 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
1029 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001030 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001031 }
1032
Mathieu Chartiere401d142015-04-22 13:56:20 -07001033 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001034 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001035}
1036
1037void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001038 __ cfi().RememberState();
1039 if (!HasEmptyFrame()) {
1040 uint32_t xmm_spill_location = GetFpuSpillStart();
1041 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
1042 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1043 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1044 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1045 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
1046 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
1047 }
1048 }
1049
1050 int adjust = GetFrameSize() - GetCoreSpillSize();
1051 __ addq(CpuRegister(RSP), Immediate(adjust));
1052 __ cfi().AdjustCFAOffset(-adjust);
1053
1054 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1055 Register reg = kCoreCalleeSaves[i];
1056 if (allocated_registers_.ContainsCoreRegister(reg)) {
1057 __ popq(CpuRegister(reg));
1058 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1059 __ cfi().Restore(DWARFReg(reg));
1060 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001061 }
1062 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001063 __ ret();
1064 __ cfi().RestoreState();
1065 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001066}
1067
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001068void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
1069 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001070}
1071
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001072Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
1073 switch (load->GetType()) {
1074 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001075 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001076 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001077
1078 case Primitive::kPrimInt:
1079 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001080 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001081 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001082
1083 case Primitive::kPrimBoolean:
1084 case Primitive::kPrimByte:
1085 case Primitive::kPrimChar:
1086 case Primitive::kPrimShort:
1087 case Primitive::kPrimVoid:
1088 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -07001089 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001090 }
1091
1092 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -07001093 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001094}
1095
1096void CodeGeneratorX86_64::Move(Location destination, Location source) {
1097 if (source.Equals(destination)) {
1098 return;
1099 }
1100 if (destination.IsRegister()) {
1101 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001104 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001105 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001106 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001107 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001108 } else {
1109 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001110 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001111 Address(CpuRegister(RSP), source.GetStackIndex()));
1112 }
1113 } else if (destination.IsFpuRegister()) {
1114 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001115 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001116 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001117 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001118 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001119 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001120 Address(CpuRegister(RSP), source.GetStackIndex()));
1121 } else {
1122 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001123 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001124 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001125 }
1126 } else if (destination.IsStackSlot()) {
1127 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001128 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001129 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001130 } else if (source.IsFpuRegister()) {
1131 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001132 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001133 } else if (source.IsConstant()) {
1134 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001135 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001136 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001137 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001138 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001139 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1140 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001141 }
1142 } else {
1143 DCHECK(destination.IsDoubleStackSlot());
1144 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001145 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001146 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001147 } else if (source.IsFpuRegister()) {
1148 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001149 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001150 } else if (source.IsConstant()) {
1151 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +08001152 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001153 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +00001154 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001155 } else {
1156 DCHECK(constant->IsLongConstant());
1157 value = constant->AsLongConstant()->GetValue();
1158 }
Mark Mendellcfa410b2015-05-25 16:02:44 -04001159 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001160 } else {
1161 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001162 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1163 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001164 }
1165 }
1166}
1167
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001168void CodeGeneratorX86_64::Move(HInstruction* instruction,
1169 Location location,
1170 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001171 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001172 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -07001173 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001174 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001175 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001176 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001177 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001178 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
1179 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +00001180 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001181 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +00001182 } else if (location.IsStackSlot()) {
1183 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
1184 } else {
1185 DCHECK(location.IsConstant());
1186 DCHECK_EQ(location.GetConstant(), const_to_move);
1187 }
1188 } else if (const_to_move->IsLongConstant()) {
1189 int64_t value = const_to_move->AsLongConstant()->GetValue();
1190 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04001191 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001192 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -04001193 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001194 } else {
1195 DCHECK(location.IsConstant());
1196 DCHECK_EQ(location.GetConstant(), const_to_move);
1197 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001198 }
Roland Levillain476df552014-10-09 17:51:36 +01001199 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001200 switch (instruction->GetType()) {
1201 case Primitive::kPrimBoolean:
1202 case Primitive::kPrimByte:
1203 case Primitive::kPrimChar:
1204 case Primitive::kPrimShort:
1205 case Primitive::kPrimInt:
1206 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001207 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001208 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
1209 break;
1210
1211 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001212 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +00001213 Move(location,
1214 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001215 break;
1216
1217 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001218 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001219 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001220 } else if (instruction->IsTemporary()) {
1221 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
1222 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001223 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001224 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001225 switch (instruction->GetType()) {
1226 case Primitive::kPrimBoolean:
1227 case Primitive::kPrimByte:
1228 case Primitive::kPrimChar:
1229 case Primitive::kPrimShort:
1230 case Primitive::kPrimInt:
1231 case Primitive::kPrimNot:
1232 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001233 case Primitive::kPrimFloat:
1234 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +00001235 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001236 break;
1237
1238 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001239 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001240 }
1241 }
1242}
1243
Calin Juravle175dc732015-08-25 15:42:32 +01001244void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
1245 DCHECK(location.IsRegister());
1246 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
1247}
1248
Calin Juravlee460d1d2015-09-29 04:52:17 +01001249void CodeGeneratorX86_64::MoveLocation(
1250 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
1251 Move(dst, src);
1252}
1253
1254void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1255 if (location.IsRegister()) {
1256 locations->AddTemp(location);
1257 } else {
1258 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1259 }
1260}
1261
David Brazdilfc6a86a2015-06-26 10:33:45 +00001262void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001263 DCHECK(!successor->IsExitBlock());
1264
1265 HBasicBlock* block = got->GetBlock();
1266 HInstruction* previous = got->GetPrevious();
1267
1268 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001269 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001270 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1271 return;
1272 }
1273
1274 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1275 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1276 }
1277 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001278 __ jmp(codegen_->GetLabelOf(successor));
1279 }
1280}
1281
David Brazdilfc6a86a2015-06-26 10:33:45 +00001282void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1283 got->SetLocations(nullptr);
1284}
1285
1286void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1287 HandleGoto(got, got->GetSuccessor());
1288}
1289
1290void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1291 try_boundary->SetLocations(nullptr);
1292}
1293
1294void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1295 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1296 if (!successor->IsExitBlock()) {
1297 HandleGoto(try_boundary, successor);
1298 }
1299}
1300
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001301void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1302 exit->SetLocations(nullptr);
1303}
1304
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001305void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001306}
1307
Mark Mendellc4701932015-04-10 13:18:51 -04001308void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
1309 Label* true_label,
1310 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001311 if (cond->IsFPConditionTrueIfNaN()) {
1312 __ j(kUnordered, true_label);
1313 } else if (cond->IsFPConditionFalseIfNaN()) {
1314 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001315 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001316 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001317}
1318
David Brazdil0debae72015-11-12 18:37:00 +00001319void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
1320 Label* true_target_in,
1321 Label* false_target_in) {
1322 // Generated branching requires both targets to be explicit. If either of the
1323 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1324 Label fallthrough_target;
1325 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1326 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1327
Mark Mendellc4701932015-04-10 13:18:51 -04001328 LocationSummary* locations = condition->GetLocations();
1329 Location left = locations->InAt(0);
1330 Location right = locations->InAt(1);
1331
Mark Mendellc4701932015-04-10 13:18:51 -04001332 Primitive::Type type = condition->InputAt(0)->GetType();
1333 switch (type) {
1334 case Primitive::kPrimLong: {
1335 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1336 if (right.IsConstant()) {
1337 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1338 if (IsInt<32>(value)) {
1339 if (value == 0) {
1340 __ testq(left_reg, left_reg);
1341 } else {
1342 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1343 }
1344 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001345 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -04001346 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
1347 }
1348 } else if (right.IsDoubleStackSlot()) {
1349 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1350 } else {
1351 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1352 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001353 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -04001354 break;
1355 }
1356 case Primitive::kPrimFloat: {
1357 if (right.IsFpuRegister()) {
1358 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1359 } else if (right.IsConstant()) {
1360 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1361 codegen_->LiteralFloatAddress(
1362 right.GetConstant()->AsFloatConstant()->GetValue()));
1363 } else {
1364 DCHECK(right.IsStackSlot());
1365 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1366 Address(CpuRegister(RSP), right.GetStackIndex()));
1367 }
1368 GenerateFPJumps(condition, true_target, false_target);
1369 break;
1370 }
1371 case Primitive::kPrimDouble: {
1372 if (right.IsFpuRegister()) {
1373 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1374 } else if (right.IsConstant()) {
1375 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1376 codegen_->LiteralDoubleAddress(
1377 right.GetConstant()->AsDoubleConstant()->GetValue()));
1378 } else {
1379 DCHECK(right.IsDoubleStackSlot());
1380 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1381 Address(CpuRegister(RSP), right.GetStackIndex()));
1382 }
1383 GenerateFPJumps(condition, true_target, false_target);
1384 break;
1385 }
1386 default:
1387 LOG(FATAL) << "Unexpected condition type " << type;
1388 }
1389
David Brazdil0debae72015-11-12 18:37:00 +00001390 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001391 __ jmp(false_target);
1392 }
David Brazdil0debae72015-11-12 18:37:00 +00001393
1394 if (fallthrough_target.IsLinked()) {
1395 __ Bind(&fallthrough_target);
1396 }
Mark Mendellc4701932015-04-10 13:18:51 -04001397}
1398
David Brazdil0debae72015-11-12 18:37:00 +00001399static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1400 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1401 // are set only strictly before `branch`. We can't use the eflags on long
1402 // conditions if they are materialized due to the complex branching.
1403 return cond->IsCondition() &&
1404 cond->GetNext() == branch &&
1405 !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
1406}
1407
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001408void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001409 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001410 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001411 Label* false_target) {
1412 HInstruction* cond = instruction->InputAt(condition_input_index);
1413
1414 if (true_target == nullptr && false_target == nullptr) {
1415 // Nothing to do. The code always falls through.
1416 return;
1417 } else if (cond->IsIntConstant()) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001418 // Constant condition, statically compared against 1.
David Brazdil0debae72015-11-12 18:37:00 +00001419 if (cond->AsIntConstant()->IsOne()) {
1420 if (true_target != nullptr) {
1421 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001422 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001423 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001424 DCHECK(cond->AsIntConstant()->IsZero());
1425 if (false_target != nullptr) {
1426 __ jmp(false_target);
1427 }
1428 }
1429 return;
1430 }
1431
1432 // The following code generates these patterns:
1433 // (1) true_target == nullptr && false_target != nullptr
1434 // - opposite condition true => branch to false_target
1435 // (2) true_target != nullptr && false_target == nullptr
1436 // - condition true => branch to true_target
1437 // (3) true_target != nullptr && false_target != nullptr
1438 // - condition true => branch to true_target
1439 // - branch to false_target
1440 if (IsBooleanValueOrMaterializedCondition(cond)) {
1441 if (AreEflagsSetFrom(cond, instruction)) {
1442 if (true_target == nullptr) {
1443 __ j(X86_64IntegerCondition(cond->AsCondition()->GetOppositeCondition()), false_target);
1444 } else {
1445 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
1446 }
1447 } else {
1448 // Materialized condition, compare against 0.
1449 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
1450 if (lhs.IsRegister()) {
1451 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1452 } else {
1453 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
1454 }
1455 if (true_target == nullptr) {
1456 __ j(kEqual, false_target);
1457 } else {
1458 __ j(kNotEqual, true_target);
1459 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001460 }
1461 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001462 // Condition has not been materialized, use its inputs as the
1463 // comparison and its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001464 HCondition* condition = cond->AsCondition();
Mark Mendellc4701932015-04-10 13:18:51 -04001465
David Brazdil0debae72015-11-12 18:37:00 +00001466 // If this is a long or FP comparison that has been folded into
1467 // the HCondition, generate the comparison directly.
1468 Primitive::Type type = condition->InputAt(0)->GetType();
1469 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1470 GenerateCompareTestAndBranch(condition, true_target, false_target);
1471 return;
1472 }
1473
1474 Location lhs = condition->GetLocations()->InAt(0);
1475 Location rhs = condition->GetLocations()->InAt(1);
1476 if (rhs.IsRegister()) {
1477 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1478 } else if (rhs.IsConstant()) {
1479 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1480 if (constant == 0) {
1481 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001482 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001483 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001484 }
1485 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001486 __ cmpl(lhs.AsRegister<CpuRegister>(),
1487 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1488 }
1489 if (true_target == nullptr) {
1490 __ j(X86_64IntegerCondition(condition->GetOppositeCondition()), false_target);
1491 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001492 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001493 }
Dave Allison20dfc792014-06-16 20:44:29 -07001494 }
David Brazdil0debae72015-11-12 18:37:00 +00001495
1496 // If neither branch falls through (case 3), the conditional branch to `true_target`
1497 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1498 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001499 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001500 }
1501}
1502
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001503void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001504 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1505 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001506 locations->SetInAt(0, Location::Any());
1507 }
1508}
1509
1510void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001511 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1512 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1513 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1514 nullptr : codegen_->GetLabelOf(true_successor);
1515 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1516 nullptr : codegen_->GetLabelOf(false_successor);
1517 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001518}
1519
1520void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1521 LocationSummary* locations = new (GetGraph()->GetArena())
1522 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001523 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001524 locations->SetInAt(0, Location::Any());
1525 }
1526}
1527
1528void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001529 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001530 DeoptimizationSlowPathX86_64(deoptimize);
1531 codegen_->AddSlowPath(slow_path);
David Brazdil0debae72015-11-12 18:37:00 +00001532 GenerateTestAndBranch(deoptimize,
1533 /* condition_input_index */ 0,
1534 slow_path->GetEntryLabel(),
1535 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001536}
1537
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001538void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1539 local->SetLocations(nullptr);
1540}
1541
1542void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1543 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1544}
1545
1546void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1547 local->SetLocations(nullptr);
1548}
1549
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001550void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001551 // Nothing to do, this is driven by the code generator.
1552}
1553
1554void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001555 LocationSummary* locations =
1556 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001557 switch (store->InputAt(1)->GetType()) {
1558 case Primitive::kPrimBoolean:
1559 case Primitive::kPrimByte:
1560 case Primitive::kPrimChar:
1561 case Primitive::kPrimShort:
1562 case Primitive::kPrimInt:
1563 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001564 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001565 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1566 break;
1567
1568 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001569 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001570 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1571 break;
1572
1573 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001574 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001575 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001576}
1577
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001578void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001579}
1580
Roland Levillain0d37cd02015-05-27 16:39:19 +01001581void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001582 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001583 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001584 // Handle the long/FP comparisons made in instruction simplification.
1585 switch (cond->InputAt(0)->GetType()) {
1586 case Primitive::kPrimLong:
1587 locations->SetInAt(0, Location::RequiresRegister());
1588 locations->SetInAt(1, Location::Any());
1589 break;
1590 case Primitive::kPrimFloat:
1591 case Primitive::kPrimDouble:
1592 locations->SetInAt(0, Location::RequiresFpuRegister());
1593 locations->SetInAt(1, Location::Any());
1594 break;
1595 default:
1596 locations->SetInAt(0, Location::RequiresRegister());
1597 locations->SetInAt(1, Location::Any());
1598 break;
1599 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001600 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001601 locations->SetOut(Location::RequiresRegister());
1602 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001603}
1604
Roland Levillain0d37cd02015-05-27 16:39:19 +01001605void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001606 if (!cond->NeedsMaterialization()) {
1607 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001608 }
Mark Mendellc4701932015-04-10 13:18:51 -04001609
1610 LocationSummary* locations = cond->GetLocations();
1611 Location lhs = locations->InAt(0);
1612 Location rhs = locations->InAt(1);
1613 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1614 Label true_label, false_label;
1615
1616 switch (cond->InputAt(0)->GetType()) {
1617 default:
1618 // Integer case.
1619
1620 // Clear output register: setcc only sets the low byte.
1621 __ xorl(reg, reg);
1622
1623 if (rhs.IsRegister()) {
1624 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1625 } else if (rhs.IsConstant()) {
1626 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1627 if (constant == 0) {
1628 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1629 } else {
1630 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1631 }
1632 } else {
1633 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1634 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001635 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001636 return;
1637 case Primitive::kPrimLong:
1638 // Clear output register: setcc only sets the low byte.
1639 __ xorl(reg, reg);
1640
1641 if (rhs.IsRegister()) {
1642 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1643 } else if (rhs.IsConstant()) {
1644 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1645 if (IsInt<32>(value)) {
1646 if (value == 0) {
1647 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1648 } else {
1649 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1650 }
1651 } else {
1652 // Value won't fit in an int.
1653 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1654 }
1655 } else {
1656 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1657 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001658 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001659 return;
1660 case Primitive::kPrimFloat: {
1661 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1662 if (rhs.IsConstant()) {
1663 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1664 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1665 } else if (rhs.IsStackSlot()) {
1666 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1667 } else {
1668 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1669 }
1670 GenerateFPJumps(cond, &true_label, &false_label);
1671 break;
1672 }
1673 case Primitive::kPrimDouble: {
1674 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1675 if (rhs.IsConstant()) {
1676 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1677 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1678 } else if (rhs.IsDoubleStackSlot()) {
1679 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1680 } else {
1681 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1682 }
1683 GenerateFPJumps(cond, &true_label, &false_label);
1684 break;
1685 }
1686 }
1687
1688 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001689 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001690
Roland Levillain4fa13f62015-07-06 18:11:54 +01001691 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001692 __ Bind(&false_label);
1693 __ xorl(reg, reg);
1694 __ jmp(&done_label);
1695
Roland Levillain4fa13f62015-07-06 18:11:54 +01001696 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001697 __ Bind(&true_label);
1698 __ movl(reg, Immediate(1));
1699 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001700}
1701
1702void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1703 VisitCondition(comp);
1704}
1705
1706void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1707 VisitCondition(comp);
1708}
1709
1710void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1711 VisitCondition(comp);
1712}
1713
1714void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1715 VisitCondition(comp);
1716}
1717
1718void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1719 VisitCondition(comp);
1720}
1721
1722void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1723 VisitCondition(comp);
1724}
1725
1726void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1727 VisitCondition(comp);
1728}
1729
1730void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1731 VisitCondition(comp);
1732}
1733
1734void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1735 VisitCondition(comp);
1736}
1737
1738void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1739 VisitCondition(comp);
1740}
1741
1742void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1743 VisitCondition(comp);
1744}
1745
1746void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1747 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001748}
1749
Aart Bike9f37602015-10-09 11:15:55 -07001750void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
1751 VisitCondition(comp);
1752}
1753
1754void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
1755 VisitCondition(comp);
1756}
1757
1758void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1759 VisitCondition(comp);
1760}
1761
1762void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1763 VisitCondition(comp);
1764}
1765
1766void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
1767 VisitCondition(comp);
1768}
1769
1770void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
1771 VisitCondition(comp);
1772}
1773
1774void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1775 VisitCondition(comp);
1776}
1777
1778void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1779 VisitCondition(comp);
1780}
1781
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001782void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001783 LocationSummary* locations =
1784 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001785 switch (compare->InputAt(0)->GetType()) {
1786 case Primitive::kPrimLong: {
1787 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001788 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001789 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1790 break;
1791 }
1792 case Primitive::kPrimFloat:
1793 case Primitive::kPrimDouble: {
1794 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001795 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001796 locations->SetOut(Location::RequiresRegister());
1797 break;
1798 }
1799 default:
1800 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1801 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001802}
1803
1804void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001805 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001806 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001807 Location left = locations->InAt(0);
1808 Location right = locations->InAt(1);
1809
Mark Mendell0c9497d2015-08-21 09:30:05 -04001810 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00001811 Primitive::Type type = compare->InputAt(0)->GetType();
1812 switch (type) {
1813 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001814 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1815 if (right.IsConstant()) {
1816 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001817 if (IsInt<32>(value)) {
1818 if (value == 0) {
1819 __ testq(left_reg, left_reg);
1820 } else {
1821 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1822 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001823 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001824 // Value won't fit in an int.
1825 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001826 }
Mark Mendell40741f32015-04-20 22:10:34 -04001827 } else if (right.IsDoubleStackSlot()) {
1828 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001829 } else {
1830 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1831 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001832 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001833 }
1834 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001835 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1836 if (right.IsConstant()) {
1837 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1838 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1839 } else if (right.IsStackSlot()) {
1840 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1841 } else {
1842 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1843 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001844 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1845 break;
1846 }
1847 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001848 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1849 if (right.IsConstant()) {
1850 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1851 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1852 } else if (right.IsDoubleStackSlot()) {
1853 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1854 } else {
1855 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1856 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001857 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1858 break;
1859 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001860 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001861 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001862 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001863 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001864 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001865 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001866
Calin Juravle91debbc2014-11-26 19:01:09 +00001867 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001868 __ movl(out, Immediate(1));
1869 __ jmp(&done);
1870
1871 __ Bind(&less);
1872 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001873
1874 __ Bind(&done);
1875}
1876
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001877void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001878 LocationSummary* locations =
1879 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001880 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001881}
1882
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001883void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001884 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001885}
1886
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001887void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1888 LocationSummary* locations =
1889 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1890 locations->SetOut(Location::ConstantLocation(constant));
1891}
1892
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001893void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001894 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001895}
1896
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001897void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001898 LocationSummary* locations =
1899 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001900 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001901}
1902
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001903void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001904 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001905}
1906
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001907void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1908 LocationSummary* locations =
1909 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1910 locations->SetOut(Location::ConstantLocation(constant));
1911}
1912
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001913void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001914 // Will be generated at use site.
1915}
1916
1917void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1918 LocationSummary* locations =
1919 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1920 locations->SetOut(Location::ConstantLocation(constant));
1921}
1922
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001923void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
1924 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001925 // Will be generated at use site.
1926}
1927
Calin Juravle27df7582015-04-17 19:12:31 +01001928void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1929 memory_barrier->SetLocations(nullptr);
1930}
1931
1932void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1933 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1934}
1935
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001936void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1937 ret->SetLocations(nullptr);
1938}
1939
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001940void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001941 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001942}
1943
1944void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001945 LocationSummary* locations =
1946 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001947 switch (ret->InputAt(0)->GetType()) {
1948 case Primitive::kPrimBoolean:
1949 case Primitive::kPrimByte:
1950 case Primitive::kPrimChar:
1951 case Primitive::kPrimShort:
1952 case Primitive::kPrimInt:
1953 case Primitive::kPrimNot:
1954 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001955 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001956 break;
1957
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001958 case Primitive::kPrimFloat:
1959 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001960 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001961 break;
1962
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001963 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001964 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001965 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001966}
1967
1968void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1969 if (kIsDebugBuild) {
1970 switch (ret->InputAt(0)->GetType()) {
1971 case Primitive::kPrimBoolean:
1972 case Primitive::kPrimByte:
1973 case Primitive::kPrimChar:
1974 case Primitive::kPrimShort:
1975 case Primitive::kPrimInt:
1976 case Primitive::kPrimNot:
1977 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001978 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001979 break;
1980
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001981 case Primitive::kPrimFloat:
1982 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001983 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001984 XMM0);
1985 break;
1986
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001987 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001988 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001989 }
1990 }
1991 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001992}
1993
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001994Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
1995 switch (type) {
1996 case Primitive::kPrimBoolean:
1997 case Primitive::kPrimByte:
1998 case Primitive::kPrimChar:
1999 case Primitive::kPrimShort:
2000 case Primitive::kPrimInt:
2001 case Primitive::kPrimNot:
2002 case Primitive::kPrimLong:
2003 return Location::RegisterLocation(RAX);
2004
2005 case Primitive::kPrimVoid:
2006 return Location::NoLocation();
2007
2008 case Primitive::kPrimDouble:
2009 case Primitive::kPrimFloat:
2010 return Location::FpuRegisterLocation(XMM0);
2011 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002012
2013 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002014}
2015
2016Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
2017 return Location::RegisterLocation(kMethodRegisterArgument);
2018}
2019
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002020Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002021 switch (type) {
2022 case Primitive::kPrimBoolean:
2023 case Primitive::kPrimByte:
2024 case Primitive::kPrimChar:
2025 case Primitive::kPrimShort:
2026 case Primitive::kPrimInt:
2027 case Primitive::kPrimNot: {
2028 uint32_t index = gp_index_++;
2029 stack_index_++;
2030 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002031 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002032 } else {
2033 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2034 }
2035 }
2036
2037 case Primitive::kPrimLong: {
2038 uint32_t index = gp_index_;
2039 stack_index_ += 2;
2040 if (index < calling_convention.GetNumberOfRegisters()) {
2041 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002042 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002043 } else {
2044 gp_index_ += 2;
2045 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2046 }
2047 }
2048
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002049 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002050 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002051 stack_index_++;
2052 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002053 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002054 } else {
2055 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2056 }
2057 }
2058
2059 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002060 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002061 stack_index_ += 2;
2062 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002063 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002064 } else {
2065 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2066 }
2067 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002068
2069 case Primitive::kPrimVoid:
2070 LOG(FATAL) << "Unexpected parameter type " << type;
2071 break;
2072 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00002073 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002074}
2075
Calin Juravle175dc732015-08-25 15:42:32 +01002076void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2077 // The trampoline uses the same calling convention as dex calling conventions,
2078 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2079 // the method_idx.
2080 HandleInvoke(invoke);
2081}
2082
2083void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2084 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2085}
2086
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002087void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01002088 // When we do not run baseline, explicit clinit checks triggered by static
2089 // invokes must have been pruned by art::PrepareForRegisterAllocation.
2090 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002091
Mark Mendellfb8d2792015-03-31 22:16:59 -04002092 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002093 if (intrinsic.TryDispatch(invoke)) {
2094 return;
2095 }
2096
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002097 HandleInvoke(invoke);
2098}
2099
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002100static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
2101 if (invoke->GetLocations()->Intrinsified()) {
2102 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
2103 intrinsic.Dispatch(invoke);
2104 return true;
2105 }
2106 return false;
2107}
2108
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002109void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01002110 // When we do not run baseline, explicit clinit checks triggered by static
2111 // invokes must have been pruned by art::PrepareForRegisterAllocation.
2112 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002113
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002114 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2115 return;
2116 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002117
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002118 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002119 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002120 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00002121 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002122}
2123
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002124void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002125 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002126 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002127}
2128
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002129void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04002130 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002131 if (intrinsic.TryDispatch(invoke)) {
2132 return;
2133 }
2134
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002135 HandleInvoke(invoke);
2136}
2137
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002138void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002139 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2140 return;
2141 }
2142
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002143 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002144 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002145 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002146}
2147
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002148void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2149 HandleInvoke(invoke);
2150 // Add the hidden argument.
2151 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
2152}
2153
2154void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2155 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002156 LocationSummary* locations = invoke->GetLocations();
2157 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2158 CpuRegister hidden_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07002159 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
2160 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002161 Location receiver = locations->InAt(0);
2162 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
2163
Roland Levillain0d5a2812015-11-13 10:07:31 +00002164 // Set the hidden argument. This is safe to do this here, as RAX
2165 // won't be modified thereafter, before the `call` instruction.
2166 DCHECK_EQ(RAX, hidden_reg.AsRegister());
Mark Mendell92e83bf2015-05-07 11:25:03 -04002167 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002168
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002169 if (receiver.IsStackSlot()) {
2170 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002171 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002172 __ movl(temp, Address(temp, class_offset));
2173 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002174 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002175 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002176 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002177 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002178 // Instead of simply (possibly) unpoisoning `temp` here, we should
2179 // emit a read barrier for the previous class reference load.
2180 // However this is not required in practice, as this is an
2181 // intermediate/temporary reference and because the current
2182 // concurrent copying collector keeps the from-space memory
2183 // intact/accessible until the end of the marking phase (the
2184 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002185 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002186 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002187 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002188 // call temp->GetEntryPoint();
Roland Levillain0d5a2812015-11-13 10:07:31 +00002189 __ call(Address(temp,
2190 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002191
2192 DCHECK(!codegen_->IsLeafMethod());
2193 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2194}
2195
Roland Levillain88cb1752014-10-20 16:36:47 +01002196void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
2197 LocationSummary* locations =
2198 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2199 switch (neg->GetResultType()) {
2200 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002201 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01002202 locations->SetInAt(0, Location::RequiresRegister());
2203 locations->SetOut(Location::SameAsFirstInput());
2204 break;
2205
Roland Levillain88cb1752014-10-20 16:36:47 +01002206 case Primitive::kPrimFloat:
2207 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002208 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002209 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00002210 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002211 break;
2212
2213 default:
2214 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2215 }
2216}
2217
2218void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
2219 LocationSummary* locations = neg->GetLocations();
2220 Location out = locations->Out();
2221 Location in = locations->InAt(0);
2222 switch (neg->GetResultType()) {
2223 case Primitive::kPrimInt:
2224 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002225 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002226 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002227 break;
2228
2229 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002230 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002231 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002232 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002233 break;
2234
Roland Levillain5368c212014-11-27 15:03:41 +00002235 case Primitive::kPrimFloat: {
2236 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002237 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002238 // Implement float negation with an exclusive or with value
2239 // 0x80000000 (mask for bit 31, representing the sign of a
2240 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002241 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002242 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002243 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002244 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002245
Roland Levillain5368c212014-11-27 15:03:41 +00002246 case Primitive::kPrimDouble: {
2247 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002248 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002249 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00002250 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00002251 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002252 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002253 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002254 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002255 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002256
2257 default:
2258 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2259 }
2260}
2261
Roland Levillaindff1f282014-11-05 14:15:05 +00002262void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2263 LocationSummary* locations =
2264 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2265 Primitive::Type result_type = conversion->GetResultType();
2266 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002267 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00002268
David Brazdilb2bd1c52015-03-25 11:17:37 +00002269 // The Java language does not allow treating boolean as an integral type but
2270 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002271
Roland Levillaindff1f282014-11-05 14:15:05 +00002272 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002273 case Primitive::kPrimByte:
2274 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002275 case Primitive::kPrimBoolean:
2276 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002277 case Primitive::kPrimShort:
2278 case Primitive::kPrimInt:
2279 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002280 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002281 locations->SetInAt(0, Location::Any());
2282 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2283 break;
2284
2285 default:
2286 LOG(FATAL) << "Unexpected type conversion from " << input_type
2287 << " to " << result_type;
2288 }
2289 break;
2290
Roland Levillain01a8d712014-11-14 16:27:39 +00002291 case Primitive::kPrimShort:
2292 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002293 case Primitive::kPrimBoolean:
2294 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002295 case Primitive::kPrimByte:
2296 case Primitive::kPrimInt:
2297 case Primitive::kPrimChar:
2298 // Processing a Dex `int-to-short' instruction.
2299 locations->SetInAt(0, Location::Any());
2300 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2301 break;
2302
2303 default:
2304 LOG(FATAL) << "Unexpected type conversion from " << input_type
2305 << " to " << result_type;
2306 }
2307 break;
2308
Roland Levillain946e1432014-11-11 17:35:19 +00002309 case Primitive::kPrimInt:
2310 switch (input_type) {
2311 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002312 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002313 locations->SetInAt(0, Location::Any());
2314 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2315 break;
2316
2317 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002318 // Processing a Dex `float-to-int' instruction.
2319 locations->SetInAt(0, Location::RequiresFpuRegister());
2320 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002321 break;
2322
Roland Levillain946e1432014-11-11 17:35:19 +00002323 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002324 // Processing a Dex `double-to-int' instruction.
2325 locations->SetInAt(0, Location::RequiresFpuRegister());
2326 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002327 break;
2328
2329 default:
2330 LOG(FATAL) << "Unexpected type conversion from " << input_type
2331 << " to " << result_type;
2332 }
2333 break;
2334
Roland Levillaindff1f282014-11-05 14:15:05 +00002335 case Primitive::kPrimLong:
2336 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002337 case Primitive::kPrimBoolean:
2338 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002339 case Primitive::kPrimByte:
2340 case Primitive::kPrimShort:
2341 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002342 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002343 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002344 // TODO: We would benefit from a (to-be-implemented)
2345 // Location::RegisterOrStackSlot requirement for this input.
2346 locations->SetInAt(0, Location::RequiresRegister());
2347 locations->SetOut(Location::RequiresRegister());
2348 break;
2349
2350 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002351 // Processing a Dex `float-to-long' instruction.
2352 locations->SetInAt(0, Location::RequiresFpuRegister());
2353 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002354 break;
2355
Roland Levillaindff1f282014-11-05 14:15:05 +00002356 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002357 // Processing a Dex `double-to-long' instruction.
2358 locations->SetInAt(0, Location::RequiresFpuRegister());
2359 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002360 break;
2361
2362 default:
2363 LOG(FATAL) << "Unexpected type conversion from " << input_type
2364 << " to " << result_type;
2365 }
2366 break;
2367
Roland Levillain981e4542014-11-14 11:47:14 +00002368 case Primitive::kPrimChar:
2369 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002370 case Primitive::kPrimBoolean:
2371 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002372 case Primitive::kPrimByte:
2373 case Primitive::kPrimShort:
2374 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002375 // Processing a Dex `int-to-char' instruction.
2376 locations->SetInAt(0, Location::Any());
2377 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2378 break;
2379
2380 default:
2381 LOG(FATAL) << "Unexpected type conversion from " << input_type
2382 << " to " << result_type;
2383 }
2384 break;
2385
Roland Levillaindff1f282014-11-05 14:15:05 +00002386 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002387 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002388 case Primitive::kPrimBoolean:
2389 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002390 case Primitive::kPrimByte:
2391 case Primitive::kPrimShort:
2392 case Primitive::kPrimInt:
2393 case Primitive::kPrimChar:
2394 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002395 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002396 locations->SetOut(Location::RequiresFpuRegister());
2397 break;
2398
2399 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002400 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002401 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002402 locations->SetOut(Location::RequiresFpuRegister());
2403 break;
2404
Roland Levillaincff13742014-11-17 14:32:17 +00002405 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002406 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002407 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002408 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002409 break;
2410
2411 default:
2412 LOG(FATAL) << "Unexpected type conversion from " << input_type
2413 << " to " << result_type;
2414 };
2415 break;
2416
Roland Levillaindff1f282014-11-05 14:15:05 +00002417 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002418 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002419 case Primitive::kPrimBoolean:
2420 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002421 case Primitive::kPrimByte:
2422 case Primitive::kPrimShort:
2423 case Primitive::kPrimInt:
2424 case Primitive::kPrimChar:
2425 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002426 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002427 locations->SetOut(Location::RequiresFpuRegister());
2428 break;
2429
2430 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002431 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002432 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002433 locations->SetOut(Location::RequiresFpuRegister());
2434 break;
2435
Roland Levillaincff13742014-11-17 14:32:17 +00002436 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002437 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002438 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002439 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002440 break;
2441
2442 default:
2443 LOG(FATAL) << "Unexpected type conversion from " << input_type
2444 << " to " << result_type;
2445 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002446 break;
2447
2448 default:
2449 LOG(FATAL) << "Unexpected type conversion from " << input_type
2450 << " to " << result_type;
2451 }
2452}
2453
2454void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2455 LocationSummary* locations = conversion->GetLocations();
2456 Location out = locations->Out();
2457 Location in = locations->InAt(0);
2458 Primitive::Type result_type = conversion->GetResultType();
2459 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002460 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002461 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002462 case Primitive::kPrimByte:
2463 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002464 case Primitive::kPrimBoolean:
2465 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002466 case Primitive::kPrimShort:
2467 case Primitive::kPrimInt:
2468 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002469 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002470 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002471 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002472 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002473 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002474 Address(CpuRegister(RSP), in.GetStackIndex()));
2475 } else {
2476 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002477 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002478 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2479 }
2480 break;
2481
2482 default:
2483 LOG(FATAL) << "Unexpected type conversion from " << input_type
2484 << " to " << result_type;
2485 }
2486 break;
2487
Roland Levillain01a8d712014-11-14 16:27:39 +00002488 case Primitive::kPrimShort:
2489 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002490 case Primitive::kPrimBoolean:
2491 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002492 case Primitive::kPrimByte:
2493 case Primitive::kPrimInt:
2494 case Primitive::kPrimChar:
2495 // Processing a Dex `int-to-short' instruction.
2496 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002497 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002498 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002499 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002500 Address(CpuRegister(RSP), in.GetStackIndex()));
2501 } else {
2502 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002503 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002504 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2505 }
2506 break;
2507
2508 default:
2509 LOG(FATAL) << "Unexpected type conversion from " << input_type
2510 << " to " << result_type;
2511 }
2512 break;
2513
Roland Levillain946e1432014-11-11 17:35:19 +00002514 case Primitive::kPrimInt:
2515 switch (input_type) {
2516 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002517 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002518 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002519 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002520 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002521 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002522 Address(CpuRegister(RSP), in.GetStackIndex()));
2523 } else {
2524 DCHECK(in.IsConstant());
2525 DCHECK(in.GetConstant()->IsLongConstant());
2526 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002527 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002528 }
2529 break;
2530
Roland Levillain3f8f9362014-12-02 17:45:01 +00002531 case Primitive::kPrimFloat: {
2532 // Processing a Dex `float-to-int' instruction.
2533 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2534 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002535 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002536
2537 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002538 // if input >= (float)INT_MAX goto done
2539 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002540 __ j(kAboveEqual, &done);
2541 // if input == NaN goto nan
2542 __ j(kUnordered, &nan);
2543 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002544 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002545 __ jmp(&done);
2546 __ Bind(&nan);
2547 // output = 0
2548 __ xorl(output, output);
2549 __ Bind(&done);
2550 break;
2551 }
2552
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002553 case Primitive::kPrimDouble: {
2554 // Processing a Dex `double-to-int' instruction.
2555 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2556 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002557 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002558
2559 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002560 // if input >= (double)INT_MAX goto done
2561 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002562 __ j(kAboveEqual, &done);
2563 // if input == NaN goto nan
2564 __ j(kUnordered, &nan);
2565 // output = double-to-int-truncate(input)
2566 __ cvttsd2si(output, input);
2567 __ jmp(&done);
2568 __ Bind(&nan);
2569 // output = 0
2570 __ xorl(output, output);
2571 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002572 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002573 }
Roland Levillain946e1432014-11-11 17:35:19 +00002574
2575 default:
2576 LOG(FATAL) << "Unexpected type conversion from " << input_type
2577 << " to " << result_type;
2578 }
2579 break;
2580
Roland Levillaindff1f282014-11-05 14:15:05 +00002581 case Primitive::kPrimLong:
2582 switch (input_type) {
2583 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002584 case Primitive::kPrimBoolean:
2585 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002586 case Primitive::kPrimByte:
2587 case Primitive::kPrimShort:
2588 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002589 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002590 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002591 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002592 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002593 break;
2594
Roland Levillain624279f2014-12-04 11:54:28 +00002595 case Primitive::kPrimFloat: {
2596 // Processing a Dex `float-to-long' instruction.
2597 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2598 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002599 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002600
Mark Mendell92e83bf2015-05-07 11:25:03 -04002601 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002602 // if input >= (float)LONG_MAX goto done
2603 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002604 __ j(kAboveEqual, &done);
2605 // if input == NaN goto nan
2606 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002607 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002608 __ cvttss2si(output, input, true);
2609 __ jmp(&done);
2610 __ Bind(&nan);
2611 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002612 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002613 __ Bind(&done);
2614 break;
2615 }
2616
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002617 case Primitive::kPrimDouble: {
2618 // Processing a Dex `double-to-long' instruction.
2619 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2620 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002621 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002622
Mark Mendell92e83bf2015-05-07 11:25:03 -04002623 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002624 // if input >= (double)LONG_MAX goto done
2625 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002626 __ j(kAboveEqual, &done);
2627 // if input == NaN goto nan
2628 __ j(kUnordered, &nan);
2629 // output = double-to-long-truncate(input)
2630 __ cvttsd2si(output, input, true);
2631 __ jmp(&done);
2632 __ Bind(&nan);
2633 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002634 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002635 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002636 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002637 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002638
2639 default:
2640 LOG(FATAL) << "Unexpected type conversion from " << input_type
2641 << " to " << result_type;
2642 }
2643 break;
2644
Roland Levillain981e4542014-11-14 11:47:14 +00002645 case Primitive::kPrimChar:
2646 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002647 case Primitive::kPrimBoolean:
2648 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002649 case Primitive::kPrimByte:
2650 case Primitive::kPrimShort:
2651 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002652 // Processing a Dex `int-to-char' instruction.
2653 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002654 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002655 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002656 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002657 Address(CpuRegister(RSP), in.GetStackIndex()));
2658 } else {
2659 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002660 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002661 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2662 }
2663 break;
2664
2665 default:
2666 LOG(FATAL) << "Unexpected type conversion from " << input_type
2667 << " to " << result_type;
2668 }
2669 break;
2670
Roland Levillaindff1f282014-11-05 14:15:05 +00002671 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002672 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002673 case Primitive::kPrimBoolean:
2674 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002675 case Primitive::kPrimByte:
2676 case Primitive::kPrimShort:
2677 case Primitive::kPrimInt:
2678 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002679 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002680 if (in.IsRegister()) {
2681 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2682 } else if (in.IsConstant()) {
2683 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2684 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2685 if (v == 0) {
2686 __ xorps(dest, dest);
2687 } else {
2688 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2689 }
2690 } else {
2691 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2692 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2693 }
Roland Levillaincff13742014-11-17 14:32:17 +00002694 break;
2695
2696 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002697 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002698 if (in.IsRegister()) {
2699 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2700 } else if (in.IsConstant()) {
2701 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2702 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2703 if (v == 0) {
2704 __ xorps(dest, dest);
2705 } else {
2706 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2707 }
2708 } else {
2709 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2710 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2711 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002712 break;
2713
Roland Levillaincff13742014-11-17 14:32:17 +00002714 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002715 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002716 if (in.IsFpuRegister()) {
2717 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2718 } else if (in.IsConstant()) {
2719 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2720 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2721 if (bit_cast<int64_t, double>(v) == 0) {
2722 __ xorps(dest, dest);
2723 } else {
2724 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2725 }
2726 } else {
2727 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2728 Address(CpuRegister(RSP), in.GetStackIndex()));
2729 }
Roland Levillaincff13742014-11-17 14:32:17 +00002730 break;
2731
2732 default:
2733 LOG(FATAL) << "Unexpected type conversion from " << input_type
2734 << " to " << result_type;
2735 };
2736 break;
2737
Roland Levillaindff1f282014-11-05 14:15:05 +00002738 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002739 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002740 case Primitive::kPrimBoolean:
2741 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002742 case Primitive::kPrimByte:
2743 case Primitive::kPrimShort:
2744 case Primitive::kPrimInt:
2745 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002746 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002747 if (in.IsRegister()) {
2748 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2749 } else if (in.IsConstant()) {
2750 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2751 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2752 if (v == 0) {
2753 __ xorpd(dest, dest);
2754 } else {
2755 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2756 }
2757 } else {
2758 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2759 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2760 }
Roland Levillaincff13742014-11-17 14:32:17 +00002761 break;
2762
2763 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002764 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002765 if (in.IsRegister()) {
2766 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2767 } else if (in.IsConstant()) {
2768 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2769 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2770 if (v == 0) {
2771 __ xorpd(dest, dest);
2772 } else {
2773 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2774 }
2775 } else {
2776 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2777 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2778 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002779 break;
2780
Roland Levillaincff13742014-11-17 14:32:17 +00002781 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002782 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002783 if (in.IsFpuRegister()) {
2784 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2785 } else if (in.IsConstant()) {
2786 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2787 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2788 if (bit_cast<int32_t, float>(v) == 0) {
2789 __ xorpd(dest, dest);
2790 } else {
2791 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2792 }
2793 } else {
2794 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2795 Address(CpuRegister(RSP), in.GetStackIndex()));
2796 }
Roland Levillaincff13742014-11-17 14:32:17 +00002797 break;
2798
2799 default:
2800 LOG(FATAL) << "Unexpected type conversion from " << input_type
2801 << " to " << result_type;
2802 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002803 break;
2804
2805 default:
2806 LOG(FATAL) << "Unexpected type conversion from " << input_type
2807 << " to " << result_type;
2808 }
2809}
2810
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002811void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002812 LocationSummary* locations =
2813 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002814 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002815 case Primitive::kPrimInt: {
2816 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002817 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2818 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002819 break;
2820 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002821
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002822 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002823 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002824 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendellea5af682015-10-22 17:35:49 -04002825 locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002826 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002827 break;
2828 }
2829
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002830 case Primitive::kPrimDouble:
2831 case Primitive::kPrimFloat: {
2832 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002833 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002834 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002835 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002836 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002837
2838 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002839 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002840 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002841}
2842
2843void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2844 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002845 Location first = locations->InAt(0);
2846 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002847 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002848
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002849 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002850 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002851 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002852 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2853 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002854 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2855 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002856 } else {
2857 __ leal(out.AsRegister<CpuRegister>(), Address(
2858 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2859 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002860 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002861 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2862 __ addl(out.AsRegister<CpuRegister>(),
2863 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2864 } else {
2865 __ leal(out.AsRegister<CpuRegister>(), Address(
2866 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2867 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002868 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002869 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002870 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002871 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002872 break;
2873 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002874
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002875 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002876 if (second.IsRegister()) {
2877 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2878 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002879 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2880 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002881 } else {
2882 __ leaq(out.AsRegister<CpuRegister>(), Address(
2883 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2884 }
2885 } else {
2886 DCHECK(second.IsConstant());
2887 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2888 int32_t int32_value = Low32Bits(value);
2889 DCHECK_EQ(int32_value, value);
2890 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2891 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2892 } else {
2893 __ leaq(out.AsRegister<CpuRegister>(), Address(
2894 first.AsRegister<CpuRegister>(), int32_value));
2895 }
2896 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002897 break;
2898 }
2899
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002900 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002901 if (second.IsFpuRegister()) {
2902 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2903 } else if (second.IsConstant()) {
2904 __ addss(first.AsFpuRegister<XmmRegister>(),
2905 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2906 } else {
2907 DCHECK(second.IsStackSlot());
2908 __ addss(first.AsFpuRegister<XmmRegister>(),
2909 Address(CpuRegister(RSP), second.GetStackIndex()));
2910 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002911 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002912 }
2913
2914 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002915 if (second.IsFpuRegister()) {
2916 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2917 } else if (second.IsConstant()) {
2918 __ addsd(first.AsFpuRegister<XmmRegister>(),
2919 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2920 } else {
2921 DCHECK(second.IsDoubleStackSlot());
2922 __ addsd(first.AsFpuRegister<XmmRegister>(),
2923 Address(CpuRegister(RSP), second.GetStackIndex()));
2924 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002925 break;
2926 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002927
2928 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002929 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002930 }
2931}
2932
2933void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002934 LocationSummary* locations =
2935 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002936 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002937 case Primitive::kPrimInt: {
2938 locations->SetInAt(0, Location::RequiresRegister());
2939 locations->SetInAt(1, Location::Any());
2940 locations->SetOut(Location::SameAsFirstInput());
2941 break;
2942 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002943 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002944 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04002945 locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002946 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002947 break;
2948 }
Calin Juravle11351682014-10-23 15:38:15 +01002949 case Primitive::kPrimFloat:
2950 case Primitive::kPrimDouble: {
2951 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002952 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002953 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002954 break;
Calin Juravle11351682014-10-23 15:38:15 +01002955 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002956 default:
Calin Juravle11351682014-10-23 15:38:15 +01002957 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002958 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002959}
2960
2961void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2962 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002963 Location first = locations->InAt(0);
2964 Location second = locations->InAt(1);
2965 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002966 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002967 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002968 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002969 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002970 } else if (second.IsConstant()) {
2971 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002972 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002973 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002974 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002975 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002976 break;
2977 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002978 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002979 if (second.IsConstant()) {
2980 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2981 DCHECK(IsInt<32>(value));
2982 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2983 } else {
2984 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2985 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002986 break;
2987 }
2988
Calin Juravle11351682014-10-23 15:38:15 +01002989 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002990 if (second.IsFpuRegister()) {
2991 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2992 } else if (second.IsConstant()) {
2993 __ subss(first.AsFpuRegister<XmmRegister>(),
2994 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2995 } else {
2996 DCHECK(second.IsStackSlot());
2997 __ subss(first.AsFpuRegister<XmmRegister>(),
2998 Address(CpuRegister(RSP), second.GetStackIndex()));
2999 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003000 break;
Calin Juravle11351682014-10-23 15:38:15 +01003001 }
3002
3003 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003004 if (second.IsFpuRegister()) {
3005 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3006 } else if (second.IsConstant()) {
3007 __ subsd(first.AsFpuRegister<XmmRegister>(),
3008 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3009 } else {
3010 DCHECK(second.IsDoubleStackSlot());
3011 __ subsd(first.AsFpuRegister<XmmRegister>(),
3012 Address(CpuRegister(RSP), second.GetStackIndex()));
3013 }
Calin Juravle11351682014-10-23 15:38:15 +01003014 break;
3015 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003016
3017 default:
Calin Juravle11351682014-10-23 15:38:15 +01003018 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003019 }
3020}
3021
Calin Juravle34bacdf2014-10-07 20:23:36 +01003022void LocationsBuilderX86_64::VisitMul(HMul* mul) {
3023 LocationSummary* locations =
3024 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3025 switch (mul->GetResultType()) {
3026 case Primitive::kPrimInt: {
3027 locations->SetInAt(0, Location::RequiresRegister());
3028 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003029 if (mul->InputAt(1)->IsIntConstant()) {
3030 // Can use 3 operand multiply.
3031 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3032 } else {
3033 locations->SetOut(Location::SameAsFirstInput());
3034 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003035 break;
3036 }
3037 case Primitive::kPrimLong: {
3038 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003039 locations->SetInAt(1, Location::Any());
3040 if (mul->InputAt(1)->IsLongConstant() &&
3041 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003042 // Can use 3 operand multiply.
3043 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3044 } else {
3045 locations->SetOut(Location::SameAsFirstInput());
3046 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003047 break;
3048 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003049 case Primitive::kPrimFloat:
3050 case Primitive::kPrimDouble: {
3051 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003052 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01003053 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003054 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003055 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003056
3057 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003058 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003059 }
3060}
3061
3062void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
3063 LocationSummary* locations = mul->GetLocations();
3064 Location first = locations->InAt(0);
3065 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003066 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003067 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003068 case Primitive::kPrimInt:
3069 // The constant may have ended up in a register, so test explicitly to avoid
3070 // problems where the output may not be the same as the first operand.
3071 if (mul->InputAt(1)->IsIntConstant()) {
3072 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3073 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
3074 } else if (second.IsRegister()) {
3075 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003076 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003077 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003078 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003079 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00003080 __ imull(first.AsRegister<CpuRegister>(),
3081 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003082 }
3083 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01003084 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003085 // The constant may have ended up in a register, so test explicitly to avoid
3086 // problems where the output may not be the same as the first operand.
3087 if (mul->InputAt(1)->IsLongConstant()) {
3088 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
3089 if (IsInt<32>(value)) {
3090 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
3091 Immediate(static_cast<int32_t>(value)));
3092 } else {
3093 // Have to use the constant area.
3094 DCHECK(first.Equals(out));
3095 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
3096 }
3097 } else if (second.IsRegister()) {
3098 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003099 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003100 } else {
3101 DCHECK(second.IsDoubleStackSlot());
3102 DCHECK(first.Equals(out));
3103 __ imulq(first.AsRegister<CpuRegister>(),
3104 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003105 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003106 break;
3107 }
3108
Calin Juravleb5bfa962014-10-21 18:02:24 +01003109 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003110 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003111 if (second.IsFpuRegister()) {
3112 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3113 } else if (second.IsConstant()) {
3114 __ mulss(first.AsFpuRegister<XmmRegister>(),
3115 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3116 } else {
3117 DCHECK(second.IsStackSlot());
3118 __ mulss(first.AsFpuRegister<XmmRegister>(),
3119 Address(CpuRegister(RSP), second.GetStackIndex()));
3120 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003121 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003122 }
3123
3124 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003125 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003126 if (second.IsFpuRegister()) {
3127 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3128 } else if (second.IsConstant()) {
3129 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3130 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3131 } else {
3132 DCHECK(second.IsDoubleStackSlot());
3133 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3134 Address(CpuRegister(RSP), second.GetStackIndex()));
3135 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003136 break;
3137 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003138
3139 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003140 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003141 }
3142}
3143
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003144void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
3145 uint32_t stack_adjustment, bool is_float) {
3146 if (source.IsStackSlot()) {
3147 DCHECK(is_float);
3148 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3149 } else if (source.IsDoubleStackSlot()) {
3150 DCHECK(!is_float);
3151 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3152 } else {
3153 // Write the value to the temporary location on the stack and load to FP stack.
3154 if (is_float) {
3155 Location stack_temp = Location::StackSlot(temp_offset);
3156 codegen_->Move(stack_temp, source);
3157 __ flds(Address(CpuRegister(RSP), temp_offset));
3158 } else {
3159 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3160 codegen_->Move(stack_temp, source);
3161 __ fldl(Address(CpuRegister(RSP), temp_offset));
3162 }
3163 }
3164}
3165
3166void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
3167 Primitive::Type type = rem->GetResultType();
3168 bool is_float = type == Primitive::kPrimFloat;
3169 size_t elem_size = Primitive::ComponentSize(type);
3170 LocationSummary* locations = rem->GetLocations();
3171 Location first = locations->InAt(0);
3172 Location second = locations->InAt(1);
3173 Location out = locations->Out();
3174
3175 // Create stack space for 2 elements.
3176 // TODO: enhance register allocator to ask for stack temporaries.
3177 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
3178
3179 // Load the values to the FP stack in reverse order, using temporaries if needed.
3180 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
3181 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
3182
3183 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003184 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003185 __ Bind(&retry);
3186 __ fprem();
3187
3188 // Move FP status to AX.
3189 __ fstsw();
3190
3191 // And see if the argument reduction is complete. This is signaled by the
3192 // C2 FPU flag bit set to 0.
3193 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
3194 __ j(kNotEqual, &retry);
3195
3196 // We have settled on the final value. Retrieve it into an XMM register.
3197 // Store FP top of stack to real stack.
3198 if (is_float) {
3199 __ fsts(Address(CpuRegister(RSP), 0));
3200 } else {
3201 __ fstl(Address(CpuRegister(RSP), 0));
3202 }
3203
3204 // Pop the 2 items from the FP stack.
3205 __ fucompp();
3206
3207 // Load the value from the stack into an XMM register.
3208 DCHECK(out.IsFpuRegister()) << out;
3209 if (is_float) {
3210 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3211 } else {
3212 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3213 }
3214
3215 // And remove the temporary stack space we allocated.
3216 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
3217}
3218
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003219void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3220 DCHECK(instruction->IsDiv() || instruction->IsRem());
3221
3222 LocationSummary* locations = instruction->GetLocations();
3223 Location second = locations->InAt(1);
3224 DCHECK(second.IsConstant());
3225
3226 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3227 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003228 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003229
3230 DCHECK(imm == 1 || imm == -1);
3231
3232 switch (instruction->GetResultType()) {
3233 case Primitive::kPrimInt: {
3234 if (instruction->IsRem()) {
3235 __ xorl(output_register, output_register);
3236 } else {
3237 __ movl(output_register, input_register);
3238 if (imm == -1) {
3239 __ negl(output_register);
3240 }
3241 }
3242 break;
3243 }
3244
3245 case Primitive::kPrimLong: {
3246 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003247 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003248 } else {
3249 __ movq(output_register, input_register);
3250 if (imm == -1) {
3251 __ negq(output_register);
3252 }
3253 }
3254 break;
3255 }
3256
3257 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003258 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003259 }
3260}
3261
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003262void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003263 LocationSummary* locations = instruction->GetLocations();
3264 Location second = locations->InAt(1);
3265
3266 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3267 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3268
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003269 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003270
3271 DCHECK(IsPowerOfTwo(std::abs(imm)));
3272
3273 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3274
3275 if (instruction->GetResultType() == Primitive::kPrimInt) {
3276 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
3277 __ testl(numerator, numerator);
3278 __ cmov(kGreaterEqual, tmp, numerator);
3279 int shift = CTZ(imm);
3280 __ sarl(tmp, Immediate(shift));
3281
3282 if (imm < 0) {
3283 __ negl(tmp);
3284 }
3285
3286 __ movl(output_register, tmp);
3287 } else {
3288 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3289 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3290
Mark Mendell92e83bf2015-05-07 11:25:03 -04003291 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003292 __ addq(rdx, numerator);
3293 __ testq(numerator, numerator);
3294 __ cmov(kGreaterEqual, rdx, numerator);
3295 int shift = CTZ(imm);
3296 __ sarq(rdx, Immediate(shift));
3297
3298 if (imm < 0) {
3299 __ negq(rdx);
3300 }
3301
3302 __ movq(output_register, rdx);
3303 }
3304}
3305
3306void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3307 DCHECK(instruction->IsDiv() || instruction->IsRem());
3308
3309 LocationSummary* locations = instruction->GetLocations();
3310 Location second = locations->InAt(1);
3311
3312 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3313 : locations->GetTemp(0).AsRegister<CpuRegister>();
3314 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3315 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3316 : locations->Out().AsRegister<CpuRegister>();
3317 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3318
3319 DCHECK_EQ(RAX, eax.AsRegister());
3320 DCHECK_EQ(RDX, edx.AsRegister());
3321 if (instruction->IsDiv()) {
3322 DCHECK_EQ(RAX, out.AsRegister());
3323 } else {
3324 DCHECK_EQ(RDX, out.AsRegister());
3325 }
3326
3327 int64_t magic;
3328 int shift;
3329
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003330 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003331 if (instruction->GetResultType() == Primitive::kPrimInt) {
3332 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3333
3334 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3335
3336 __ movl(numerator, eax);
3337
Mark Mendell0c9497d2015-08-21 09:30:05 -04003338 NearLabel no_div;
3339 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003340 __ testl(eax, eax);
3341 __ j(kNotEqual, &no_div);
3342
3343 __ xorl(out, out);
3344 __ jmp(&end);
3345
3346 __ Bind(&no_div);
3347
3348 __ movl(eax, Immediate(magic));
3349 __ imull(numerator);
3350
3351 if (imm > 0 && magic < 0) {
3352 __ addl(edx, numerator);
3353 } else if (imm < 0 && magic > 0) {
3354 __ subl(edx, numerator);
3355 }
3356
3357 if (shift != 0) {
3358 __ sarl(edx, Immediate(shift));
3359 }
3360
3361 __ movl(eax, edx);
3362 __ shrl(edx, Immediate(31));
3363 __ addl(edx, eax);
3364
3365 if (instruction->IsRem()) {
3366 __ movl(eax, numerator);
3367 __ imull(edx, Immediate(imm));
3368 __ subl(eax, edx);
3369 __ movl(edx, eax);
3370 } else {
3371 __ movl(eax, edx);
3372 }
3373 __ Bind(&end);
3374 } else {
3375 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3376
3377 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3378
3379 CpuRegister rax = eax;
3380 CpuRegister rdx = edx;
3381
3382 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3383
3384 // Save the numerator.
3385 __ movq(numerator, rax);
3386
3387 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003388 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003389
3390 // RDX:RAX = magic * numerator
3391 __ imulq(numerator);
3392
3393 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003394 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003395 __ addq(rdx, numerator);
3396 } else if (imm < 0 && magic > 0) {
3397 // RDX -= numerator
3398 __ subq(rdx, numerator);
3399 }
3400
3401 // Shift if needed.
3402 if (shift != 0) {
3403 __ sarq(rdx, Immediate(shift));
3404 }
3405
3406 // RDX += 1 if RDX < 0
3407 __ movq(rax, rdx);
3408 __ shrq(rdx, Immediate(63));
3409 __ addq(rdx, rax);
3410
3411 if (instruction->IsRem()) {
3412 __ movq(rax, numerator);
3413
3414 if (IsInt<32>(imm)) {
3415 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3416 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003417 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003418 }
3419
3420 __ subq(rax, rdx);
3421 __ movq(rdx, rax);
3422 } else {
3423 __ movq(rax, rdx);
3424 }
3425 }
3426}
3427
Calin Juravlebacfec32014-11-14 15:54:36 +00003428void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3429 DCHECK(instruction->IsDiv() || instruction->IsRem());
3430 Primitive::Type type = instruction->GetResultType();
3431 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3432
3433 bool is_div = instruction->IsDiv();
3434 LocationSummary* locations = instruction->GetLocations();
3435
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003436 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3437 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003438
Roland Levillain271ab9c2014-11-27 15:23:57 +00003439 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003440 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003441
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003442 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003443 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003444
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003445 if (imm == 0) {
3446 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3447 } else if (imm == 1 || imm == -1) {
3448 DivRemOneOrMinusOne(instruction);
3449 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003450 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003451 } else {
3452 DCHECK(imm <= -2 || imm >= 2);
3453 GenerateDivRemWithAnyConstant(instruction);
3454 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003455 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003456 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003457 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3458 out.AsRegister(), type, is_div);
3459 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003460
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003461 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3462 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3463 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3464 // so it's safe to just use negl instead of more complex comparisons.
3465 if (type == Primitive::kPrimInt) {
3466 __ cmpl(second_reg, Immediate(-1));
3467 __ j(kEqual, slow_path->GetEntryLabel());
3468 // edx:eax <- sign-extended of eax
3469 __ cdq();
3470 // eax = quotient, edx = remainder
3471 __ idivl(second_reg);
3472 } else {
3473 __ cmpq(second_reg, Immediate(-1));
3474 __ j(kEqual, slow_path->GetEntryLabel());
3475 // rdx:rax <- sign-extended of rax
3476 __ cqo();
3477 // rax = quotient, rdx = remainder
3478 __ idivq(second_reg);
3479 }
3480 __ Bind(slow_path->GetExitLabel());
3481 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003482}
3483
Calin Juravle7c4954d2014-10-28 16:57:40 +00003484void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3485 LocationSummary* locations =
3486 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3487 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003488 case Primitive::kPrimInt:
3489 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003490 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003491 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003492 locations->SetOut(Location::SameAsFirstInput());
3493 // Intel uses edx:eax as the dividend.
3494 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003495 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3496 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3497 // output and request another temp.
3498 if (div->InputAt(1)->IsConstant()) {
3499 locations->AddTemp(Location::RequiresRegister());
3500 }
Calin Juravled0d48522014-11-04 16:40:20 +00003501 break;
3502 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003503
Calin Juravle7c4954d2014-10-28 16:57:40 +00003504 case Primitive::kPrimFloat:
3505 case Primitive::kPrimDouble: {
3506 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003507 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003508 locations->SetOut(Location::SameAsFirstInput());
3509 break;
3510 }
3511
3512 default:
3513 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3514 }
3515}
3516
3517void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3518 LocationSummary* locations = div->GetLocations();
3519 Location first = locations->InAt(0);
3520 Location second = locations->InAt(1);
3521 DCHECK(first.Equals(locations->Out()));
3522
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003523 Primitive::Type type = div->GetResultType();
3524 switch (type) {
3525 case Primitive::kPrimInt:
3526 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003527 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003528 break;
3529 }
3530
Calin Juravle7c4954d2014-10-28 16:57:40 +00003531 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003532 if (second.IsFpuRegister()) {
3533 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3534 } else if (second.IsConstant()) {
3535 __ divss(first.AsFpuRegister<XmmRegister>(),
3536 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3537 } else {
3538 DCHECK(second.IsStackSlot());
3539 __ divss(first.AsFpuRegister<XmmRegister>(),
3540 Address(CpuRegister(RSP), second.GetStackIndex()));
3541 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003542 break;
3543 }
3544
3545 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003546 if (second.IsFpuRegister()) {
3547 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3548 } else if (second.IsConstant()) {
3549 __ divsd(first.AsFpuRegister<XmmRegister>(),
3550 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3551 } else {
3552 DCHECK(second.IsDoubleStackSlot());
3553 __ divsd(first.AsFpuRegister<XmmRegister>(),
3554 Address(CpuRegister(RSP), second.GetStackIndex()));
3555 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003556 break;
3557 }
3558
3559 default:
3560 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3561 }
3562}
3563
Calin Juravlebacfec32014-11-14 15:54:36 +00003564void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003565 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003566 LocationSummary* locations =
3567 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003568
3569 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003570 case Primitive::kPrimInt:
3571 case Primitive::kPrimLong: {
3572 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003573 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003574 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3575 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003576 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3577 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3578 // output and request another temp.
3579 if (rem->InputAt(1)->IsConstant()) {
3580 locations->AddTemp(Location::RequiresRegister());
3581 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003582 break;
3583 }
3584
3585 case Primitive::kPrimFloat:
3586 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003587 locations->SetInAt(0, Location::Any());
3588 locations->SetInAt(1, Location::Any());
3589 locations->SetOut(Location::RequiresFpuRegister());
3590 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003591 break;
3592 }
3593
3594 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003595 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003596 }
3597}
3598
3599void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3600 Primitive::Type type = rem->GetResultType();
3601 switch (type) {
3602 case Primitive::kPrimInt:
3603 case Primitive::kPrimLong: {
3604 GenerateDivRemIntegral(rem);
3605 break;
3606 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003607 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003608 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003609 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003610 break;
3611 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003612 default:
3613 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3614 }
3615}
3616
Calin Juravled0d48522014-11-04 16:40:20 +00003617void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003618 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3619 ? LocationSummary::kCallOnSlowPath
3620 : LocationSummary::kNoCall;
3621 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled0d48522014-11-04 16:40:20 +00003622 locations->SetInAt(0, Location::Any());
3623 if (instruction->HasUses()) {
3624 locations->SetOut(Location::SameAsFirstInput());
3625 }
3626}
3627
3628void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003629 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003630 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3631 codegen_->AddSlowPath(slow_path);
3632
3633 LocationSummary* locations = instruction->GetLocations();
3634 Location value = locations->InAt(0);
3635
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003636 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003637 case Primitive::kPrimByte:
3638 case Primitive::kPrimChar:
3639 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003640 case Primitive::kPrimInt: {
3641 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003643 __ j(kEqual, slow_path->GetEntryLabel());
3644 } else if (value.IsStackSlot()) {
3645 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3646 __ j(kEqual, slow_path->GetEntryLabel());
3647 } else {
3648 DCHECK(value.IsConstant()) << value;
3649 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3650 __ jmp(slow_path->GetEntryLabel());
3651 }
3652 }
3653 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003654 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003655 case Primitive::kPrimLong: {
3656 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003657 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003658 __ j(kEqual, slow_path->GetEntryLabel());
3659 } else if (value.IsDoubleStackSlot()) {
3660 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3661 __ j(kEqual, slow_path->GetEntryLabel());
3662 } else {
3663 DCHECK(value.IsConstant()) << value;
3664 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3665 __ jmp(slow_path->GetEntryLabel());
3666 }
3667 }
3668 break;
3669 }
3670 default:
3671 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003672 }
Calin Juravled0d48522014-11-04 16:40:20 +00003673}
3674
Calin Juravle9aec02f2014-11-18 23:06:35 +00003675void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3676 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3677
3678 LocationSummary* locations =
3679 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3680
3681 switch (op->GetResultType()) {
3682 case Primitive::kPrimInt:
3683 case Primitive::kPrimLong: {
3684 locations->SetInAt(0, Location::RequiresRegister());
3685 // The shift count needs to be in CL.
3686 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3687 locations->SetOut(Location::SameAsFirstInput());
3688 break;
3689 }
3690 default:
3691 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3692 }
3693}
3694
3695void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3696 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3697
3698 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003699 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003700 Location second = locations->InAt(1);
3701
3702 switch (op->GetResultType()) {
3703 case Primitive::kPrimInt: {
3704 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003705 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003706 if (op->IsShl()) {
3707 __ shll(first_reg, second_reg);
3708 } else if (op->IsShr()) {
3709 __ sarl(first_reg, second_reg);
3710 } else {
3711 __ shrl(first_reg, second_reg);
3712 }
3713 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003714 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003715 if (op->IsShl()) {
3716 __ shll(first_reg, imm);
3717 } else if (op->IsShr()) {
3718 __ sarl(first_reg, imm);
3719 } else {
3720 __ shrl(first_reg, imm);
3721 }
3722 }
3723 break;
3724 }
3725 case Primitive::kPrimLong: {
3726 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003727 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003728 if (op->IsShl()) {
3729 __ shlq(first_reg, second_reg);
3730 } else if (op->IsShr()) {
3731 __ sarq(first_reg, second_reg);
3732 } else {
3733 __ shrq(first_reg, second_reg);
3734 }
3735 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003736 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003737 if (op->IsShl()) {
3738 __ shlq(first_reg, imm);
3739 } else if (op->IsShr()) {
3740 __ sarq(first_reg, imm);
3741 } else {
3742 __ shrq(first_reg, imm);
3743 }
3744 }
3745 break;
3746 }
3747 default:
3748 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3749 }
3750}
3751
3752void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3753 HandleShift(shl);
3754}
3755
3756void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3757 HandleShift(shl);
3758}
3759
3760void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3761 HandleShift(shr);
3762}
3763
3764void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3765 HandleShift(shr);
3766}
3767
3768void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3769 HandleShift(ushr);
3770}
3771
3772void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3773 HandleShift(ushr);
3774}
3775
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003776void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003777 LocationSummary* locations =
3778 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003779 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray729645a2015-11-19 13:29:02 +00003780 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3781 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003782 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003783}
3784
3785void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003786 // Note: if heap poisoning is enabled, the entry point takes cares
3787 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003788 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3789 instruction,
3790 instruction->GetDexPc(),
3791 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003792 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003793
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003794 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003795}
3796
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003797void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3798 LocationSummary* locations =
3799 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3800 InvokeRuntimeCallingConvention calling_convention;
3801 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003802 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003803 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003804 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003805}
3806
3807void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3808 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003809 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3810 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003811 // Note: if heap poisoning is enabled, the entry point takes cares
3812 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003813 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3814 instruction,
3815 instruction->GetDexPc(),
3816 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003817 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003818
3819 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003820}
3821
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003822void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003823 LocationSummary* locations =
3824 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003825 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3826 if (location.IsStackSlot()) {
3827 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3828 } else if (location.IsDoubleStackSlot()) {
3829 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3830 }
3831 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003832}
3833
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003834void InstructionCodeGeneratorX86_64::VisitParameterValue(
3835 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003836 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003837}
3838
3839void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3840 LocationSummary* locations =
3841 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3842 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3843}
3844
3845void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3846 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3847 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003848}
3849
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003850void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003851 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003852 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003853 locations->SetInAt(0, Location::RequiresRegister());
3854 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003855}
3856
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003857void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3858 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003859 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3860 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003861 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003862 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003863 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003864 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003865 break;
3866
3867 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003868 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003869 break;
3870
3871 default:
3872 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3873 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003874}
3875
David Brazdil66d126e2015-04-03 16:02:44 +01003876void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3877 LocationSummary* locations =
3878 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3879 locations->SetInAt(0, Location::RequiresRegister());
3880 locations->SetOut(Location::SameAsFirstInput());
3881}
3882
3883void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003884 LocationSummary* locations = bool_not->GetLocations();
3885 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3886 locations->Out().AsRegister<CpuRegister>().AsRegister());
3887 Location out = locations->Out();
3888 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3889}
3890
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003891void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003892 LocationSummary* locations =
3893 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003894 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3895 locations->SetInAt(i, Location::Any());
3896 }
3897 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003898}
3899
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003900void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003901 LOG(FATAL) << "Unimplemented";
3902}
3903
Calin Juravle52c48962014-12-16 17:02:57 +00003904void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3905 /*
3906 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3907 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3908 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3909 */
3910 switch (kind) {
3911 case MemBarrierKind::kAnyAny: {
3912 __ mfence();
3913 break;
3914 }
3915 case MemBarrierKind::kAnyStore:
3916 case MemBarrierKind::kLoadAny:
3917 case MemBarrierKind::kStoreStore: {
3918 // nop
3919 break;
3920 }
3921 default:
3922 LOG(FATAL) << "Unexpected memory barier " << kind;
3923 }
3924}
3925
3926void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3927 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3928
Roland Levillain0d5a2812015-11-13 10:07:31 +00003929 bool object_field_get_with_read_barrier =
3930 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003931 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00003932 new (GetGraph()->GetArena()) LocationSummary(instruction,
3933 object_field_get_with_read_barrier ?
3934 LocationSummary::kCallOnSlowPath :
3935 LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003936 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003937 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3938 locations->SetOut(Location::RequiresFpuRegister());
3939 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00003940 // The output overlaps for an object field get when read barriers
3941 // are enabled: we do not want the move to overwrite the object's
3942 // location, as we need it to emit the read barrier.
3943 locations->SetOut(
3944 Location::RequiresRegister(),
3945 object_field_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003946 }
Calin Juravle52c48962014-12-16 17:02:57 +00003947}
3948
3949void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3950 const FieldInfo& field_info) {
3951 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3952
3953 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00003954 Location base_loc = locations->InAt(0);
3955 CpuRegister base = base_loc.AsRegister<CpuRegister>();
Calin Juravle52c48962014-12-16 17:02:57 +00003956 Location out = locations->Out();
3957 bool is_volatile = field_info.IsVolatile();
3958 Primitive::Type field_type = field_info.GetFieldType();
3959 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3960
3961 switch (field_type) {
3962 case Primitive::kPrimBoolean: {
3963 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3964 break;
3965 }
3966
3967 case Primitive::kPrimByte: {
3968 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3969 break;
3970 }
3971
3972 case Primitive::kPrimShort: {
3973 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3974 break;
3975 }
3976
3977 case Primitive::kPrimChar: {
3978 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3979 break;
3980 }
3981
3982 case Primitive::kPrimInt:
3983 case Primitive::kPrimNot: {
3984 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3985 break;
3986 }
3987
3988 case Primitive::kPrimLong: {
3989 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3990 break;
3991 }
3992
3993 case Primitive::kPrimFloat: {
3994 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
3995 break;
3996 }
3997
3998 case Primitive::kPrimDouble: {
3999 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4000 break;
4001 }
4002
4003 case Primitive::kPrimVoid:
4004 LOG(FATAL) << "Unreachable type " << field_type;
4005 UNREACHABLE();
4006 }
4007
Calin Juravle77520bc2015-01-12 18:45:46 +00004008 codegen_->MaybeRecordImplicitNullCheck(instruction);
4009
Calin Juravle52c48962014-12-16 17:02:57 +00004010 if (is_volatile) {
4011 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4012 }
Roland Levillain4d027112015-07-01 15:41:14 +01004013
4014 if (field_type == Primitive::kPrimNot) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004015 codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004016 }
Calin Juravle52c48962014-12-16 17:02:57 +00004017}
4018
4019void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
4020 const FieldInfo& field_info) {
4021 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4022
4023 LocationSummary* locations =
4024 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01004025 Primitive::Type field_type = field_info.GetFieldType();
Mark Mendellea5af682015-10-22 17:35:49 -04004026 bool is_volatile = field_info.IsVolatile();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004027 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01004028 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004029
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004030 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004031 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
Mark Mendellea5af682015-10-22 17:35:49 -04004032 if (is_volatile) {
4033 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4034 locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
4035 } else {
4036 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
4037 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004038 } else {
Mark Mendellea5af682015-10-22 17:35:49 -04004039 if (is_volatile) {
4040 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4041 locations->SetInAt(1, Location::RegisterOrInt32Constant(instruction->InputAt(1)));
4042 } else {
4043 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4044 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004045 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004046 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004047 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01004048 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004049 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01004050 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4051 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004052 locations->AddTemp(Location::RequiresRegister());
4053 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004054}
4055
Calin Juravle52c48962014-12-16 17:02:57 +00004056void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004057 const FieldInfo& field_info,
4058 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004059 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4060
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004061 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004062 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
4063 Location value = locations->InAt(1);
4064 bool is_volatile = field_info.IsVolatile();
4065 Primitive::Type field_type = field_info.GetFieldType();
4066 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4067
4068 if (is_volatile) {
4069 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4070 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004071
Mark Mendellea5af682015-10-22 17:35:49 -04004072 bool maybe_record_implicit_null_check_done = false;
4073
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004074 switch (field_type) {
4075 case Primitive::kPrimBoolean:
4076 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04004077 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004078 int8_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004079 __ movb(Address(base, offset), Immediate(v));
4080 } else {
4081 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
4082 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004083 break;
4084 }
4085
4086 case Primitive::kPrimShort:
4087 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04004088 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004089 int16_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004090 __ movw(Address(base, offset), Immediate(v));
4091 } else {
4092 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
4093 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004094 break;
4095 }
4096
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004097 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004098 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04004099 if (value.IsConstant()) {
4100 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004101 // `field_type == Primitive::kPrimNot` implies `v == 0`.
4102 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
4103 // Note: if heap poisoning is enabled, no need to poison
4104 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01004105 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04004106 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01004107 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4108 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4109 __ movl(temp, value.AsRegister<CpuRegister>());
4110 __ PoisonHeapReference(temp);
4111 __ movl(Address(base, offset), temp);
4112 } else {
4113 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
4114 }
Mark Mendell40741f32015-04-20 22:10:34 -04004115 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004116 break;
4117 }
4118
4119 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04004120 if (value.IsConstant()) {
4121 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004122 codegen_->MoveInt64ToAddress(Address(base, offset),
4123 Address(base, offset + sizeof(int32_t)),
4124 v,
4125 instruction);
4126 maybe_record_implicit_null_check_done = true;
Mark Mendell40741f32015-04-20 22:10:34 -04004127 } else {
4128 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
4129 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004130 break;
4131 }
4132
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004133 case Primitive::kPrimFloat: {
Mark Mendellea5af682015-10-22 17:35:49 -04004134 if (value.IsConstant()) {
4135 int32_t v =
4136 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4137 __ movl(Address(base, offset), Immediate(v));
4138 } else {
4139 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4140 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004141 break;
4142 }
4143
4144 case Primitive::kPrimDouble: {
Mark Mendellea5af682015-10-22 17:35:49 -04004145 if (value.IsConstant()) {
4146 int64_t v =
4147 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4148 codegen_->MoveInt64ToAddress(Address(base, offset),
4149 Address(base, offset + sizeof(int32_t)),
4150 v,
4151 instruction);
4152 maybe_record_implicit_null_check_done = true;
4153 } else {
4154 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4155 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004156 break;
4157 }
4158
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004159 case Primitive::kPrimVoid:
4160 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004161 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004162 }
Calin Juravle52c48962014-12-16 17:02:57 +00004163
Mark Mendellea5af682015-10-22 17:35:49 -04004164 if (!maybe_record_implicit_null_check_done) {
4165 codegen_->MaybeRecordImplicitNullCheck(instruction);
4166 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004167
4168 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4169 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4170 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004171 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004172 }
4173
Calin Juravle52c48962014-12-16 17:02:57 +00004174 if (is_volatile) {
4175 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4176 }
4177}
4178
4179void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4180 HandleFieldSet(instruction, instruction->GetFieldInfo());
4181}
4182
4183void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004184 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004185}
4186
4187void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004188 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004189}
4190
4191void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004192 HandleFieldGet(instruction, instruction->GetFieldInfo());
4193}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004194
Calin Juravle52c48962014-12-16 17:02:57 +00004195void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4196 HandleFieldGet(instruction);
4197}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004198
Calin Juravle52c48962014-12-16 17:02:57 +00004199void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4200 HandleFieldGet(instruction, instruction->GetFieldInfo());
4201}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004202
Calin Juravle52c48962014-12-16 17:02:57 +00004203void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4204 HandleFieldSet(instruction, instruction->GetFieldInfo());
4205}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004206
Calin Juravle52c48962014-12-16 17:02:57 +00004207void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004208 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004209}
4210
Calin Juravlee460d1d2015-09-29 04:52:17 +01004211void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
4212 HUnresolvedInstanceFieldGet* instruction) {
4213 FieldAccessCallingConventionX86_64 calling_convention;
4214 codegen_->CreateUnresolvedFieldLocationSummary(
4215 instruction, instruction->GetFieldType(), calling_convention);
4216}
4217
4218void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
4219 HUnresolvedInstanceFieldGet* instruction) {
4220 FieldAccessCallingConventionX86_64 calling_convention;
4221 codegen_->GenerateUnresolvedFieldAccess(instruction,
4222 instruction->GetFieldType(),
4223 instruction->GetFieldIndex(),
4224 instruction->GetDexPc(),
4225 calling_convention);
4226}
4227
4228void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
4229 HUnresolvedInstanceFieldSet* instruction) {
4230 FieldAccessCallingConventionX86_64 calling_convention;
4231 codegen_->CreateUnresolvedFieldLocationSummary(
4232 instruction, instruction->GetFieldType(), calling_convention);
4233}
4234
4235void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
4236 HUnresolvedInstanceFieldSet* instruction) {
4237 FieldAccessCallingConventionX86_64 calling_convention;
4238 codegen_->GenerateUnresolvedFieldAccess(instruction,
4239 instruction->GetFieldType(),
4240 instruction->GetFieldIndex(),
4241 instruction->GetDexPc(),
4242 calling_convention);
4243}
4244
4245void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
4246 HUnresolvedStaticFieldGet* instruction) {
4247 FieldAccessCallingConventionX86_64 calling_convention;
4248 codegen_->CreateUnresolvedFieldLocationSummary(
4249 instruction, instruction->GetFieldType(), calling_convention);
4250}
4251
4252void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
4253 HUnresolvedStaticFieldGet* instruction) {
4254 FieldAccessCallingConventionX86_64 calling_convention;
4255 codegen_->GenerateUnresolvedFieldAccess(instruction,
4256 instruction->GetFieldType(),
4257 instruction->GetFieldIndex(),
4258 instruction->GetDexPc(),
4259 calling_convention);
4260}
4261
4262void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
4263 HUnresolvedStaticFieldSet* instruction) {
4264 FieldAccessCallingConventionX86_64 calling_convention;
4265 codegen_->CreateUnresolvedFieldLocationSummary(
4266 instruction, instruction->GetFieldType(), calling_convention);
4267}
4268
4269void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
4270 HUnresolvedStaticFieldSet* instruction) {
4271 FieldAccessCallingConventionX86_64 calling_convention;
4272 codegen_->GenerateUnresolvedFieldAccess(instruction,
4273 instruction->GetFieldType(),
4274 instruction->GetFieldIndex(),
4275 instruction->GetDexPc(),
4276 calling_convention);
4277}
4278
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004279void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004280 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4281 ? LocationSummary::kCallOnSlowPath
4282 : LocationSummary::kNoCall;
4283 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4284 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004285 ? Location::RequiresRegister()
4286 : Location::Any();
4287 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004288 if (instruction->HasUses()) {
4289 locations->SetOut(Location::SameAsFirstInput());
4290 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004291}
4292
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004293void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004294 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4295 return;
4296 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004297 LocationSummary* locations = instruction->GetLocations();
4298 Location obj = locations->InAt(0);
4299
4300 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
4301 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4302}
4303
4304void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004305 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004306 codegen_->AddSlowPath(slow_path);
4307
4308 LocationSummary* locations = instruction->GetLocations();
4309 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004310
4311 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004312 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004313 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004314 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004315 } else {
4316 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004317 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004318 __ jmp(slow_path->GetEntryLabel());
4319 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004320 }
4321 __ j(kEqual, slow_path->GetEntryLabel());
4322}
4323
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004324void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004325 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004326 GenerateImplicitNullCheck(instruction);
4327 } else {
4328 GenerateExplicitNullCheck(instruction);
4329 }
4330}
4331
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004332void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004333 bool object_array_get_with_read_barrier =
4334 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004335 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004336 new (GetGraph()->GetArena()) LocationSummary(instruction,
4337 object_array_get_with_read_barrier ?
4338 LocationSummary::kCallOnSlowPath :
4339 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004340 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004341 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004342 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4343 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4344 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004345 // The output overlaps for an object array get when read barriers
4346 // are enabled: we do not want the move to overwrite the array's
4347 // location, as we need it to emit the read barrier.
4348 locations->SetOut(
4349 Location::RequiresRegister(),
4350 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004351 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004352}
4353
4354void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4355 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004356 Location obj_loc = locations->InAt(0);
4357 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004359 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004360
Roland Levillain4d027112015-07-01 15:41:14 +01004361 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004362 case Primitive::kPrimBoolean: {
4363 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004364 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004365 if (index.IsConstant()) {
4366 __ movzxb(out, Address(obj,
4367 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4368 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004369 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004370 }
4371 break;
4372 }
4373
4374 case Primitive::kPrimByte: {
4375 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004376 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004377 if (index.IsConstant()) {
4378 __ movsxb(out, Address(obj,
4379 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4380 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004381 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004382 }
4383 break;
4384 }
4385
4386 case Primitive::kPrimShort: {
4387 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004388 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004389 if (index.IsConstant()) {
4390 __ movsxw(out, Address(obj,
4391 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4392 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004393 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004394 }
4395 break;
4396 }
4397
4398 case Primitive::kPrimChar: {
4399 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004400 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004401 if (index.IsConstant()) {
4402 __ movzxw(out, Address(obj,
4403 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4404 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004406 }
4407 break;
4408 }
4409
4410 case Primitive::kPrimInt:
4411 case Primitive::kPrimNot: {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004412 static_assert(
4413 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4414 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004415 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004416 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004417 if (index.IsConstant()) {
4418 __ movl(out, Address(obj,
4419 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4420 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004421 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004422 }
4423 break;
4424 }
4425
4426 case Primitive::kPrimLong: {
4427 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004428 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004429 if (index.IsConstant()) {
4430 __ movq(out, Address(obj,
4431 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4432 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004433 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004434 }
4435 break;
4436 }
4437
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004438 case Primitive::kPrimFloat: {
4439 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004440 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004441 if (index.IsConstant()) {
4442 __ movss(out, Address(obj,
4443 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4444 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004445 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004446 }
4447 break;
4448 }
4449
4450 case Primitive::kPrimDouble: {
4451 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004452 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004453 if (index.IsConstant()) {
4454 __ movsd(out, Address(obj,
4455 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4456 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004457 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004458 }
4459 break;
4460 }
4461
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004462 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004463 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004464 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004465 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004466 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004467
4468 if (type == Primitive::kPrimNot) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004469 static_assert(
4470 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4471 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4472 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4473 Location out = locations->Out();
4474 if (index.IsConstant()) {
4475 uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4476 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4477 } else {
4478 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4479 }
Roland Levillain4d027112015-07-01 15:41:14 +01004480 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004481}
4482
4483void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004484 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004485
4486 bool needs_write_barrier =
4487 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004488 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004489 bool object_array_set_with_read_barrier =
4490 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004491
Nicolas Geoffray39468442014-09-02 15:17:15 +01004492 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004493 instruction,
Roland Levillain0d5a2812015-11-13 10:07:31 +00004494 (may_need_runtime_call || object_array_set_with_read_barrier) ?
4495 LocationSummary::kCallOnSlowPath :
4496 LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004497
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004498 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04004499 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4500 if (Primitive::IsFloatingPointType(value_type)) {
4501 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004502 } else {
4503 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4504 }
4505
4506 if (needs_write_barrier) {
4507 // Temporary registers for the write barrier.
Roland Levillain0d5a2812015-11-13 10:07:31 +00004508
4509 // This first temporary register is possibly used for heap
4510 // reference poisoning and/or read barrier emission too.
4511 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004512 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004513 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004514}
4515
4516void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4517 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004518 Location array_loc = locations->InAt(0);
4519 CpuRegister array = array_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004520 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004521 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004522 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004523 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004524 bool needs_write_barrier =
4525 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004526 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4527 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4528 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004529
4530 switch (value_type) {
4531 case Primitive::kPrimBoolean:
4532 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004533 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4534 Address address = index.IsConstant()
4535 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4536 : Address(array, index.AsRegister<CpuRegister>(), TIMES_1, offset);
4537 if (value.IsRegister()) {
4538 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004539 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004540 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004541 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004542 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004543 break;
4544 }
4545
4546 case Primitive::kPrimShort:
4547 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004548 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4549 Address address = index.IsConstant()
4550 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4551 : Address(array, index.AsRegister<CpuRegister>(), TIMES_2, offset);
4552 if (value.IsRegister()) {
4553 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004554 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004555 DCHECK(value.IsConstant()) << value;
4556 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004557 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004558 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004559 break;
4560 }
4561
4562 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004563 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4564 Address address = index.IsConstant()
4565 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4566 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00004567
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004568 if (!value.IsRegister()) {
4569 // Just setting null.
4570 DCHECK(instruction->InputAt(2)->IsNullConstant());
4571 DCHECK(value.IsConstant()) << value;
4572 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004573 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004574 DCHECK(!needs_write_barrier);
4575 DCHECK(!may_need_runtime_call);
4576 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004577 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004578
4579 DCHECK(needs_write_barrier);
4580 CpuRegister register_value = value.AsRegister<CpuRegister>();
4581 NearLabel done, not_null, do_put;
4582 SlowPathCode* slow_path = nullptr;
4583 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4584 if (may_need_runtime_call) {
4585 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4586 codegen_->AddSlowPath(slow_path);
4587 if (instruction->GetValueCanBeNull()) {
4588 __ testl(register_value, register_value);
4589 __ j(kNotEqual, &not_null);
4590 __ movl(address, Immediate(0));
4591 codegen_->MaybeRecordImplicitNullCheck(instruction);
4592 __ jmp(&done);
4593 __ Bind(&not_null);
4594 }
4595
Roland Levillain0d5a2812015-11-13 10:07:31 +00004596 if (kEmitCompilerReadBarrier) {
4597 // When read barriers are enabled, the type checking
4598 // instrumentation requires two read barriers:
4599 //
4600 // __ movl(temp2, temp);
4601 // // /* HeapReference<Class> */ temp = temp->component_type_
4602 // __ movl(temp, Address(temp, component_offset));
4603 // codegen_->GenerateReadBarrier(
4604 // instruction, temp_loc, temp_loc, temp2_loc, component_offset);
4605 //
4606 // // /* HeapReference<Class> */ temp2 = register_value->klass_
4607 // __ movl(temp2, Address(register_value, class_offset));
4608 // codegen_->GenerateReadBarrier(
4609 // instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
4610 //
4611 // __ cmpl(temp, temp2);
4612 //
4613 // However, the second read barrier may trash `temp`, as it
4614 // is a temporary register, and as such would not be saved
4615 // along with live registers before calling the runtime (nor
4616 // restored afterwards). So in this case, we bail out and
4617 // delegate the work to the array set slow path.
4618 //
4619 // TODO: Extend the register allocator to support a new
4620 // "(locally) live temp" location so as to avoid always
4621 // going into the slow path when read barriers are enabled.
4622 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004623 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004624 // /* HeapReference<Class> */ temp = array->klass_
4625 __ movl(temp, Address(array, class_offset));
4626 codegen_->MaybeRecordImplicitNullCheck(instruction);
4627 __ MaybeUnpoisonHeapReference(temp);
4628
4629 // /* HeapReference<Class> */ temp = temp->component_type_
4630 __ movl(temp, Address(temp, component_offset));
4631 // If heap poisoning is enabled, no need to unpoison `temp`
4632 // nor the object reference in `register_value->klass`, as
4633 // we are comparing two poisoned references.
4634 __ cmpl(temp, Address(register_value, class_offset));
4635
4636 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4637 __ j(kEqual, &do_put);
4638 // If heap poisoning is enabled, the `temp` reference has
4639 // not been unpoisoned yet; unpoison it now.
4640 __ MaybeUnpoisonHeapReference(temp);
4641
4642 // /* HeapReference<Class> */ temp = temp->super_class_
4643 __ movl(temp, Address(temp, super_offset));
4644 // If heap poisoning is enabled, no need to unpoison
4645 // `temp`, as we are comparing against null below.
4646 __ testl(temp, temp);
4647 __ j(kNotEqual, slow_path->GetEntryLabel());
4648 __ Bind(&do_put);
4649 } else {
4650 __ j(kNotEqual, slow_path->GetEntryLabel());
4651 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004652 }
4653 }
4654
4655 if (kPoisonHeapReferences) {
4656 __ movl(temp, register_value);
4657 __ PoisonHeapReference(temp);
4658 __ movl(address, temp);
4659 } else {
4660 __ movl(address, register_value);
4661 }
4662 if (!may_need_runtime_call) {
4663 codegen_->MaybeRecordImplicitNullCheck(instruction);
4664 }
4665
4666 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4667 codegen_->MarkGCCard(
4668 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4669 __ Bind(&done);
4670
4671 if (slow_path != nullptr) {
4672 __ Bind(slow_path->GetExitLabel());
4673 }
4674
4675 break;
4676 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00004677
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004678 case Primitive::kPrimInt: {
4679 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4680 Address address = index.IsConstant()
4681 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4682 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4683 if (value.IsRegister()) {
4684 __ movl(address, value.AsRegister<CpuRegister>());
4685 } else {
4686 DCHECK(value.IsConstant()) << value;
4687 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4688 __ movl(address, Immediate(v));
4689 }
4690 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004691 break;
4692 }
4693
4694 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004695 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4696 Address address = index.IsConstant()
4697 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4698 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4699 if (value.IsRegister()) {
4700 __ movq(address, value.AsRegister<CpuRegister>());
Mark Mendellea5af682015-10-22 17:35:49 -04004701 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004702 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004703 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004704 Address address_high = index.IsConstant()
4705 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) +
4706 offset + sizeof(int32_t))
4707 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset + sizeof(int32_t));
4708 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004709 }
4710 break;
4711 }
4712
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004713 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004714 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4715 Address address = index.IsConstant()
4716 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4717 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04004718 if (value.IsFpuRegister()) {
4719 __ movss(address, value.AsFpuRegister<XmmRegister>());
4720 } else {
4721 DCHECK(value.IsConstant());
4722 int32_t v =
4723 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4724 __ movl(address, Immediate(v));
4725 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004726 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004727 break;
4728 }
4729
4730 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004731 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4732 Address address = index.IsConstant()
4733 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4734 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04004735 if (value.IsFpuRegister()) {
4736 __ movsd(address, value.AsFpuRegister<XmmRegister>());
4737 codegen_->MaybeRecordImplicitNullCheck(instruction);
4738 } else {
4739 int64_t v =
4740 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4741 Address address_high = index.IsConstant()
4742 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) +
4743 offset + sizeof(int32_t))
4744 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset + sizeof(int32_t));
4745 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
4746 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004747 break;
4748 }
4749
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004750 case Primitive::kPrimVoid:
4751 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004752 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004753 }
4754}
4755
4756void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004757 LocationSummary* locations =
4758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004759 locations->SetInAt(0, Location::RequiresRegister());
4760 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004761}
4762
4763void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4764 LocationSummary* locations = instruction->GetLocations();
4765 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004766 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4767 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004768 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004769 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004770}
4771
4772void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004773 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4774 ? LocationSummary::kCallOnSlowPath
4775 : LocationSummary::kNoCall;
4776 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004777 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004778 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004779 if (instruction->HasUses()) {
4780 locations->SetOut(Location::SameAsFirstInput());
4781 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004782}
4783
4784void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4785 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004786 Location index_loc = locations->InAt(0);
4787 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004788 SlowPathCode* slow_path =
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004789 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004790
Mark Mendell99dbd682015-04-22 16:18:52 -04004791 if (length_loc.IsConstant()) {
4792 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4793 if (index_loc.IsConstant()) {
4794 // BCE will remove the bounds check if we are guarenteed to pass.
4795 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4796 if (index < 0 || index >= length) {
4797 codegen_->AddSlowPath(slow_path);
4798 __ jmp(slow_path->GetEntryLabel());
4799 } else {
4800 // Some optimization after BCE may have generated this, and we should not
4801 // generate a bounds check if it is a valid range.
4802 }
4803 return;
4804 }
4805
4806 // We have to reverse the jump condition because the length is the constant.
4807 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4808 __ cmpl(index_reg, Immediate(length));
4809 codegen_->AddSlowPath(slow_path);
4810 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004811 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004812 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4813 if (index_loc.IsConstant()) {
4814 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4815 __ cmpl(length, Immediate(value));
4816 } else {
4817 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4818 }
4819 codegen_->AddSlowPath(slow_path);
4820 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004821 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004822}
4823
4824void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4825 CpuRegister card,
4826 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004827 CpuRegister value,
4828 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004829 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004830 if (value_can_be_null) {
4831 __ testl(value, value);
4832 __ j(kEqual, &is_null);
4833 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004834 __ gs()->movq(card, Address::Absolute(
4835 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4836 __ movq(temp, object);
4837 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004838 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004839 if (value_can_be_null) {
4840 __ Bind(&is_null);
4841 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004842}
4843
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004844void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4845 temp->SetLocations(nullptr);
4846}
4847
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004848void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004849 // Nothing to do, this is driven by the code generator.
4850}
4851
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004852void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004853 LOG(FATAL) << "Unimplemented";
4854}
4855
4856void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004857 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4858}
4859
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004860void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4861 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4862}
4863
4864void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004865 HBasicBlock* block = instruction->GetBlock();
4866 if (block->GetLoopInformation() != nullptr) {
4867 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4868 // The back edge will generate the suspend check.
4869 return;
4870 }
4871 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4872 // The goto will generate the suspend check.
4873 return;
4874 }
4875 GenerateSuspendCheck(instruction, nullptr);
4876}
4877
4878void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4879 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004880 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004881 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4882 if (slow_path == nullptr) {
4883 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4884 instruction->SetSlowPath(slow_path);
4885 codegen_->AddSlowPath(slow_path);
4886 if (successor != nullptr) {
4887 DCHECK(successor->IsLoopHeader());
4888 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4889 }
4890 } else {
4891 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4892 }
4893
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004894 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004895 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004896 if (successor == nullptr) {
4897 __ j(kNotEqual, slow_path->GetEntryLabel());
4898 __ Bind(slow_path->GetReturnLabel());
4899 } else {
4900 __ j(kEqual, codegen_->GetLabelOf(successor));
4901 __ jmp(slow_path->GetEntryLabel());
4902 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004903}
4904
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004905X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4906 return codegen_->GetAssembler();
4907}
4908
4909void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004910 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004911 Location source = move->GetSource();
4912 Location destination = move->GetDestination();
4913
4914 if (source.IsRegister()) {
4915 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004916 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004917 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004918 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004919 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004920 } else {
4921 DCHECK(destination.IsDoubleStackSlot());
4922 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004923 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004924 }
4925 } else if (source.IsStackSlot()) {
4926 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004927 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004928 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004929 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004930 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004931 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004932 } else {
4933 DCHECK(destination.IsStackSlot());
4934 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4935 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4936 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004937 } else if (source.IsDoubleStackSlot()) {
4938 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004939 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004940 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004941 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004942 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4943 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004944 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004945 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004946 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4947 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4948 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004949 } else if (source.IsConstant()) {
4950 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004951 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4952 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004953 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004954 if (value == 0) {
4955 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4956 } else {
4957 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4958 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004959 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004960 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004961 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004962 }
4963 } else if (constant->IsLongConstant()) {
4964 int64_t value = constant->AsLongConstant()->GetValue();
4965 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004966 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004967 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004968 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004969 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004970 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004971 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004972 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004973 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004974 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004975 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4976 if (value == 0) {
4977 // easy FP 0.0.
4978 __ xorps(dest, dest);
4979 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004980 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004981 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004982 } else {
4983 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004984 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004985 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4986 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004987 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004988 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004989 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004990 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004991 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004992 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4993 if (value == 0) {
4994 __ xorpd(dest, dest);
4995 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004996 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004997 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004998 } else {
4999 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005000 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005001 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005002 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005003 } else if (source.IsFpuRegister()) {
5004 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005005 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005006 } else if (destination.IsStackSlot()) {
5007 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005008 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005009 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00005010 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005011 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005012 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005013 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005014 }
5015}
5016
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005017void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005018 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005019 __ movl(Address(CpuRegister(RSP), mem), reg);
5020 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005021}
5022
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005023void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005024 ScratchRegisterScope ensure_scratch(
5025 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5026
5027 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5028 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5029 __ movl(CpuRegister(ensure_scratch.GetRegister()),
5030 Address(CpuRegister(RSP), mem2 + stack_offset));
5031 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5032 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
5033 CpuRegister(ensure_scratch.GetRegister()));
5034}
5035
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005036void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
5037 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5038 __ movq(Address(CpuRegister(RSP), mem), reg);
5039 __ movq(reg, CpuRegister(TMP));
5040}
5041
5042void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
5043 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005044 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005045
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005046 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5047 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5048 __ movq(CpuRegister(ensure_scratch.GetRegister()),
5049 Address(CpuRegister(RSP), mem2 + stack_offset));
5050 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5051 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
5052 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005053}
5054
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005055void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
5056 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5057 __ movss(Address(CpuRegister(RSP), mem), reg);
5058 __ movd(reg, CpuRegister(TMP));
5059}
5060
5061void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
5062 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5063 __ movsd(Address(CpuRegister(RSP), mem), reg);
5064 __ movd(reg, CpuRegister(TMP));
5065}
5066
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005067void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005068 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005069 Location source = move->GetSource();
5070 Location destination = move->GetDestination();
5071
5072 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005073 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005074 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005075 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005076 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005077 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005078 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005079 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
5080 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005081 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005082 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005083 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005084 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5085 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005086 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005087 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
5088 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5089 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005090 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005091 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005092 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005093 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005094 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005095 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005096 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005097 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005098 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005099 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005100 }
5101}
5102
5103
5104void ParallelMoveResolverX86_64::SpillScratch(int reg) {
5105 __ pushq(CpuRegister(reg));
5106}
5107
5108
5109void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
5110 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005111}
5112
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005113void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005114 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005115 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5116 Immediate(mirror::Class::kStatusInitialized));
5117 __ j(kLess, slow_path->GetEntryLabel());
5118 __ Bind(slow_path->GetExitLabel());
5119 // No need for memory fence, thanks to the X86_64 memory model.
5120}
5121
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005122void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005123 InvokeRuntimeCallingConvention calling_convention;
5124 CodeGenerator::CreateLoadClassLocationSummary(
5125 cls,
5126 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain0d5a2812015-11-13 10:07:31 +00005127 Location::RegisterLocation(RAX),
5128 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005129}
5130
5131void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005132 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005133 if (cls->NeedsAccessCheck()) {
5134 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5135 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5136 cls,
5137 cls->GetDexPc(),
5138 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005139 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005140 return;
5141 }
5142
Roland Levillain0d5a2812015-11-13 10:07:31 +00005143 Location out_loc = locations->Out();
5144 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Calin Juravle580b6092015-10-06 17:35:58 +01005145 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005146
Calin Juravle580b6092015-10-06 17:35:58 +01005147 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005148 DCHECK(!cls->CanCallRuntime());
5149 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005150 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5151 if (kEmitCompilerReadBarrier) {
5152 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5153 __ leaq(out, Address(current_method, declaring_class_offset));
5154 // /* mirror::Class* */ out = out->Read()
5155 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5156 } else {
5157 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5158 __ movl(out, Address(current_method, declaring_class_offset));
5159 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005160 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005161 DCHECK(cls->CanCallRuntime());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005162 // /* GcRoot<mirror::Class>[] */ out =
5163 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
5164 __ movq(out, Address(current_method,
5165 ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
5166
5167 size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5168 if (kEmitCompilerReadBarrier) {
5169 // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5170 __ leaq(out, Address(out, cache_offset));
5171 // /* mirror::Class* */ out = out->Read()
5172 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5173 } else {
5174 // /* GcRoot<mirror::Class> */ out = out[type_index]
5175 __ movl(out, Address(out, cache_offset));
5176 }
Roland Levillain4d027112015-07-01 15:41:14 +01005177
Andreas Gampe85b62f22015-09-09 13:15:38 -07005178 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005179 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5180 codegen_->AddSlowPath(slow_path);
5181 __ testl(out, out);
5182 __ j(kEqual, slow_path->GetEntryLabel());
5183 if (cls->MustGenerateClinitCheck()) {
5184 GenerateClassInitializationCheck(slow_path, out);
5185 } else {
5186 __ Bind(slow_path->GetExitLabel());
5187 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005188 }
5189}
5190
5191void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
5192 LocationSummary* locations =
5193 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5194 locations->SetInAt(0, Location::RequiresRegister());
5195 if (check->HasUses()) {
5196 locations->SetOut(Location::SameAsFirstInput());
5197 }
5198}
5199
5200void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005201 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005202 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005203 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005204 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005205 GenerateClassInitializationCheck(slow_path,
5206 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005207}
5208
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005209void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
5210 LocationSummary* locations =
5211 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005212 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005213 locations->SetOut(Location::RequiresRegister());
5214}
5215
5216void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005217 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005218 codegen_->AddSlowPath(slow_path);
5219
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005220 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005221 Location out_loc = locations->Out();
5222 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005223 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005224
5225 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5226 if (kEmitCompilerReadBarrier) {
5227 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5228 __ leaq(out, Address(current_method, declaring_class_offset));
5229 // /* mirror::Class* */ out = out->Read()
5230 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5231 } else {
5232 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5233 __ movl(out, Address(current_method, declaring_class_offset));
5234 }
5235
5236 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5237 __ movq(out, Address(out, mirror::Class::DexCacheStringsOffset().Uint32Value()));
5238
5239 size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5240 if (kEmitCompilerReadBarrier) {
5241 // /* GcRoot<mirror::String>* */ out = &out[string_index]
5242 __ leaq(out, Address(out, cache_offset));
5243 // /* mirror::String* */ out = out->Read()
5244 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5245 } else {
5246 // /* GcRoot<mirror::String> */ out = out[string_index]
5247 __ movl(out, Address(out, cache_offset));
5248 }
5249
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005250 __ testl(out, out);
5251 __ j(kEqual, slow_path->GetEntryLabel());
5252 __ Bind(slow_path->GetExitLabel());
5253}
5254
David Brazdilcb1c0552015-08-04 16:22:25 +01005255static Address GetExceptionTlsAddress() {
5256 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
5257}
5258
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005259void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
5260 LocationSummary* locations =
5261 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5262 locations->SetOut(Location::RequiresRegister());
5263}
5264
5265void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005266 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
5267}
5268
5269void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
5270 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5271}
5272
5273void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5274 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005275}
5276
5277void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
5278 LocationSummary* locations =
5279 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5280 InvokeRuntimeCallingConvention calling_convention;
5281 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5282}
5283
5284void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005285 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5286 instruction,
5287 instruction->GetDexPc(),
5288 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005289 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005290}
5291
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005292void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005293 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005294 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5295 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005296 case TypeCheckKind::kExactCheck:
5297 case TypeCheckKind::kAbstractClassCheck:
5298 case TypeCheckKind::kClassHierarchyCheck:
5299 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005300 call_kind =
5301 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005302 break;
5303 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005304 case TypeCheckKind::kUnresolvedCheck:
5305 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005306 call_kind = LocationSummary::kCallOnSlowPath;
5307 break;
5308 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005309
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005310 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005311 locations->SetInAt(0, Location::RequiresRegister());
5312 locations->SetInAt(1, Location::Any());
5313 // Note that TypeCheckSlowPathX86_64 uses this "out" register too.
5314 locations->SetOut(Location::RequiresRegister());
5315 // When read barriers are enabled, we need a temporary register for
5316 // some cases.
5317 if (kEmitCompilerReadBarrier &&
5318 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5319 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5320 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5321 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005322 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005323}
5324
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005325void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005326 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005327 Location obj_loc = locations->InAt(0);
5328 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005329 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005330 Location out_loc = locations->Out();
5331 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005332 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005333 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5334 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5335 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005336 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005337 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005338
5339 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005340 // Avoid null check if we know obj is not null.
5341 if (instruction->MustDoNullCheck()) {
5342 __ testl(obj, obj);
5343 __ j(kEqual, &zero);
5344 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005345
Roland Levillain0d5a2812015-11-13 10:07:31 +00005346 // /* HeapReference<Class> */ out = obj->klass_
5347 __ movl(out, Address(obj, class_offset));
5348 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005349
5350 switch (instruction->GetTypeCheckKind()) {
5351 case TypeCheckKind::kExactCheck: {
5352 if (cls.IsRegister()) {
5353 __ cmpl(out, cls.AsRegister<CpuRegister>());
5354 } else {
5355 DCHECK(cls.IsStackSlot()) << cls;
5356 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5357 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005358 if (zero.IsLinked()) {
5359 // Classes must be equal for the instanceof to succeed.
5360 __ j(kNotEqual, &zero);
5361 __ movl(out, Immediate(1));
5362 __ jmp(&done);
5363 } else {
5364 __ setcc(kEqual, out);
5365 // setcc only sets the low byte.
5366 __ andl(out, Immediate(1));
5367 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005368 break;
5369 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005370
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005371 case TypeCheckKind::kAbstractClassCheck: {
5372 // If the class is abstract, we eagerly fetch the super class of the
5373 // object to avoid doing a comparison we know will fail.
5374 NearLabel loop, success;
5375 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005376 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5377 if (kEmitCompilerReadBarrier) {
5378 // Save the value of `out` into `temp` before overwriting it
5379 // in the following move operation, as we will need it for the
5380 // read barrier below.
5381 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5382 __ movl(temp, out);
5383 }
5384 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005385 __ movl(out, Address(out, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005386 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005387 __ testl(out, out);
5388 // If `out` is null, we use it for the result, and jump to `done`.
5389 __ j(kEqual, &done);
5390 if (cls.IsRegister()) {
5391 __ cmpl(out, cls.AsRegister<CpuRegister>());
5392 } else {
5393 DCHECK(cls.IsStackSlot()) << cls;
5394 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5395 }
5396 __ j(kNotEqual, &loop);
5397 __ movl(out, Immediate(1));
5398 if (zero.IsLinked()) {
5399 __ jmp(&done);
5400 }
5401 break;
5402 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005403
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005404 case TypeCheckKind::kClassHierarchyCheck: {
5405 // Walk over the class hierarchy to find a match.
5406 NearLabel loop, success;
5407 __ Bind(&loop);
5408 if (cls.IsRegister()) {
5409 __ cmpl(out, cls.AsRegister<CpuRegister>());
5410 } else {
5411 DCHECK(cls.IsStackSlot()) << cls;
5412 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5413 }
5414 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005415 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5416 if (kEmitCompilerReadBarrier) {
5417 // Save the value of `out` into `temp` before overwriting it
5418 // in the following move operation, as we will need it for the
5419 // read barrier below.
5420 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5421 __ movl(temp, out);
5422 }
5423 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005424 __ movl(out, Address(out, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005425 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005426 __ testl(out, out);
5427 __ j(kNotEqual, &loop);
5428 // If `out` is null, we use it for the result, and jump to `done`.
5429 __ jmp(&done);
5430 __ Bind(&success);
5431 __ movl(out, Immediate(1));
5432 if (zero.IsLinked()) {
5433 __ jmp(&done);
5434 }
5435 break;
5436 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005437
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005438 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005439 // Do an exact check.
5440 NearLabel exact_check;
5441 if (cls.IsRegister()) {
5442 __ cmpl(out, cls.AsRegister<CpuRegister>());
5443 } else {
5444 DCHECK(cls.IsStackSlot()) << cls;
5445 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5446 }
5447 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005448 // Otherwise, we need to check that the object's class is a non-primitive array.
5449 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5450 if (kEmitCompilerReadBarrier) {
5451 // Save the value of `out` into `temp` before overwriting it
5452 // in the following move operation, as we will need it for the
5453 // read barrier below.
5454 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5455 __ movl(temp, out);
5456 }
5457 // /* HeapReference<Class> */ out = out->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005458 __ movl(out, Address(out, component_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005459 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005460 __ testl(out, out);
5461 // If `out` is null, we use it for the result, and jump to `done`.
5462 __ j(kEqual, &done);
5463 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5464 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005465 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005466 __ movl(out, Immediate(1));
5467 __ jmp(&done);
5468 break;
5469 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005470
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005471 case TypeCheckKind::kArrayCheck: {
5472 if (cls.IsRegister()) {
5473 __ cmpl(out, cls.AsRegister<CpuRegister>());
5474 } else {
5475 DCHECK(cls.IsStackSlot()) << cls;
5476 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5477 }
5478 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005479 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5480 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005481 codegen_->AddSlowPath(slow_path);
5482 __ j(kNotEqual, slow_path->GetEntryLabel());
5483 __ movl(out, Immediate(1));
5484 if (zero.IsLinked()) {
5485 __ jmp(&done);
5486 }
5487 break;
5488 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005489
Calin Juravle98893e12015-10-02 21:05:03 +01005490 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005491 case TypeCheckKind::kInterfaceCheck: {
5492 // Note that we indeed only call on slow path, but we always go
5493 // into the slow path for the unresolved & interface check
5494 // cases.
5495 //
5496 // We cannot directly call the InstanceofNonTrivial runtime
5497 // entry point without resorting to a type checking slow path
5498 // here (i.e. by calling InvokeRuntime directly), as it would
5499 // require to assign fixed registers for the inputs of this
5500 // HInstanceOf instruction (following the runtime calling
5501 // convention), which might be cluttered by the potential first
5502 // read barrier emission at the beginning of this method.
5503 DCHECK(locations->OnlyCallsOnSlowPath());
5504 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5505 /* is_fatal */ false);
5506 codegen_->AddSlowPath(slow_path);
5507 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005508 if (zero.IsLinked()) {
5509 __ jmp(&done);
5510 }
5511 break;
5512 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005513 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005514
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005515 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005516 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005517 __ xorl(out, out);
5518 }
5519
5520 if (done.IsLinked()) {
5521 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005522 }
5523
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005524 if (slow_path != nullptr) {
5525 __ Bind(slow_path->GetExitLabel());
5526 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005527}
5528
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005529void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005530 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5531 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005532 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5533 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005534 case TypeCheckKind::kExactCheck:
5535 case TypeCheckKind::kAbstractClassCheck:
5536 case TypeCheckKind::kClassHierarchyCheck:
5537 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005538 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5539 LocationSummary::kCallOnSlowPath :
5540 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005541 break;
5542 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005543 case TypeCheckKind::kUnresolvedCheck:
5544 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005545 call_kind = LocationSummary::kCallOnSlowPath;
5546 break;
5547 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005548 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5549 locations->SetInAt(0, Location::RequiresRegister());
5550 locations->SetInAt(1, Location::Any());
5551 // Note that TypeCheckSlowPathX86_64 uses this "temp" register too.
5552 locations->AddTemp(Location::RequiresRegister());
5553 // When read barriers are enabled, we need an additional temporary
5554 // register for some cases.
5555 if (kEmitCompilerReadBarrier &&
5556 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5557 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5558 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005559 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005560 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005561}
5562
5563void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
5564 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005565 Location obj_loc = locations->InAt(0);
5566 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005567 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005568 Location temp_loc = locations->GetTemp(0);
5569 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005570 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5571 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5572 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5573 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005574
Roland Levillain0d5a2812015-11-13 10:07:31 +00005575 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5576 bool is_type_check_slow_path_fatal =
5577 (type_check_kind == TypeCheckKind::kExactCheck ||
5578 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5579 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5580 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5581 !instruction->CanThrowIntoCatchBlock();
5582 SlowPathCode* type_check_slow_path =
5583 new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5584 is_type_check_slow_path_fatal);
5585 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005586
5587 NearLabel done;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005588 // Avoid null check if we know obj is not null.
5589 if (instruction->MustDoNullCheck()) {
5590 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005591 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005592 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005593
Roland Levillain0d5a2812015-11-13 10:07:31 +00005594 // /* HeapReference<Class> */ temp = obj->klass_
5595 __ movl(temp, Address(obj, class_offset));
5596 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005597
Roland Levillain0d5a2812015-11-13 10:07:31 +00005598 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005599 case TypeCheckKind::kExactCheck:
5600 case TypeCheckKind::kArrayCheck: {
5601 if (cls.IsRegister()) {
5602 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5603 } else {
5604 DCHECK(cls.IsStackSlot()) << cls;
5605 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5606 }
5607 // Jump to slow path for throwing the exception or doing a
5608 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005609 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005610 break;
5611 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005612
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005613 case TypeCheckKind::kAbstractClassCheck: {
5614 // If the class is abstract, we eagerly fetch the super class of the
5615 // object to avoid doing a comparison we know will fail.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005616 NearLabel loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005617 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005618 Location temp2_loc =
5619 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5620 if (kEmitCompilerReadBarrier) {
5621 // Save the value of `temp` into `temp2` before overwriting it
5622 // in the following move operation, as we will need it for the
5623 // read barrier below.
5624 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5625 __ movl(temp2, temp);
5626 }
5627 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005628 __ movl(temp, Address(temp, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005629 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5630
5631 // If the class reference currently in `temp` is not null, jump
5632 // to the `compare_classes` label to compare it with the checked
5633 // class.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005634 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005635 __ j(kNotEqual, &compare_classes);
5636 // Otherwise, jump to the slow path to throw the exception.
5637 //
5638 // But before, move back the object's class into `temp` before
5639 // going into the slow path, as it has been overwritten in the
5640 // meantime.
5641 // /* HeapReference<Class> */ temp = obj->klass_
5642 __ movl(temp, Address(obj, class_offset));
5643 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5644 __ jmp(type_check_slow_path->GetEntryLabel());
5645
5646 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005647 if (cls.IsRegister()) {
5648 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5649 } else {
5650 DCHECK(cls.IsStackSlot()) << cls;
5651 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5652 }
5653 __ j(kNotEqual, &loop);
5654 break;
5655 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005656
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005657 case TypeCheckKind::kClassHierarchyCheck: {
5658 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005659 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005660 __ Bind(&loop);
5661 if (cls.IsRegister()) {
5662 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5663 } else {
5664 DCHECK(cls.IsStackSlot()) << cls;
5665 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5666 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005667 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005668
5669 Location temp2_loc =
5670 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5671 if (kEmitCompilerReadBarrier) {
5672 // Save the value of `temp` into `temp2` before overwriting it
5673 // in the following move operation, as we will need it for the
5674 // read barrier below.
5675 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5676 __ movl(temp2, temp);
5677 }
5678 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005679 __ movl(temp, Address(temp, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005680 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5681
5682 // If the class reference currently in `temp` is not null, jump
5683 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005684 __ testl(temp, temp);
5685 __ j(kNotEqual, &loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005686 // Otherwise, jump to the slow path to throw the exception.
5687 //
5688 // But before, move back the object's class into `temp` before
5689 // going into the slow path, as it has been overwritten in the
5690 // meantime.
5691 // /* HeapReference<Class> */ temp = obj->klass_
5692 __ movl(temp, Address(obj, class_offset));
5693 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5694 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005695 break;
5696 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005697
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005698 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005699 // Do an exact check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005700 NearLabel check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005701 if (cls.IsRegister()) {
5702 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5703 } else {
5704 DCHECK(cls.IsStackSlot()) << cls;
5705 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5706 }
5707 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005708
5709 // Otherwise, we need to check that the object's class is a non-primitive array.
5710 Location temp2_loc =
5711 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5712 if (kEmitCompilerReadBarrier) {
5713 // Save the value of `temp` into `temp2` before overwriting it
5714 // in the following move operation, as we will need it for the
5715 // read barrier below.
5716 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5717 __ movl(temp2, temp);
5718 }
5719 // /* HeapReference<Class> */ temp = temp->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005720 __ movl(temp, Address(temp, component_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005721 codegen_->MaybeGenerateReadBarrier(
5722 instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5723
5724 // If the component type is not null (i.e. the object is indeed
5725 // an array), jump to label `check_non_primitive_component_type`
5726 // to further check that this component type is not a primitive
5727 // type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005728 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005729 __ j(kNotEqual, &check_non_primitive_component_type);
5730 // Otherwise, jump to the slow path to throw the exception.
5731 //
5732 // But before, move back the object's class into `temp` before
5733 // going into the slow path, as it has been overwritten in the
5734 // meantime.
5735 // /* HeapReference<Class> */ temp = obj->klass_
5736 __ movl(temp, Address(obj, class_offset));
5737 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5738 __ jmp(type_check_slow_path->GetEntryLabel());
5739
5740 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005741 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005742 __ j(kEqual, &done);
5743 // Same comment as above regarding `temp` and the slow path.
5744 // /* HeapReference<Class> */ temp = obj->klass_
5745 __ movl(temp, Address(obj, class_offset));
5746 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5747 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005748 break;
5749 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005750
Calin Juravle98893e12015-10-02 21:05:03 +01005751 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005752 case TypeCheckKind::kInterfaceCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005753 // We always go into the type check slow path for the unresolved &
5754 // interface check cases.
5755 //
5756 // We cannot directly call the CheckCast runtime entry point
5757 // without resorting to a type checking slow path here (i.e. by
5758 // calling InvokeRuntime directly), as it would require to
5759 // assign fixed registers for the inputs of this HInstanceOf
5760 // instruction (following the runtime calling convention), which
5761 // might be cluttered by the potential first read barrier
5762 // emission at the beginning of this method.
5763 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005764 break;
5765 }
5766 __ Bind(&done);
5767
Roland Levillain0d5a2812015-11-13 10:07:31 +00005768 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005769}
5770
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005771void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
5772 LocationSummary* locations =
5773 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5774 InvokeRuntimeCallingConvention calling_convention;
5775 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5776}
5777
5778void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005779 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5780 : QUICK_ENTRY_POINT(pUnlockObject),
5781 instruction,
5782 instruction->GetDexPc(),
5783 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005784 if (instruction->IsEnter()) {
5785 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5786 } else {
5787 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5788 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005789}
5790
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005791void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5792void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5793void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5794
5795void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5796 LocationSummary* locations =
5797 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5798 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5799 || instruction->GetResultType() == Primitive::kPrimLong);
5800 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04005801 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005802 locations->SetOut(Location::SameAsFirstInput());
5803}
5804
5805void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
5806 HandleBitwiseOperation(instruction);
5807}
5808
5809void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
5810 HandleBitwiseOperation(instruction);
5811}
5812
5813void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
5814 HandleBitwiseOperation(instruction);
5815}
5816
5817void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5818 LocationSummary* locations = instruction->GetLocations();
5819 Location first = locations->InAt(0);
5820 Location second = locations->InAt(1);
5821 DCHECK(first.Equals(locations->Out()));
5822
5823 if (instruction->GetResultType() == Primitive::kPrimInt) {
5824 if (second.IsRegister()) {
5825 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005826 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005827 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005828 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005829 } else {
5830 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005831 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005832 }
5833 } else if (second.IsConstant()) {
5834 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
5835 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005836 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005837 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005838 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005839 } else {
5840 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005841 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005842 }
5843 } else {
5844 Address address(CpuRegister(RSP), second.GetStackIndex());
5845 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005846 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005847 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005848 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005849 } else {
5850 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005851 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005852 }
5853 }
5854 } else {
5855 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005856 CpuRegister first_reg = first.AsRegister<CpuRegister>();
5857 bool second_is_constant = false;
5858 int64_t value = 0;
5859 if (second.IsConstant()) {
5860 second_is_constant = true;
5861 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005862 }
Mark Mendell40741f32015-04-20 22:10:34 -04005863 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005864
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005865 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005866 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005867 if (is_int32_value) {
5868 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
5869 } else {
5870 __ andq(first_reg, codegen_->LiteralInt64Address(value));
5871 }
5872 } else if (second.IsDoubleStackSlot()) {
5873 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005874 } else {
5875 __ andq(first_reg, second.AsRegister<CpuRegister>());
5876 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005877 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005878 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005879 if (is_int32_value) {
5880 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
5881 } else {
5882 __ orq(first_reg, codegen_->LiteralInt64Address(value));
5883 }
5884 } else if (second.IsDoubleStackSlot()) {
5885 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005886 } else {
5887 __ orq(first_reg, second.AsRegister<CpuRegister>());
5888 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005889 } else {
5890 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005891 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005892 if (is_int32_value) {
5893 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
5894 } else {
5895 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
5896 }
5897 } else if (second.IsDoubleStackSlot()) {
5898 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005899 } else {
5900 __ xorq(first_reg, second.AsRegister<CpuRegister>());
5901 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005902 }
5903 }
5904}
5905
Roland Levillain0d5a2812015-11-13 10:07:31 +00005906void CodeGeneratorX86_64::GenerateReadBarrier(HInstruction* instruction,
5907 Location out,
5908 Location ref,
5909 Location obj,
5910 uint32_t offset,
5911 Location index) {
5912 DCHECK(kEmitCompilerReadBarrier);
5913
5914 // If heap poisoning is enabled, the unpoisoning of the loaded
5915 // reference will be carried out by the runtime within the slow
5916 // path.
5917 //
5918 // Note that `ref` currently does not get unpoisoned (when heap
5919 // poisoning is enabled), which is alright as the `ref` argument is
5920 // not used by the artReadBarrierSlow entry point.
5921 //
5922 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5923 SlowPathCode* slow_path = new (GetGraph()->GetArena())
5924 ReadBarrierForHeapReferenceSlowPathX86_64(instruction, out, ref, obj, offset, index);
5925 AddSlowPath(slow_path);
5926
5927 // TODO: When read barrier has a fast path, add it here.
5928 /* Currently the read barrier call is inserted after the original load.
5929 * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5930 * original load. This load-load ordering is required by the read barrier.
5931 * The fast path/slow path (for Baker's algorithm) should look like:
5932 *
5933 * bool isGray = obj.LockWord & kReadBarrierMask;
5934 * lfence; // load fence or artificial data dependence to prevent load-load reordering
5935 * ref = obj.field; // this is the original load
5936 * if (isGray) {
5937 * ref = Mark(ref); // ideally the slow path just does Mark(ref)
5938 * }
5939 */
5940
5941 __ jmp(slow_path->GetEntryLabel());
5942 __ Bind(slow_path->GetExitLabel());
5943}
5944
5945void CodeGeneratorX86_64::MaybeGenerateReadBarrier(HInstruction* instruction,
5946 Location out,
5947 Location ref,
5948 Location obj,
5949 uint32_t offset,
5950 Location index) {
5951 if (kEmitCompilerReadBarrier) {
5952 // If heap poisoning is enabled, unpoisoning will be taken care of
5953 // by the runtime within the slow path.
5954 GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5955 } else if (kPoisonHeapReferences) {
5956 __ UnpoisonHeapReference(out.AsRegister<CpuRegister>());
5957 }
5958}
5959
5960void CodeGeneratorX86_64::GenerateReadBarrierForRoot(HInstruction* instruction,
5961 Location out,
5962 Location root) {
5963 DCHECK(kEmitCompilerReadBarrier);
5964
5965 // Note that GC roots are not affected by heap poisoning, so we do
5966 // not need to do anything special for this here.
5967 SlowPathCode* slow_path =
5968 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathX86_64(instruction, out, root);
5969 AddSlowPath(slow_path);
5970
5971 // TODO: Implement a fast path for ReadBarrierForRoot, performing
5972 // the following operation (for Baker's algorithm):
5973 //
5974 // if (thread.tls32_.is_gc_marking) {
5975 // root = Mark(root);
5976 // }
5977
5978 __ jmp(slow_path->GetEntryLabel());
5979 __ Bind(slow_path->GetExitLabel());
5980}
5981
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005982void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005983 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005984 LOG(FATAL) << "Unreachable";
5985}
5986
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005987void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005988 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005989 LOG(FATAL) << "Unreachable";
5990}
5991
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005992void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
5993 DCHECK(codegen_->IsBaseline());
5994 LocationSummary* locations =
5995 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5996 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5997}
5998
5999void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6000 DCHECK(codegen_->IsBaseline());
6001 // Will be generated at use site.
6002}
6003
Mark Mendellfe57faa2015-09-18 09:26:15 -04006004// Simple implementation of packed switch - generate cascaded compare/jumps.
6005void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6006 LocationSummary* locations =
6007 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6008 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04006009 locations->AddTemp(Location::RequiresRegister());
6010 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04006011}
6012
6013void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6014 int32_t lower_bound = switch_instr->GetStartValue();
6015 int32_t num_entries = switch_instr->GetNumEntries();
6016 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04006017 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
6018 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
6019 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
6020
6021 // Remove the bias, if needed.
6022 Register value_reg_out = value_reg_in.AsRegister();
6023 if (lower_bound != 0) {
6024 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
6025 value_reg_out = temp_reg.AsRegister();
6026 }
6027 CpuRegister value_reg(value_reg_out);
6028
6029 // Is the value in range?
Mark Mendellfe57faa2015-09-18 09:26:15 -04006030 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
Mark Mendell9c86b482015-09-18 13:36:07 -04006031 __ cmpl(value_reg, Immediate(num_entries - 1));
6032 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006033
Mark Mendell9c86b482015-09-18 13:36:07 -04006034 // We are in the range of the table.
6035 // Load the address of the jump table in the constant area.
6036 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006037
Mark Mendell9c86b482015-09-18 13:36:07 -04006038 // Load the (signed) offset from the jump table.
6039 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
6040
6041 // Add the offset to the address of the table base.
6042 __ addq(temp_reg, base_reg);
6043
6044 // And jump.
6045 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006046}
6047
Mark Mendell92e83bf2015-05-07 11:25:03 -04006048void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
6049 if (value == 0) {
6050 __ xorl(dest, dest);
6051 } else if (value > 0 && IsInt<32>(value)) {
6052 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
6053 __ movl(dest, Immediate(static_cast<int32_t>(value)));
6054 } else {
6055 __ movq(dest, Immediate(value));
6056 }
6057}
6058
Mark Mendellcfa410b2015-05-25 16:02:44 -04006059void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
6060 DCHECK(dest.IsDoubleStackSlot());
6061 if (IsInt<32>(value)) {
6062 // Can move directly as an int32 constant.
6063 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
6064 Immediate(static_cast<int32_t>(value)));
6065 } else {
6066 Load64BitValue(CpuRegister(TMP), value);
6067 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
6068 }
6069}
6070
Mark Mendell9c86b482015-09-18 13:36:07 -04006071/**
6072 * Class to handle late fixup of offsets into constant area.
6073 */
6074class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
6075 public:
6076 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
6077 : codegen_(&codegen), offset_into_constant_area_(offset) {}
6078
6079 protected:
6080 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
6081
6082 CodeGeneratorX86_64* codegen_;
6083
6084 private:
6085 void Process(const MemoryRegion& region, int pos) OVERRIDE {
6086 // Patch the correct offset for the instruction. We use the address of the
6087 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
6088 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
6089 int32_t relative_position = constant_offset - pos;
6090
6091 // Patch in the right value.
6092 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
6093 }
6094
6095 // Location in constant area that the fixup refers to.
6096 size_t offset_into_constant_area_;
6097};
6098
6099/**
6100 t * Class to handle late fixup of offsets to a jump table that will be created in the
6101 * constant area.
6102 */
6103class JumpTableRIPFixup : public RIPFixup {
6104 public:
6105 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
6106 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
6107
6108 void CreateJumpTable() {
6109 X86_64Assembler* assembler = codegen_->GetAssembler();
6110
6111 // Ensure that the reference to the jump table has the correct offset.
6112 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
6113 SetOffset(offset_in_constant_table);
6114
6115 // Compute the offset from the start of the function to this jump table.
6116 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
6117
6118 // Populate the jump table with the correct values for the jump table.
6119 int32_t num_entries = switch_instr_->GetNumEntries();
6120 HBasicBlock* block = switch_instr_->GetBlock();
6121 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
6122 // The value that we want is the target offset - the position of the table.
6123 for (int32_t i = 0; i < num_entries; i++) {
6124 HBasicBlock* b = successors[i];
6125 Label* l = codegen_->GetLabelOf(b);
6126 DCHECK(l->IsBound());
6127 int32_t offset_to_block = l->Position() - current_table_offset;
6128 assembler->AppendInt32(offset_to_block);
6129 }
6130 }
6131
6132 private:
6133 const HPackedSwitch* switch_instr_;
6134};
6135
Mark Mendellf55c3e02015-03-26 21:07:46 -04006136void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
6137 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04006138 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04006139 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
6140 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8 byte values.
Mark Mendell39dcf552015-04-09 20:42:42 -04006141 assembler->Align(4, 0);
6142 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04006143
6144 // Populate any jump tables.
6145 for (auto jump_table : fixups_to_jump_tables_) {
6146 jump_table->CreateJumpTable();
6147 }
6148
6149 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04006150 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04006151 }
6152
6153 // And finish up.
6154 CodeGenerator::Finalize(allocator);
6155}
6156
Mark Mendellf55c3e02015-03-26 21:07:46 -04006157Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
6158 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
6159 return Address::RIP(fixup);
6160}
6161
6162Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
6163 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
6164 return Address::RIP(fixup);
6165}
6166
6167Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
6168 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
6169 return Address::RIP(fixup);
6170}
6171
6172Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
6173 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
6174 return Address::RIP(fixup);
6175}
6176
Andreas Gampe85b62f22015-09-09 13:15:38 -07006177// TODO: trg as memory.
6178void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6179 if (!trg.IsValid()) {
6180 DCHECK(type == Primitive::kPrimVoid);
6181 return;
6182 }
6183
6184 DCHECK_NE(type, Primitive::kPrimVoid);
6185
6186 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
6187 if (trg.Equals(return_loc)) {
6188 return;
6189 }
6190
6191 // Let the parallel move resolver take care of all of this.
6192 HParallelMove parallel_move(GetGraph()->GetArena());
6193 parallel_move.AddMove(return_loc, trg, type, nullptr);
6194 GetMoveResolver()->EmitNativeCode(&parallel_move);
6195}
6196
Mark Mendell9c86b482015-09-18 13:36:07 -04006197Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
6198 // Create a fixup to be used to create and address the jump table.
6199 JumpTableRIPFixup* table_fixup =
6200 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
6201
6202 // We have to populate the jump tables.
6203 fixups_to_jump_tables_.push_back(table_fixup);
6204 return Address::RIP(table_fixup);
6205}
6206
Mark Mendellea5af682015-10-22 17:35:49 -04006207void CodeGeneratorX86_64::MoveInt64ToAddress(const Address& addr_low,
6208 const Address& addr_high,
6209 int64_t v,
6210 HInstruction* instruction) {
6211 if (IsInt<32>(v)) {
6212 int32_t v_32 = v;
6213 __ movq(addr_low, Immediate(v_32));
6214 MaybeRecordImplicitNullCheck(instruction);
6215 } else {
6216 // Didn't fit in a register. Do it in pieces.
6217 int32_t low_v = Low32Bits(v);
6218 int32_t high_v = High32Bits(v);
6219 __ movl(addr_low, Immediate(low_v));
6220 MaybeRecordImplicitNullCheck(instruction);
6221 __ movl(addr_high, Immediate(high_v));
6222 }
6223}
6224
Roland Levillain4d027112015-07-01 15:41:14 +01006225#undef __
6226
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01006227} // namespace x86_64
6228} // namespace art