blob: 4618be9cc37b6b97c215cd94cacdb42cff418471 [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();
Nicolas Geoffraye5234232015-12-02 09:06:11 +0000805
806 // Use the calling convention instead of the location of the receiver, as
807 // intrinsics may have put the receiver in a different register. In the intrinsics
808 // slow path, the arguments have been moved to the right place, so here we are
809 // guaranteed that the receiver is the first register of the calling convention.
810 InvokeDexCallingConvention calling_convention;
811 Register receiver = calling_convention.GetRegisterAt(0);
812
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000813 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000814 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +0000815 __ movl(temp, Address(CpuRegister(receiver), class_offset));
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000816 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000817 // Instead of simply (possibly) unpoisoning `temp` here, we should
818 // emit a read barrier for the previous class reference load.
819 // However this is not required in practice, as this is an
820 // intermediate/temporary reference and because the current
821 // concurrent copying collector keeps the from-space memory
822 // intact/accessible until the end of the marking phase (the
823 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000824 __ MaybeUnpoisonHeapReference(temp);
825 // temp = temp->GetMethodAt(method_offset);
826 __ movq(temp, Address(temp, method_offset));
827 // call temp->GetEntryPoint();
828 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
829 kX86_64WordSize).SizeValue()));
830}
831
Vladimir Marko58155012015-08-19 12:49:41 +0000832void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
833 DCHECK(linker_patches->empty());
834 size_t size =
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000835 method_patches_.size() +
836 relative_call_patches_.size() +
837 pc_relative_dex_cache_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +0000838 linker_patches->reserve(size);
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000839 // The label points to the end of the "movl" insn but the literal offset for method
840 // patch needs to point to the embedded constant which occupies the last 4 bytes.
841 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
Vladimir Marko58155012015-08-19 12:49:41 +0000842 for (const MethodPatchInfo<Label>& info : method_patches_) {
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000843 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000844 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
845 info.target_method.dex_file,
846 info.target_method.dex_method_index));
847 }
848 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000849 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000850 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
851 info.target_method.dex_file,
852 info.target_method.dex_method_index));
853 }
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000854 for (const PcRelativeDexCacheAccessInfo& info : pc_relative_dex_cache_patches_) {
855 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko58155012015-08-19 12:49:41 +0000856 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
857 &info.target_dex_file,
858 info.label.Position(),
859 info.element_offset));
860 }
861}
862
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100863void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100864 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100865}
866
867void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100868 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100869}
870
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100871size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
872 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
873 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100874}
875
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100876size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
877 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
878 return kX86_64WordSize;
879}
880
881size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
882 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
883 return kX86_64WordSize;
884}
885
886size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
887 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
888 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100889}
890
Calin Juravle175dc732015-08-25 15:42:32 +0100891void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
892 HInstruction* instruction,
893 uint32_t dex_pc,
894 SlowPathCode* slow_path) {
895 InvokeRuntime(GetThreadOffset<kX86_64WordSize>(entrypoint).Int32Value(),
896 instruction,
897 dex_pc,
898 slow_path);
899}
900
901void CodeGeneratorX86_64::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100902 HInstruction* instruction,
903 uint32_t dex_pc,
904 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100905 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100906 __ gs()->call(Address::Absolute(entry_point_offset, true));
Alexandre Rames8158f282015-08-07 10:26:17 +0100907 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100908}
909
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000910static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000911// Use a fake return address register to mimic Quick.
912static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400913CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000914 const X86_64InstructionSetFeatures& isa_features,
915 const CompilerOptions& compiler_options,
916 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +0000917 : CodeGenerator(graph,
918 kNumberOfCpuRegisters,
919 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000920 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000921 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
922 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +0000923 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000924 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
925 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100926 compiler_options,
927 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100928 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100929 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000930 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400931 move_resolver_(graph->GetArena(), this),
Mark Mendellf55c3e02015-03-26 21:07:46 -0400932 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +0000933 constant_area_start_(0),
Vladimir Marko5233f932015-09-29 19:01:15 +0100934 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
935 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000936 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Mark Mendell9c86b482015-09-18 13:36:07 -0400937 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000938 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
939}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100940
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100941InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
942 CodeGeneratorX86_64* codegen)
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100943 : HGraphVisitor(graph),
944 assembler_(codegen->GetAssembler()),
945 codegen_(codegen) {}
946
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100947Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100948 switch (type) {
949 case Primitive::kPrimLong:
950 case Primitive::kPrimByte:
951 case Primitive::kPrimBoolean:
952 case Primitive::kPrimChar:
953 case Primitive::kPrimShort:
954 case Primitive::kPrimInt:
955 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100956 size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100957 return Location::RegisterLocation(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100958 }
959
960 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100961 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100962 size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100963 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100964 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100965
966 case Primitive::kPrimVoid:
967 LOG(FATAL) << "Unreachable type " << type;
968 }
969
Roland Levillain0d5a2812015-11-13 10:07:31 +0000970 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100971}
972
Nicolas Geoffray98893962015-01-21 12:32:32 +0000973void CodeGeneratorX86_64::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100974 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100975 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100976
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000977 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100978 blocked_core_registers_[TMP] = true;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000979
Nicolas Geoffray98893962015-01-21 12:32:32 +0000980 if (is_baseline) {
981 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
982 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
983 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000984 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
985 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
986 }
Nicolas Geoffray98893962015-01-21 12:32:32 +0000987 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100988}
989
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100990static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100991 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100992}
David Srbecky9d8606d2015-04-12 09:35:32 +0100993
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100994static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100995 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100996}
997
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100998void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100999 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001000 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001001 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -07001002 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001003 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001004
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001005 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001006 __ testq(CpuRegister(RAX), Address(
1007 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001008 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001009 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +00001010
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001011 if (HasEmptyFrame()) {
1012 return;
1013 }
1014
Nicolas Geoffray98893962015-01-21 12:32:32 +00001015 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001016 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001017 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001018 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001019 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1020 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +00001021 }
1022 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001023
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001024 int adjust = GetFrameSize() - GetCoreSpillSize();
1025 __ subq(CpuRegister(RSP), Immediate(adjust));
1026 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001027 uint32_t xmm_spill_location = GetFpuSpillStart();
1028 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001029
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001030 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1031 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001032 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1033 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
1034 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001035 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001036 }
1037
Mathieu Chartiere401d142015-04-22 13:56:20 -07001038 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001039 CpuRegister(kMethodRegisterArgument));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001040}
1041
1042void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001043 __ cfi().RememberState();
1044 if (!HasEmptyFrame()) {
1045 uint32_t xmm_spill_location = GetFpuSpillStart();
1046 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
1047 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1048 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1049 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1050 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
1051 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
1052 }
1053 }
1054
1055 int adjust = GetFrameSize() - GetCoreSpillSize();
1056 __ addq(CpuRegister(RSP), Immediate(adjust));
1057 __ cfi().AdjustCFAOffset(-adjust);
1058
1059 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1060 Register reg = kCoreCalleeSaves[i];
1061 if (allocated_registers_.ContainsCoreRegister(reg)) {
1062 __ popq(CpuRegister(reg));
1063 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1064 __ cfi().Restore(DWARFReg(reg));
1065 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001066 }
1067 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001068 __ ret();
1069 __ cfi().RestoreState();
1070 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001071}
1072
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001073void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
1074 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001075}
1076
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001077Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
1078 switch (load->GetType()) {
1079 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001080 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001081 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001082
1083 case Primitive::kPrimInt:
1084 case Primitive::kPrimNot:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001085 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001086 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001087
1088 case Primitive::kPrimBoolean:
1089 case Primitive::kPrimByte:
1090 case Primitive::kPrimChar:
1091 case Primitive::kPrimShort:
1092 case Primitive::kPrimVoid:
1093 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -07001094 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001095 }
1096
1097 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -07001098 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001099}
1100
1101void CodeGeneratorX86_64::Move(Location destination, Location source) {
1102 if (source.Equals(destination)) {
1103 return;
1104 }
1105 if (destination.IsRegister()) {
1106 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001107 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001108 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001110 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001111 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001112 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001113 } else {
1114 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001115 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001116 Address(CpuRegister(RSP), source.GetStackIndex()));
1117 }
1118 } else if (destination.IsFpuRegister()) {
1119 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001120 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001121 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001122 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001123 } else if (source.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001124 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001125 Address(CpuRegister(RSP), source.GetStackIndex()));
1126 } else {
1127 DCHECK(source.IsDoubleStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001128 __ movsd(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001129 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001130 }
1131 } else if (destination.IsStackSlot()) {
1132 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001133 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001134 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001135 } else if (source.IsFpuRegister()) {
1136 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001137 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001138 } else if (source.IsConstant()) {
1139 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001140 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001141 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001142 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001143 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001144 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1145 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001146 }
1147 } else {
1148 DCHECK(destination.IsDoubleStackSlot());
1149 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001150 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001151 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001152 } else if (source.IsFpuRegister()) {
1153 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001154 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001155 } else if (source.IsConstant()) {
1156 HConstant* constant = source.GetConstant();
Zheng Xu12bca972015-03-30 19:35:50 +08001157 int64_t value;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001158 if (constant->IsDoubleConstant()) {
Roland Levillainda4d79b2015-03-24 14:36:11 +00001159 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001160 } else {
1161 DCHECK(constant->IsLongConstant());
1162 value = constant->AsLongConstant()->GetValue();
1163 }
Mark Mendellcfa410b2015-05-25 16:02:44 -04001164 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001165 } else {
1166 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001167 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1168 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001169 }
1170 }
1171}
1172
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001173void CodeGeneratorX86_64::Move(HInstruction* instruction,
1174 Location location,
1175 HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001176 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001177 if (instruction->IsCurrentMethod()) {
Mathieu Chartiere3b034a2015-05-31 14:29:23 -07001178 Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001179 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001180 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001181 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001182 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001183 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
1184 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +00001185 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001186 __ movl(location.AsRegister<CpuRegister>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +00001187 } else if (location.IsStackSlot()) {
1188 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
1189 } else {
1190 DCHECK(location.IsConstant());
1191 DCHECK_EQ(location.GetConstant(), const_to_move);
1192 }
1193 } else if (const_to_move->IsLongConstant()) {
1194 int64_t value = const_to_move->AsLongConstant()->GetValue();
1195 if (location.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04001196 Load64BitValue(location.AsRegister<CpuRegister>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001197 } else if (location.IsDoubleStackSlot()) {
Mark Mendellcfa410b2015-05-25 16:02:44 -04001198 Store64BitValueToStack(location, value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001199 } else {
1200 DCHECK(location.IsConstant());
1201 DCHECK_EQ(location.GetConstant(), const_to_move);
1202 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001203 }
Roland Levillain476df552014-10-09 17:51:36 +01001204 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001205 switch (instruction->GetType()) {
1206 case Primitive::kPrimBoolean:
1207 case Primitive::kPrimByte:
1208 case Primitive::kPrimChar:
1209 case Primitive::kPrimShort:
1210 case Primitive::kPrimInt:
1211 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001212 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001213 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
1214 break;
1215
1216 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001217 case Primitive::kPrimDouble:
Roland Levillain199f3362014-11-27 17:15:16 +00001218 Move(location,
1219 Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001220 break;
1221
1222 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001223 LOG(FATAL) << "Unexpected local type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001224 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001225 } else if (instruction->IsTemporary()) {
1226 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
1227 Move(location, temp_location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001228 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001229 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001230 switch (instruction->GetType()) {
1231 case Primitive::kPrimBoolean:
1232 case Primitive::kPrimByte:
1233 case Primitive::kPrimChar:
1234 case Primitive::kPrimShort:
1235 case Primitive::kPrimInt:
1236 case Primitive::kPrimNot:
1237 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001238 case Primitive::kPrimFloat:
1239 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +00001240 Move(location, locations->Out());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001241 break;
1242
1243 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001244 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001245 }
1246 }
1247}
1248
Calin Juravle175dc732015-08-25 15:42:32 +01001249void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
1250 DCHECK(location.IsRegister());
1251 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
1252}
1253
Calin Juravlee460d1d2015-09-29 04:52:17 +01001254void CodeGeneratorX86_64::MoveLocation(
1255 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
1256 Move(dst, src);
1257}
1258
1259void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1260 if (location.IsRegister()) {
1261 locations->AddTemp(location);
1262 } else {
1263 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1264 }
1265}
1266
David Brazdilfc6a86a2015-06-26 10:33:45 +00001267void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001268 DCHECK(!successor->IsExitBlock());
1269
1270 HBasicBlock* block = got->GetBlock();
1271 HInstruction* previous = got->GetPrevious();
1272
1273 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001274 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001275 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1276 return;
1277 }
1278
1279 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1280 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1281 }
1282 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001283 __ jmp(codegen_->GetLabelOf(successor));
1284 }
1285}
1286
David Brazdilfc6a86a2015-06-26 10:33:45 +00001287void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1288 got->SetLocations(nullptr);
1289}
1290
1291void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1292 HandleGoto(got, got->GetSuccessor());
1293}
1294
1295void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1296 try_boundary->SetLocations(nullptr);
1297}
1298
1299void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1300 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1301 if (!successor->IsExitBlock()) {
1302 HandleGoto(try_boundary, successor);
1303 }
1304}
1305
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001306void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1307 exit->SetLocations(nullptr);
1308}
1309
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001310void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001311}
1312
Mark Mendellc4701932015-04-10 13:18:51 -04001313void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
1314 Label* true_label,
1315 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001316 if (cond->IsFPConditionTrueIfNaN()) {
1317 __ j(kUnordered, true_label);
1318 } else if (cond->IsFPConditionFalseIfNaN()) {
1319 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001320 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001321 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001322}
1323
David Brazdil0debae72015-11-12 18:37:00 +00001324void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
1325 Label* true_target_in,
1326 Label* false_target_in) {
1327 // Generated branching requires both targets to be explicit. If either of the
1328 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1329 Label fallthrough_target;
1330 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1331 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1332
Mark Mendellc4701932015-04-10 13:18:51 -04001333 LocationSummary* locations = condition->GetLocations();
1334 Location left = locations->InAt(0);
1335 Location right = locations->InAt(1);
1336
Mark Mendellc4701932015-04-10 13:18:51 -04001337 Primitive::Type type = condition->InputAt(0)->GetType();
1338 switch (type) {
1339 case Primitive::kPrimLong: {
1340 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1341 if (right.IsConstant()) {
1342 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1343 if (IsInt<32>(value)) {
1344 if (value == 0) {
1345 __ testq(left_reg, left_reg);
1346 } else {
1347 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1348 }
1349 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001350 // Value won't fit in a 32-bit integer.
Mark Mendellc4701932015-04-10 13:18:51 -04001351 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
1352 }
1353 } else if (right.IsDoubleStackSlot()) {
1354 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1355 } else {
1356 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1357 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001358 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Mark Mendellc4701932015-04-10 13:18:51 -04001359 break;
1360 }
1361 case Primitive::kPrimFloat: {
1362 if (right.IsFpuRegister()) {
1363 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1364 } else if (right.IsConstant()) {
1365 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1366 codegen_->LiteralFloatAddress(
1367 right.GetConstant()->AsFloatConstant()->GetValue()));
1368 } else {
1369 DCHECK(right.IsStackSlot());
1370 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1371 Address(CpuRegister(RSP), right.GetStackIndex()));
1372 }
1373 GenerateFPJumps(condition, true_target, false_target);
1374 break;
1375 }
1376 case Primitive::kPrimDouble: {
1377 if (right.IsFpuRegister()) {
1378 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1379 } else if (right.IsConstant()) {
1380 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1381 codegen_->LiteralDoubleAddress(
1382 right.GetConstant()->AsDoubleConstant()->GetValue()));
1383 } else {
1384 DCHECK(right.IsDoubleStackSlot());
1385 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1386 Address(CpuRegister(RSP), right.GetStackIndex()));
1387 }
1388 GenerateFPJumps(condition, true_target, false_target);
1389 break;
1390 }
1391 default:
1392 LOG(FATAL) << "Unexpected condition type " << type;
1393 }
1394
David Brazdil0debae72015-11-12 18:37:00 +00001395 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001396 __ jmp(false_target);
1397 }
David Brazdil0debae72015-11-12 18:37:00 +00001398
1399 if (fallthrough_target.IsLinked()) {
1400 __ Bind(&fallthrough_target);
1401 }
Mark Mendellc4701932015-04-10 13:18:51 -04001402}
1403
David Brazdil0debae72015-11-12 18:37:00 +00001404static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1405 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1406 // are set only strictly before `branch`. We can't use the eflags on long
1407 // conditions if they are materialized due to the complex branching.
1408 return cond->IsCondition() &&
1409 cond->GetNext() == branch &&
1410 !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
1411}
1412
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001413void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001414 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001415 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001416 Label* false_target) {
1417 HInstruction* cond = instruction->InputAt(condition_input_index);
1418
1419 if (true_target == nullptr && false_target == nullptr) {
1420 // Nothing to do. The code always falls through.
1421 return;
1422 } else if (cond->IsIntConstant()) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001423 // Constant condition, statically compared against 1.
David Brazdil0debae72015-11-12 18:37:00 +00001424 if (cond->AsIntConstant()->IsOne()) {
1425 if (true_target != nullptr) {
1426 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001427 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001428 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001429 DCHECK(cond->AsIntConstant()->IsZero());
1430 if (false_target != nullptr) {
1431 __ jmp(false_target);
1432 }
1433 }
1434 return;
1435 }
1436
1437 // The following code generates these patterns:
1438 // (1) true_target == nullptr && false_target != nullptr
1439 // - opposite condition true => branch to false_target
1440 // (2) true_target != nullptr && false_target == nullptr
1441 // - condition true => branch to true_target
1442 // (3) true_target != nullptr && false_target != nullptr
1443 // - condition true => branch to true_target
1444 // - branch to false_target
1445 if (IsBooleanValueOrMaterializedCondition(cond)) {
1446 if (AreEflagsSetFrom(cond, instruction)) {
1447 if (true_target == nullptr) {
1448 __ j(X86_64IntegerCondition(cond->AsCondition()->GetOppositeCondition()), false_target);
1449 } else {
1450 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
1451 }
1452 } else {
1453 // Materialized condition, compare against 0.
1454 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
1455 if (lhs.IsRegister()) {
1456 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1457 } else {
1458 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
1459 }
1460 if (true_target == nullptr) {
1461 __ j(kEqual, false_target);
1462 } else {
1463 __ j(kNotEqual, true_target);
1464 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001465 }
1466 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001467 // Condition has not been materialized, use its inputs as the
1468 // comparison and its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001469 HCondition* condition = cond->AsCondition();
Mark Mendellc4701932015-04-10 13:18:51 -04001470
David Brazdil0debae72015-11-12 18:37:00 +00001471 // If this is a long or FP comparison that has been folded into
1472 // the HCondition, generate the comparison directly.
1473 Primitive::Type type = condition->InputAt(0)->GetType();
1474 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1475 GenerateCompareTestAndBranch(condition, true_target, false_target);
1476 return;
1477 }
1478
1479 Location lhs = condition->GetLocations()->InAt(0);
1480 Location rhs = condition->GetLocations()->InAt(1);
1481 if (rhs.IsRegister()) {
1482 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1483 } else if (rhs.IsConstant()) {
1484 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1485 if (constant == 0) {
1486 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001487 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001488 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001489 }
1490 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001491 __ cmpl(lhs.AsRegister<CpuRegister>(),
1492 Address(CpuRegister(RSP), rhs.GetStackIndex()));
1493 }
1494 if (true_target == nullptr) {
1495 __ j(X86_64IntegerCondition(condition->GetOppositeCondition()), false_target);
1496 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001497 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001498 }
Dave Allison20dfc792014-06-16 20:44:29 -07001499 }
David Brazdil0debae72015-11-12 18:37:00 +00001500
1501 // If neither branch falls through (case 3), the conditional branch to `true_target`
1502 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1503 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001504 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001505 }
1506}
1507
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001508void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001509 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1510 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001511 locations->SetInAt(0, Location::Any());
1512 }
1513}
1514
1515void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001516 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1517 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1518 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1519 nullptr : codegen_->GetLabelOf(true_successor);
1520 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1521 nullptr : codegen_->GetLabelOf(false_successor);
1522 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001523}
1524
1525void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1526 LocationSummary* locations = new (GetGraph()->GetArena())
1527 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001528 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001529 locations->SetInAt(0, Location::Any());
1530 }
1531}
1532
1533void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001534 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001535 DeoptimizationSlowPathX86_64(deoptimize);
1536 codegen_->AddSlowPath(slow_path);
David Brazdil0debae72015-11-12 18:37:00 +00001537 GenerateTestAndBranch(deoptimize,
1538 /* condition_input_index */ 0,
1539 slow_path->GetEntryLabel(),
1540 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001541}
1542
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001543void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
1544 local->SetLocations(nullptr);
1545}
1546
1547void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
1548 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1549}
1550
1551void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
1552 local->SetLocations(nullptr);
1553}
1554
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001555void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001556 // Nothing to do, this is driven by the code generator.
1557}
1558
1559void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001560 LocationSummary* locations =
1561 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001562 switch (store->InputAt(1)->GetType()) {
1563 case Primitive::kPrimBoolean:
1564 case Primitive::kPrimByte:
1565 case Primitive::kPrimChar:
1566 case Primitive::kPrimShort:
1567 case Primitive::kPrimInt:
1568 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001569 case Primitive::kPrimFloat:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001570 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1571 break;
1572
1573 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001574 case Primitive::kPrimDouble:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001575 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1576 break;
1577
1578 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001579 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001580 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001581}
1582
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001583void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001584}
1585
Roland Levillain0d37cd02015-05-27 16:39:19 +01001586void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001587 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001588 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001589 // Handle the long/FP comparisons made in instruction simplification.
1590 switch (cond->InputAt(0)->GetType()) {
1591 case Primitive::kPrimLong:
1592 locations->SetInAt(0, Location::RequiresRegister());
1593 locations->SetInAt(1, Location::Any());
1594 break;
1595 case Primitive::kPrimFloat:
1596 case Primitive::kPrimDouble:
1597 locations->SetInAt(0, Location::RequiresFpuRegister());
1598 locations->SetInAt(1, Location::Any());
1599 break;
1600 default:
1601 locations->SetInAt(0, Location::RequiresRegister());
1602 locations->SetInAt(1, Location::Any());
1603 break;
1604 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001605 if (cond->NeedsMaterialization()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001606 locations->SetOut(Location::RequiresRegister());
1607 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001608}
1609
Roland Levillain0d37cd02015-05-27 16:39:19 +01001610void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001611 if (!cond->NeedsMaterialization()) {
1612 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001613 }
Mark Mendellc4701932015-04-10 13:18:51 -04001614
1615 LocationSummary* locations = cond->GetLocations();
1616 Location lhs = locations->InAt(0);
1617 Location rhs = locations->InAt(1);
1618 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
1619 Label true_label, false_label;
1620
1621 switch (cond->InputAt(0)->GetType()) {
1622 default:
1623 // Integer case.
1624
1625 // Clear output register: setcc only sets the low byte.
1626 __ xorl(reg, reg);
1627
1628 if (rhs.IsRegister()) {
1629 __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1630 } else if (rhs.IsConstant()) {
1631 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1632 if (constant == 0) {
1633 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1634 } else {
1635 __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
1636 }
1637 } else {
1638 __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1639 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001640 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001641 return;
1642 case Primitive::kPrimLong:
1643 // Clear output register: setcc only sets the low byte.
1644 __ xorl(reg, reg);
1645
1646 if (rhs.IsRegister()) {
1647 __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
1648 } else if (rhs.IsConstant()) {
1649 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
1650 if (IsInt<32>(value)) {
1651 if (value == 0) {
1652 __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1653 } else {
1654 __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
1655 }
1656 } else {
1657 // Value won't fit in an int.
1658 __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
1659 }
1660 } else {
1661 __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
1662 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001663 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001664 return;
1665 case Primitive::kPrimFloat: {
1666 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1667 if (rhs.IsConstant()) {
1668 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1669 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1670 } else if (rhs.IsStackSlot()) {
1671 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1672 } else {
1673 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1674 }
1675 GenerateFPJumps(cond, &true_label, &false_label);
1676 break;
1677 }
1678 case Primitive::kPrimDouble: {
1679 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1680 if (rhs.IsConstant()) {
1681 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1682 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1683 } else if (rhs.IsDoubleStackSlot()) {
1684 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1685 } else {
1686 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1687 }
1688 GenerateFPJumps(cond, &true_label, &false_label);
1689 break;
1690 }
1691 }
1692
1693 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001694 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001695
Roland Levillain4fa13f62015-07-06 18:11:54 +01001696 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001697 __ Bind(&false_label);
1698 __ xorl(reg, reg);
1699 __ jmp(&done_label);
1700
Roland Levillain4fa13f62015-07-06 18:11:54 +01001701 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001702 __ Bind(&true_label);
1703 __ movl(reg, Immediate(1));
1704 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001705}
1706
1707void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
1708 VisitCondition(comp);
1709}
1710
1711void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
1712 VisitCondition(comp);
1713}
1714
1715void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
1716 VisitCondition(comp);
1717}
1718
1719void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
1720 VisitCondition(comp);
1721}
1722
1723void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
1724 VisitCondition(comp);
1725}
1726
1727void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
1728 VisitCondition(comp);
1729}
1730
1731void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1732 VisitCondition(comp);
1733}
1734
1735void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1736 VisitCondition(comp);
1737}
1738
1739void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
1740 VisitCondition(comp);
1741}
1742
1743void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
1744 VisitCondition(comp);
1745}
1746
1747void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1748 VisitCondition(comp);
1749}
1750
1751void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1752 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001753}
1754
Aart Bike9f37602015-10-09 11:15:55 -07001755void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
1756 VisitCondition(comp);
1757}
1758
1759void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
1760 VisitCondition(comp);
1761}
1762
1763void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1764 VisitCondition(comp);
1765}
1766
1767void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
1768 VisitCondition(comp);
1769}
1770
1771void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
1772 VisitCondition(comp);
1773}
1774
1775void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
1776 VisitCondition(comp);
1777}
1778
1779void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1780 VisitCondition(comp);
1781}
1782
1783void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
1784 VisitCondition(comp);
1785}
1786
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001787void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001788 LocationSummary* locations =
1789 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00001790 switch (compare->InputAt(0)->GetType()) {
1791 case Primitive::kPrimLong: {
1792 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001793 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001794 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1795 break;
1796 }
1797 case Primitive::kPrimFloat:
1798 case Primitive::kPrimDouble: {
1799 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04001800 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00001801 locations->SetOut(Location::RequiresRegister());
1802 break;
1803 }
1804 default:
1805 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
1806 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001807}
1808
1809void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001810 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001811 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00001812 Location left = locations->InAt(0);
1813 Location right = locations->InAt(1);
1814
Mark Mendell0c9497d2015-08-21 09:30:05 -04001815 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00001816 Primitive::Type type = compare->InputAt(0)->GetType();
1817 switch (type) {
1818 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001819 CpuRegister left_reg = left.AsRegister<CpuRegister>();
1820 if (right.IsConstant()) {
1821 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell40741f32015-04-20 22:10:34 -04001822 if (IsInt<32>(value)) {
1823 if (value == 0) {
1824 __ testq(left_reg, left_reg);
1825 } else {
1826 __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
1827 }
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001828 } else {
Mark Mendell40741f32015-04-20 22:10:34 -04001829 // Value won't fit in an int.
1830 __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001831 }
Mark Mendell40741f32015-04-20 22:10:34 -04001832 } else if (right.IsDoubleStackSlot()) {
1833 __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04001834 } else {
1835 __ cmpq(left_reg, right.AsRegister<CpuRegister>());
1836 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001837 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00001838 }
1839 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04001840 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1841 if (right.IsConstant()) {
1842 float value = right.GetConstant()->AsFloatConstant()->GetValue();
1843 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
1844 } else if (right.IsStackSlot()) {
1845 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1846 } else {
1847 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
1848 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001849 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1850 break;
1851 }
1852 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04001853 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
1854 if (right.IsConstant()) {
1855 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
1856 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
1857 } else if (right.IsDoubleStackSlot()) {
1858 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
1859 } else {
1860 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
1861 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001862 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
1863 break;
1864 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001865 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00001866 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001867 }
Calin Juravleddb7df22014-11-25 20:56:51 +00001868 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00001869 __ j(kEqual, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00001870 __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less); // ucomis{s,d} sets CF (kBelow)
Calin Juravlefd861242014-11-25 20:56:51 +00001871
Calin Juravle91debbc2014-11-26 19:01:09 +00001872 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00001873 __ movl(out, Immediate(1));
1874 __ jmp(&done);
1875
1876 __ Bind(&less);
1877 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001878
1879 __ Bind(&done);
1880}
1881
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001882void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001883 LocationSummary* locations =
1884 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001885 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001886}
1887
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001888void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001889 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001890}
1891
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001892void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
1893 LocationSummary* locations =
1894 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1895 locations->SetOut(Location::ConstantLocation(constant));
1896}
1897
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001898void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001899 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001900}
1901
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001902void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001903 LocationSummary* locations =
1904 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001905 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001906}
1907
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001908void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001909 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001910}
1911
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001912void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
1913 LocationSummary* locations =
1914 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1915 locations->SetOut(Location::ConstantLocation(constant));
1916}
1917
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001918void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001919 // Will be generated at use site.
1920}
1921
1922void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
1923 LocationSummary* locations =
1924 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1925 locations->SetOut(Location::ConstantLocation(constant));
1926}
1927
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001928void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
1929 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001930 // Will be generated at use site.
1931}
1932
Calin Juravle27df7582015-04-17 19:12:31 +01001933void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1934 memory_barrier->SetLocations(nullptr);
1935}
1936
1937void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1938 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1939}
1940
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001941void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
1942 ret->SetLocations(nullptr);
1943}
1944
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001945void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001946 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001947}
1948
1949void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001950 LocationSummary* locations =
1951 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001952 switch (ret->InputAt(0)->GetType()) {
1953 case Primitive::kPrimBoolean:
1954 case Primitive::kPrimByte:
1955 case Primitive::kPrimChar:
1956 case Primitive::kPrimShort:
1957 case Primitive::kPrimInt:
1958 case Primitive::kPrimNot:
1959 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001960 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001961 break;
1962
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001963 case Primitive::kPrimFloat:
1964 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04001965 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001966 break;
1967
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001968 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001969 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001970 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001971}
1972
1973void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
1974 if (kIsDebugBuild) {
1975 switch (ret->InputAt(0)->GetType()) {
1976 case Primitive::kPrimBoolean:
1977 case Primitive::kPrimByte:
1978 case Primitive::kPrimChar:
1979 case Primitive::kPrimShort:
1980 case Primitive::kPrimInt:
1981 case Primitive::kPrimNot:
1982 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001983 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001984 break;
1985
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001986 case Primitive::kPrimFloat:
1987 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001988 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001989 XMM0);
1990 break;
1991
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001992 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001993 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001994 }
1995 }
1996 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001997}
1998
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001999Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
2000 switch (type) {
2001 case Primitive::kPrimBoolean:
2002 case Primitive::kPrimByte:
2003 case Primitive::kPrimChar:
2004 case Primitive::kPrimShort:
2005 case Primitive::kPrimInt:
2006 case Primitive::kPrimNot:
2007 case Primitive::kPrimLong:
2008 return Location::RegisterLocation(RAX);
2009
2010 case Primitive::kPrimVoid:
2011 return Location::NoLocation();
2012
2013 case Primitive::kPrimDouble:
2014 case Primitive::kPrimFloat:
2015 return Location::FpuRegisterLocation(XMM0);
2016 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002017
2018 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002019}
2020
2021Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
2022 return Location::RegisterLocation(kMethodRegisterArgument);
2023}
2024
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002025Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002026 switch (type) {
2027 case Primitive::kPrimBoolean:
2028 case Primitive::kPrimByte:
2029 case Primitive::kPrimChar:
2030 case Primitive::kPrimShort:
2031 case Primitive::kPrimInt:
2032 case Primitive::kPrimNot: {
2033 uint32_t index = gp_index_++;
2034 stack_index_++;
2035 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002036 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002037 } else {
2038 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2039 }
2040 }
2041
2042 case Primitive::kPrimLong: {
2043 uint32_t index = gp_index_;
2044 stack_index_ += 2;
2045 if (index < calling_convention.GetNumberOfRegisters()) {
2046 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002047 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002048 } else {
2049 gp_index_ += 2;
2050 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2051 }
2052 }
2053
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002054 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002055 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002056 stack_index_++;
2057 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002058 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002059 } else {
2060 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2061 }
2062 }
2063
2064 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002065 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002066 stack_index_ += 2;
2067 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002068 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002069 } else {
2070 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2071 }
2072 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002073
2074 case Primitive::kPrimVoid:
2075 LOG(FATAL) << "Unexpected parameter type " << type;
2076 break;
2077 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00002078 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002079}
2080
Calin Juravle175dc732015-08-25 15:42:32 +01002081void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2082 // The trampoline uses the same calling convention as dex calling conventions,
2083 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2084 // the method_idx.
2085 HandleInvoke(invoke);
2086}
2087
2088void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2089 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2090}
2091
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002092void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01002093 // When we do not run baseline, explicit clinit checks triggered by static
2094 // invokes must have been pruned by art::PrepareForRegisterAllocation.
2095 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002096
Mark Mendellfb8d2792015-03-31 22:16:59 -04002097 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002098 if (intrinsic.TryDispatch(invoke)) {
2099 return;
2100 }
2101
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002102 HandleInvoke(invoke);
2103}
2104
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002105static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
2106 if (invoke->GetLocations()->Intrinsified()) {
2107 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
2108 intrinsic.Dispatch(invoke);
2109 return true;
2110 }
2111 return false;
2112}
2113
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002114void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01002115 // When we do not run baseline, explicit clinit checks triggered by static
2116 // invokes must have been pruned by art::PrepareForRegisterAllocation.
2117 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002118
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002119 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2120 return;
2121 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002122
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002123 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002124 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002125 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00002126 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002127}
2128
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002129void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002130 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002131 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002132}
2133
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002134void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04002135 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002136 if (intrinsic.TryDispatch(invoke)) {
2137 return;
2138 }
2139
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002140 HandleInvoke(invoke);
2141}
2142
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002143void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002144 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2145 return;
2146 }
2147
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002148 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002149 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002150 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002151}
2152
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002153void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2154 HandleInvoke(invoke);
2155 // Add the hidden argument.
2156 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
2157}
2158
2159void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2160 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002161 LocationSummary* locations = invoke->GetLocations();
2162 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2163 CpuRegister hidden_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07002164 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
2165 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86_64PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002166 Location receiver = locations->InAt(0);
2167 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
2168
Roland Levillain0d5a2812015-11-13 10:07:31 +00002169 // Set the hidden argument. This is safe to do this here, as RAX
2170 // won't be modified thereafter, before the `call` instruction.
2171 DCHECK_EQ(RAX, hidden_reg.AsRegister());
Mark Mendell92e83bf2015-05-07 11:25:03 -04002172 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002173
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002174 if (receiver.IsStackSlot()) {
2175 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002176 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002177 __ movl(temp, Address(temp, class_offset));
2178 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002179 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002180 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002181 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002182 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002183 // Instead of simply (possibly) unpoisoning `temp` here, we should
2184 // emit a read barrier for the previous class reference load.
2185 // However this is not required in practice, as this is an
2186 // intermediate/temporary reference and because the current
2187 // concurrent copying collector keeps the from-space memory
2188 // intact/accessible until the end of the marking phase (the
2189 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002190 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002191 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002192 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002193 // call temp->GetEntryPoint();
Roland Levillain0d5a2812015-11-13 10:07:31 +00002194 __ call(Address(temp,
2195 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64WordSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002196
2197 DCHECK(!codegen_->IsLeafMethod());
2198 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2199}
2200
Roland Levillain88cb1752014-10-20 16:36:47 +01002201void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
2202 LocationSummary* locations =
2203 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2204 switch (neg->GetResultType()) {
2205 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002206 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01002207 locations->SetInAt(0, Location::RequiresRegister());
2208 locations->SetOut(Location::SameAsFirstInput());
2209 break;
2210
Roland Levillain88cb1752014-10-20 16:36:47 +01002211 case Primitive::kPrimFloat:
2212 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002213 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002214 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00002215 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002216 break;
2217
2218 default:
2219 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2220 }
2221}
2222
2223void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
2224 LocationSummary* locations = neg->GetLocations();
2225 Location out = locations->Out();
2226 Location in = locations->InAt(0);
2227 switch (neg->GetResultType()) {
2228 case Primitive::kPrimInt:
2229 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002230 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002231 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002232 break;
2233
2234 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002235 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002236 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002237 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002238 break;
2239
Roland Levillain5368c212014-11-27 15:03:41 +00002240 case Primitive::kPrimFloat: {
2241 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002242 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002243 // Implement float negation with an exclusive or with value
2244 // 0x80000000 (mask for bit 31, representing the sign of a
2245 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002246 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002247 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002248 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002249 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002250
Roland Levillain5368c212014-11-27 15:03:41 +00002251 case Primitive::kPrimDouble: {
2252 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002253 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002254 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00002255 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00002256 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002257 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002258 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002259 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002260 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002261
2262 default:
2263 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2264 }
2265}
2266
Roland Levillaindff1f282014-11-05 14:15:05 +00002267void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2268 LocationSummary* locations =
2269 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2270 Primitive::Type result_type = conversion->GetResultType();
2271 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002272 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00002273
David Brazdilb2bd1c52015-03-25 11:17:37 +00002274 // The Java language does not allow treating boolean as an integral type but
2275 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002276
Roland Levillaindff1f282014-11-05 14:15:05 +00002277 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002278 case Primitive::kPrimByte:
2279 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002280 case Primitive::kPrimBoolean:
2281 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002282 case Primitive::kPrimShort:
2283 case Primitive::kPrimInt:
2284 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002285 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002286 locations->SetInAt(0, Location::Any());
2287 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2288 break;
2289
2290 default:
2291 LOG(FATAL) << "Unexpected type conversion from " << input_type
2292 << " to " << result_type;
2293 }
2294 break;
2295
Roland Levillain01a8d712014-11-14 16:27:39 +00002296 case Primitive::kPrimShort:
2297 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002298 case Primitive::kPrimBoolean:
2299 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002300 case Primitive::kPrimByte:
2301 case Primitive::kPrimInt:
2302 case Primitive::kPrimChar:
2303 // Processing a Dex `int-to-short' instruction.
2304 locations->SetInAt(0, Location::Any());
2305 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2306 break;
2307
2308 default:
2309 LOG(FATAL) << "Unexpected type conversion from " << input_type
2310 << " to " << result_type;
2311 }
2312 break;
2313
Roland Levillain946e1432014-11-11 17:35:19 +00002314 case Primitive::kPrimInt:
2315 switch (input_type) {
2316 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002317 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002318 locations->SetInAt(0, Location::Any());
2319 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2320 break;
2321
2322 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002323 // Processing a Dex `float-to-int' instruction.
2324 locations->SetInAt(0, Location::RequiresFpuRegister());
2325 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002326 break;
2327
Roland Levillain946e1432014-11-11 17:35:19 +00002328 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002329 // Processing a Dex `double-to-int' instruction.
2330 locations->SetInAt(0, Location::RequiresFpuRegister());
2331 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002332 break;
2333
2334 default:
2335 LOG(FATAL) << "Unexpected type conversion from " << input_type
2336 << " to " << result_type;
2337 }
2338 break;
2339
Roland Levillaindff1f282014-11-05 14:15:05 +00002340 case Primitive::kPrimLong:
2341 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002342 case Primitive::kPrimBoolean:
2343 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002344 case Primitive::kPrimByte:
2345 case Primitive::kPrimShort:
2346 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002347 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002348 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002349 // TODO: We would benefit from a (to-be-implemented)
2350 // Location::RegisterOrStackSlot requirement for this input.
2351 locations->SetInAt(0, Location::RequiresRegister());
2352 locations->SetOut(Location::RequiresRegister());
2353 break;
2354
2355 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002356 // Processing a Dex `float-to-long' instruction.
2357 locations->SetInAt(0, Location::RequiresFpuRegister());
2358 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002359 break;
2360
Roland Levillaindff1f282014-11-05 14:15:05 +00002361 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002362 // Processing a Dex `double-to-long' instruction.
2363 locations->SetInAt(0, Location::RequiresFpuRegister());
2364 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002365 break;
2366
2367 default:
2368 LOG(FATAL) << "Unexpected type conversion from " << input_type
2369 << " to " << result_type;
2370 }
2371 break;
2372
Roland Levillain981e4542014-11-14 11:47:14 +00002373 case Primitive::kPrimChar:
2374 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002375 case Primitive::kPrimBoolean:
2376 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002377 case Primitive::kPrimByte:
2378 case Primitive::kPrimShort:
2379 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002380 // Processing a Dex `int-to-char' instruction.
2381 locations->SetInAt(0, Location::Any());
2382 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2383 break;
2384
2385 default:
2386 LOG(FATAL) << "Unexpected type conversion from " << input_type
2387 << " to " << result_type;
2388 }
2389 break;
2390
Roland Levillaindff1f282014-11-05 14:15:05 +00002391 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002392 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002393 case Primitive::kPrimBoolean:
2394 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002395 case Primitive::kPrimByte:
2396 case Primitive::kPrimShort:
2397 case Primitive::kPrimInt:
2398 case Primitive::kPrimChar:
2399 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002400 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002401 locations->SetOut(Location::RequiresFpuRegister());
2402 break;
2403
2404 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002405 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002406 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002407 locations->SetOut(Location::RequiresFpuRegister());
2408 break;
2409
Roland Levillaincff13742014-11-17 14:32:17 +00002410 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002411 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002412 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002413 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002414 break;
2415
2416 default:
2417 LOG(FATAL) << "Unexpected type conversion from " << input_type
2418 << " to " << result_type;
2419 };
2420 break;
2421
Roland Levillaindff1f282014-11-05 14:15:05 +00002422 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002423 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002424 case Primitive::kPrimBoolean:
2425 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002426 case Primitive::kPrimByte:
2427 case Primitive::kPrimShort:
2428 case Primitive::kPrimInt:
2429 case Primitive::kPrimChar:
2430 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002431 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002432 locations->SetOut(Location::RequiresFpuRegister());
2433 break;
2434
2435 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002436 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002437 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002438 locations->SetOut(Location::RequiresFpuRegister());
2439 break;
2440
Roland Levillaincff13742014-11-17 14:32:17 +00002441 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002442 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002443 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002444 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002445 break;
2446
2447 default:
2448 LOG(FATAL) << "Unexpected type conversion from " << input_type
2449 << " to " << result_type;
2450 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002451 break;
2452
2453 default:
2454 LOG(FATAL) << "Unexpected type conversion from " << input_type
2455 << " to " << result_type;
2456 }
2457}
2458
2459void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2460 LocationSummary* locations = conversion->GetLocations();
2461 Location out = locations->Out();
2462 Location in = locations->InAt(0);
2463 Primitive::Type result_type = conversion->GetResultType();
2464 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002465 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002466 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002467 case Primitive::kPrimByte:
2468 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002469 case Primitive::kPrimBoolean:
2470 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002471 case Primitive::kPrimShort:
2472 case Primitive::kPrimInt:
2473 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002474 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002475 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002476 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain51d3fc42014-11-13 14:11:42 +00002477 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002478 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002479 Address(CpuRegister(RSP), in.GetStackIndex()));
2480 } else {
2481 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002482 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002483 Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2484 }
2485 break;
2486
2487 default:
2488 LOG(FATAL) << "Unexpected type conversion from " << input_type
2489 << " to " << result_type;
2490 }
2491 break;
2492
Roland Levillain01a8d712014-11-14 16:27:39 +00002493 case Primitive::kPrimShort:
2494 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002495 case Primitive::kPrimBoolean:
2496 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002497 case Primitive::kPrimByte:
2498 case Primitive::kPrimInt:
2499 case Primitive::kPrimChar:
2500 // Processing a Dex `int-to-short' instruction.
2501 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002502 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002503 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002504 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002505 Address(CpuRegister(RSP), in.GetStackIndex()));
2506 } else {
2507 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002508 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002509 Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2510 }
2511 break;
2512
2513 default:
2514 LOG(FATAL) << "Unexpected type conversion from " << input_type
2515 << " to " << result_type;
2516 }
2517 break;
2518
Roland Levillain946e1432014-11-11 17:35:19 +00002519 case Primitive::kPrimInt:
2520 switch (input_type) {
2521 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002522 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002523 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002524 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002525 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002526 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002527 Address(CpuRegister(RSP), in.GetStackIndex()));
2528 } else {
2529 DCHECK(in.IsConstant());
2530 DCHECK(in.GetConstant()->IsLongConstant());
2531 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002532 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002533 }
2534 break;
2535
Roland Levillain3f8f9362014-12-02 17:45:01 +00002536 case Primitive::kPrimFloat: {
2537 // Processing a Dex `float-to-int' instruction.
2538 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2539 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002540 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002541
2542 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002543 // if input >= (float)INT_MAX goto done
2544 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002545 __ j(kAboveEqual, &done);
2546 // if input == NaN goto nan
2547 __ j(kUnordered, &nan);
2548 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002549 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002550 __ jmp(&done);
2551 __ Bind(&nan);
2552 // output = 0
2553 __ xorl(output, output);
2554 __ Bind(&done);
2555 break;
2556 }
2557
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002558 case Primitive::kPrimDouble: {
2559 // Processing a Dex `double-to-int' instruction.
2560 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2561 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002562 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002563
2564 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002565 // if input >= (double)INT_MAX goto done
2566 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002567 __ j(kAboveEqual, &done);
2568 // if input == NaN goto nan
2569 __ j(kUnordered, &nan);
2570 // output = double-to-int-truncate(input)
2571 __ cvttsd2si(output, input);
2572 __ jmp(&done);
2573 __ Bind(&nan);
2574 // output = 0
2575 __ xorl(output, output);
2576 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002577 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002578 }
Roland Levillain946e1432014-11-11 17:35:19 +00002579
2580 default:
2581 LOG(FATAL) << "Unexpected type conversion from " << input_type
2582 << " to " << result_type;
2583 }
2584 break;
2585
Roland Levillaindff1f282014-11-05 14:15:05 +00002586 case Primitive::kPrimLong:
2587 switch (input_type) {
2588 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002589 case Primitive::kPrimBoolean:
2590 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002591 case Primitive::kPrimByte:
2592 case Primitive::kPrimShort:
2593 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002594 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002595 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002596 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002597 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002598 break;
2599
Roland Levillain624279f2014-12-04 11:54:28 +00002600 case Primitive::kPrimFloat: {
2601 // Processing a Dex `float-to-long' instruction.
2602 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2603 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002604 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002605
Mark Mendell92e83bf2015-05-07 11:25:03 -04002606 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002607 // if input >= (float)LONG_MAX goto done
2608 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002609 __ j(kAboveEqual, &done);
2610 // if input == NaN goto nan
2611 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002612 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002613 __ cvttss2si(output, input, true);
2614 __ jmp(&done);
2615 __ Bind(&nan);
2616 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002617 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002618 __ Bind(&done);
2619 break;
2620 }
2621
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002622 case Primitive::kPrimDouble: {
2623 // Processing a Dex `double-to-long' instruction.
2624 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2625 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002626 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002627
Mark Mendell92e83bf2015-05-07 11:25:03 -04002628 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002629 // if input >= (double)LONG_MAX goto done
2630 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002631 __ j(kAboveEqual, &done);
2632 // if input == NaN goto nan
2633 __ j(kUnordered, &nan);
2634 // output = double-to-long-truncate(input)
2635 __ cvttsd2si(output, input, true);
2636 __ jmp(&done);
2637 __ Bind(&nan);
2638 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002639 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002640 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002641 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002642 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002643
2644 default:
2645 LOG(FATAL) << "Unexpected type conversion from " << input_type
2646 << " to " << result_type;
2647 }
2648 break;
2649
Roland Levillain981e4542014-11-14 11:47:14 +00002650 case Primitive::kPrimChar:
2651 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002652 case Primitive::kPrimBoolean:
2653 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002654 case Primitive::kPrimByte:
2655 case Primitive::kPrimShort:
2656 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002657 // Processing a Dex `int-to-char' instruction.
2658 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002659 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain981e4542014-11-14 11:47:14 +00002660 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002661 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002662 Address(CpuRegister(RSP), in.GetStackIndex()));
2663 } else {
2664 DCHECK(in.GetConstant()->IsIntConstant());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002665 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002666 Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
2667 }
2668 break;
2669
2670 default:
2671 LOG(FATAL) << "Unexpected type conversion from " << input_type
2672 << " to " << result_type;
2673 }
2674 break;
2675
Roland Levillaindff1f282014-11-05 14:15:05 +00002676 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002677 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002678 case Primitive::kPrimBoolean:
2679 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002680 case Primitive::kPrimByte:
2681 case Primitive::kPrimShort:
2682 case Primitive::kPrimInt:
2683 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002684 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002685 if (in.IsRegister()) {
2686 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2687 } else if (in.IsConstant()) {
2688 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2689 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2690 if (v == 0) {
2691 __ xorps(dest, dest);
2692 } else {
2693 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2694 }
2695 } else {
2696 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2697 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2698 }
Roland Levillaincff13742014-11-17 14:32:17 +00002699 break;
2700
2701 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002702 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002703 if (in.IsRegister()) {
2704 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2705 } else if (in.IsConstant()) {
2706 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2707 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2708 if (v == 0) {
2709 __ xorps(dest, dest);
2710 } else {
2711 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2712 }
2713 } else {
2714 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2715 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2716 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002717 break;
2718
Roland Levillaincff13742014-11-17 14:32:17 +00002719 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002720 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002721 if (in.IsFpuRegister()) {
2722 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2723 } else if (in.IsConstant()) {
2724 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2725 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2726 if (bit_cast<int64_t, double>(v) == 0) {
2727 __ xorps(dest, dest);
2728 } else {
2729 __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
2730 }
2731 } else {
2732 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2733 Address(CpuRegister(RSP), in.GetStackIndex()));
2734 }
Roland Levillaincff13742014-11-17 14:32:17 +00002735 break;
2736
2737 default:
2738 LOG(FATAL) << "Unexpected type conversion from " << input_type
2739 << " to " << result_type;
2740 };
2741 break;
2742
Roland Levillaindff1f282014-11-05 14:15:05 +00002743 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002744 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002745 case Primitive::kPrimBoolean:
2746 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002747 case Primitive::kPrimByte:
2748 case Primitive::kPrimShort:
2749 case Primitive::kPrimInt:
2750 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002751 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002752 if (in.IsRegister()) {
2753 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2754 } else if (in.IsConstant()) {
2755 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2756 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2757 if (v == 0) {
2758 __ xorpd(dest, dest);
2759 } else {
2760 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2761 }
2762 } else {
2763 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2764 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2765 }
Roland Levillaincff13742014-11-17 14:32:17 +00002766 break;
2767
2768 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002769 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002770 if (in.IsRegister()) {
2771 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2772 } else if (in.IsConstant()) {
2773 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2774 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2775 if (v == 0) {
2776 __ xorpd(dest, dest);
2777 } else {
2778 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2779 }
2780 } else {
2781 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
2782 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2783 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002784 break;
2785
Roland Levillaincff13742014-11-17 14:32:17 +00002786 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002787 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002788 if (in.IsFpuRegister()) {
2789 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2790 } else if (in.IsConstant()) {
2791 float v = in.GetConstant()->AsFloatConstant()->GetValue();
2792 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
2793 if (bit_cast<int32_t, float>(v) == 0) {
2794 __ xorpd(dest, dest);
2795 } else {
2796 __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
2797 }
2798 } else {
2799 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
2800 Address(CpuRegister(RSP), in.GetStackIndex()));
2801 }
Roland Levillaincff13742014-11-17 14:32:17 +00002802 break;
2803
2804 default:
2805 LOG(FATAL) << "Unexpected type conversion from " << input_type
2806 << " to " << result_type;
2807 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002808 break;
2809
2810 default:
2811 LOG(FATAL) << "Unexpected type conversion from " << input_type
2812 << " to " << result_type;
2813 }
2814}
2815
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002816void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002817 LocationSummary* locations =
2818 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002819 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002820 case Primitive::kPrimInt: {
2821 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002822 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2823 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002824 break;
2825 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002826
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002827 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002828 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05002829 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendellea5af682015-10-22 17:35:49 -04002830 locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05002831 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002832 break;
2833 }
2834
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002835 case Primitive::kPrimDouble:
2836 case Primitive::kPrimFloat: {
2837 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002838 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002839 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002840 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002841 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002842
2843 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002844 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002845 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002846}
2847
2848void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
2849 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002850 Location first = locations->InAt(0);
2851 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002852 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01002853
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002854 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002855 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002856 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002857 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2858 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002859 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2860 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002861 } else {
2862 __ leal(out.AsRegister<CpuRegister>(), Address(
2863 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2864 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002865 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002866 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2867 __ addl(out.AsRegister<CpuRegister>(),
2868 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
2869 } else {
2870 __ leal(out.AsRegister<CpuRegister>(), Address(
2871 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
2872 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002873 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00002874 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002875 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002876 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002877 break;
2878 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002879
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002880 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05002881 if (second.IsRegister()) {
2882 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2883 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002884 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2885 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05002886 } else {
2887 __ leaq(out.AsRegister<CpuRegister>(), Address(
2888 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
2889 }
2890 } else {
2891 DCHECK(second.IsConstant());
2892 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2893 int32_t int32_value = Low32Bits(value);
2894 DCHECK_EQ(int32_value, value);
2895 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2896 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
2897 } else {
2898 __ leaq(out.AsRegister<CpuRegister>(), Address(
2899 first.AsRegister<CpuRegister>(), int32_value));
2900 }
2901 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002902 break;
2903 }
2904
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002905 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002906 if (second.IsFpuRegister()) {
2907 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2908 } else if (second.IsConstant()) {
2909 __ addss(first.AsFpuRegister<XmmRegister>(),
2910 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
2911 } else {
2912 DCHECK(second.IsStackSlot());
2913 __ addss(first.AsFpuRegister<XmmRegister>(),
2914 Address(CpuRegister(RSP), second.GetStackIndex()));
2915 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002916 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002917 }
2918
2919 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002920 if (second.IsFpuRegister()) {
2921 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2922 } else if (second.IsConstant()) {
2923 __ addsd(first.AsFpuRegister<XmmRegister>(),
2924 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
2925 } else {
2926 DCHECK(second.IsDoubleStackSlot());
2927 __ addsd(first.AsFpuRegister<XmmRegister>(),
2928 Address(CpuRegister(RSP), second.GetStackIndex()));
2929 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002930 break;
2931 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002932
2933 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002934 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002935 }
2936}
2937
2938void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002939 LocationSummary* locations =
2940 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002941 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002942 case Primitive::kPrimInt: {
2943 locations->SetInAt(0, Location::RequiresRegister());
2944 locations->SetInAt(1, Location::Any());
2945 locations->SetOut(Location::SameAsFirstInput());
2946 break;
2947 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002948 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002949 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04002950 locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002951 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002952 break;
2953 }
Calin Juravle11351682014-10-23 15:38:15 +01002954 case Primitive::kPrimFloat:
2955 case Primitive::kPrimDouble: {
2956 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04002957 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002958 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002959 break;
Calin Juravle11351682014-10-23 15:38:15 +01002960 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002961 default:
Calin Juravle11351682014-10-23 15:38:15 +01002962 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002963 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002964}
2965
2966void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
2967 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002968 Location first = locations->InAt(0);
2969 Location second = locations->InAt(1);
2970 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002971 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002972 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002973 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002974 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002975 } else if (second.IsConstant()) {
2976 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002977 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002978 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002979 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002980 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00002981 break;
2982 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002983 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002984 if (second.IsConstant()) {
2985 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2986 DCHECK(IsInt<32>(value));
2987 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
2988 } else {
2989 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
2990 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002991 break;
2992 }
2993
Calin Juravle11351682014-10-23 15:38:15 +01002994 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04002995 if (second.IsFpuRegister()) {
2996 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2997 } else if (second.IsConstant()) {
2998 __ subss(first.AsFpuRegister<XmmRegister>(),
2999 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3000 } else {
3001 DCHECK(second.IsStackSlot());
3002 __ subss(first.AsFpuRegister<XmmRegister>(),
3003 Address(CpuRegister(RSP), second.GetStackIndex()));
3004 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003005 break;
Calin Juravle11351682014-10-23 15:38:15 +01003006 }
3007
3008 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003009 if (second.IsFpuRegister()) {
3010 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3011 } else if (second.IsConstant()) {
3012 __ subsd(first.AsFpuRegister<XmmRegister>(),
3013 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3014 } else {
3015 DCHECK(second.IsDoubleStackSlot());
3016 __ subsd(first.AsFpuRegister<XmmRegister>(),
3017 Address(CpuRegister(RSP), second.GetStackIndex()));
3018 }
Calin Juravle11351682014-10-23 15:38:15 +01003019 break;
3020 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003021
3022 default:
Calin Juravle11351682014-10-23 15:38:15 +01003023 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003024 }
3025}
3026
Calin Juravle34bacdf2014-10-07 20:23:36 +01003027void LocationsBuilderX86_64::VisitMul(HMul* mul) {
3028 LocationSummary* locations =
3029 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3030 switch (mul->GetResultType()) {
3031 case Primitive::kPrimInt: {
3032 locations->SetInAt(0, Location::RequiresRegister());
3033 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003034 if (mul->InputAt(1)->IsIntConstant()) {
3035 // Can use 3 operand multiply.
3036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3037 } else {
3038 locations->SetOut(Location::SameAsFirstInput());
3039 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003040 break;
3041 }
3042 case Primitive::kPrimLong: {
3043 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003044 locations->SetInAt(1, Location::Any());
3045 if (mul->InputAt(1)->IsLongConstant() &&
3046 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003047 // Can use 3 operand multiply.
3048 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3049 } else {
3050 locations->SetOut(Location::SameAsFirstInput());
3051 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003052 break;
3053 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003054 case Primitive::kPrimFloat:
3055 case Primitive::kPrimDouble: {
3056 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003057 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01003058 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003059 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003060 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003061
3062 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003063 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003064 }
3065}
3066
3067void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
3068 LocationSummary* locations = mul->GetLocations();
3069 Location first = locations->InAt(0);
3070 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003071 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003072 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003073 case Primitive::kPrimInt:
3074 // The constant may have ended up in a register, so test explicitly to avoid
3075 // problems where the output may not be the same as the first operand.
3076 if (mul->InputAt(1)->IsIntConstant()) {
3077 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3078 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
3079 } else if (second.IsRegister()) {
3080 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003081 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003082 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003083 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003084 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00003085 __ imull(first.AsRegister<CpuRegister>(),
3086 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003087 }
3088 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01003089 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003090 // The constant may have ended up in a register, so test explicitly to avoid
3091 // problems where the output may not be the same as the first operand.
3092 if (mul->InputAt(1)->IsLongConstant()) {
3093 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
3094 if (IsInt<32>(value)) {
3095 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
3096 Immediate(static_cast<int32_t>(value)));
3097 } else {
3098 // Have to use the constant area.
3099 DCHECK(first.Equals(out));
3100 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
3101 }
3102 } else if (second.IsRegister()) {
3103 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003104 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003105 } else {
3106 DCHECK(second.IsDoubleStackSlot());
3107 DCHECK(first.Equals(out));
3108 __ imulq(first.AsRegister<CpuRegister>(),
3109 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003110 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003111 break;
3112 }
3113
Calin Juravleb5bfa962014-10-21 18:02:24 +01003114 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003115 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003116 if (second.IsFpuRegister()) {
3117 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3118 } else if (second.IsConstant()) {
3119 __ mulss(first.AsFpuRegister<XmmRegister>(),
3120 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3121 } else {
3122 DCHECK(second.IsStackSlot());
3123 __ mulss(first.AsFpuRegister<XmmRegister>(),
3124 Address(CpuRegister(RSP), second.GetStackIndex()));
3125 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003126 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003127 }
3128
3129 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003130 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003131 if (second.IsFpuRegister()) {
3132 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3133 } else if (second.IsConstant()) {
3134 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3135 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3136 } else {
3137 DCHECK(second.IsDoubleStackSlot());
3138 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3139 Address(CpuRegister(RSP), second.GetStackIndex()));
3140 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003141 break;
3142 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003143
3144 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003145 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003146 }
3147}
3148
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003149void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
3150 uint32_t stack_adjustment, bool is_float) {
3151 if (source.IsStackSlot()) {
3152 DCHECK(is_float);
3153 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3154 } else if (source.IsDoubleStackSlot()) {
3155 DCHECK(!is_float);
3156 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3157 } else {
3158 // Write the value to the temporary location on the stack and load to FP stack.
3159 if (is_float) {
3160 Location stack_temp = Location::StackSlot(temp_offset);
3161 codegen_->Move(stack_temp, source);
3162 __ flds(Address(CpuRegister(RSP), temp_offset));
3163 } else {
3164 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3165 codegen_->Move(stack_temp, source);
3166 __ fldl(Address(CpuRegister(RSP), temp_offset));
3167 }
3168 }
3169}
3170
3171void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
3172 Primitive::Type type = rem->GetResultType();
3173 bool is_float = type == Primitive::kPrimFloat;
3174 size_t elem_size = Primitive::ComponentSize(type);
3175 LocationSummary* locations = rem->GetLocations();
3176 Location first = locations->InAt(0);
3177 Location second = locations->InAt(1);
3178 Location out = locations->Out();
3179
3180 // Create stack space for 2 elements.
3181 // TODO: enhance register allocator to ask for stack temporaries.
3182 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
3183
3184 // Load the values to the FP stack in reverse order, using temporaries if needed.
3185 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
3186 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
3187
3188 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003189 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003190 __ Bind(&retry);
3191 __ fprem();
3192
3193 // Move FP status to AX.
3194 __ fstsw();
3195
3196 // And see if the argument reduction is complete. This is signaled by the
3197 // C2 FPU flag bit set to 0.
3198 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
3199 __ j(kNotEqual, &retry);
3200
3201 // We have settled on the final value. Retrieve it into an XMM register.
3202 // Store FP top of stack to real stack.
3203 if (is_float) {
3204 __ fsts(Address(CpuRegister(RSP), 0));
3205 } else {
3206 __ fstl(Address(CpuRegister(RSP), 0));
3207 }
3208
3209 // Pop the 2 items from the FP stack.
3210 __ fucompp();
3211
3212 // Load the value from the stack into an XMM register.
3213 DCHECK(out.IsFpuRegister()) << out;
3214 if (is_float) {
3215 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3216 } else {
3217 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3218 }
3219
3220 // And remove the temporary stack space we allocated.
3221 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
3222}
3223
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003224void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3225 DCHECK(instruction->IsDiv() || instruction->IsRem());
3226
3227 LocationSummary* locations = instruction->GetLocations();
3228 Location second = locations->InAt(1);
3229 DCHECK(second.IsConstant());
3230
3231 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3232 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003233 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003234
3235 DCHECK(imm == 1 || imm == -1);
3236
3237 switch (instruction->GetResultType()) {
3238 case Primitive::kPrimInt: {
3239 if (instruction->IsRem()) {
3240 __ xorl(output_register, output_register);
3241 } else {
3242 __ movl(output_register, input_register);
3243 if (imm == -1) {
3244 __ negl(output_register);
3245 }
3246 }
3247 break;
3248 }
3249
3250 case Primitive::kPrimLong: {
3251 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003252 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003253 } else {
3254 __ movq(output_register, input_register);
3255 if (imm == -1) {
3256 __ negq(output_register);
3257 }
3258 }
3259 break;
3260 }
3261
3262 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003263 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003264 }
3265}
3266
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003267void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003268 LocationSummary* locations = instruction->GetLocations();
3269 Location second = locations->InAt(1);
3270
3271 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3272 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3273
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003274 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003275
3276 DCHECK(IsPowerOfTwo(std::abs(imm)));
3277
3278 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3279
3280 if (instruction->GetResultType() == Primitive::kPrimInt) {
3281 __ leal(tmp, Address(numerator, std::abs(imm) - 1));
3282 __ testl(numerator, numerator);
3283 __ cmov(kGreaterEqual, tmp, numerator);
3284 int shift = CTZ(imm);
3285 __ sarl(tmp, Immediate(shift));
3286
3287 if (imm < 0) {
3288 __ negl(tmp);
3289 }
3290
3291 __ movl(output_register, tmp);
3292 } else {
3293 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3294 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3295
Mark Mendell92e83bf2015-05-07 11:25:03 -04003296 codegen_->Load64BitValue(rdx, std::abs(imm) - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003297 __ addq(rdx, numerator);
3298 __ testq(numerator, numerator);
3299 __ cmov(kGreaterEqual, rdx, numerator);
3300 int shift = CTZ(imm);
3301 __ sarq(rdx, Immediate(shift));
3302
3303 if (imm < 0) {
3304 __ negq(rdx);
3305 }
3306
3307 __ movq(output_register, rdx);
3308 }
3309}
3310
3311void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3312 DCHECK(instruction->IsDiv() || instruction->IsRem());
3313
3314 LocationSummary* locations = instruction->GetLocations();
3315 Location second = locations->InAt(1);
3316
3317 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3318 : locations->GetTemp(0).AsRegister<CpuRegister>();
3319 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3320 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3321 : locations->Out().AsRegister<CpuRegister>();
3322 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3323
3324 DCHECK_EQ(RAX, eax.AsRegister());
3325 DCHECK_EQ(RDX, edx.AsRegister());
3326 if (instruction->IsDiv()) {
3327 DCHECK_EQ(RAX, out.AsRegister());
3328 } else {
3329 DCHECK_EQ(RDX, out.AsRegister());
3330 }
3331
3332 int64_t magic;
3333 int shift;
3334
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003335 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003336 if (instruction->GetResultType() == Primitive::kPrimInt) {
3337 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3338
3339 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3340
3341 __ movl(numerator, eax);
3342
Mark Mendell0c9497d2015-08-21 09:30:05 -04003343 NearLabel no_div;
3344 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003345 __ testl(eax, eax);
3346 __ j(kNotEqual, &no_div);
3347
3348 __ xorl(out, out);
3349 __ jmp(&end);
3350
3351 __ Bind(&no_div);
3352
3353 __ movl(eax, Immediate(magic));
3354 __ imull(numerator);
3355
3356 if (imm > 0 && magic < 0) {
3357 __ addl(edx, numerator);
3358 } else if (imm < 0 && magic > 0) {
3359 __ subl(edx, numerator);
3360 }
3361
3362 if (shift != 0) {
3363 __ sarl(edx, Immediate(shift));
3364 }
3365
3366 __ movl(eax, edx);
3367 __ shrl(edx, Immediate(31));
3368 __ addl(edx, eax);
3369
3370 if (instruction->IsRem()) {
3371 __ movl(eax, numerator);
3372 __ imull(edx, Immediate(imm));
3373 __ subl(eax, edx);
3374 __ movl(edx, eax);
3375 } else {
3376 __ movl(eax, edx);
3377 }
3378 __ Bind(&end);
3379 } else {
3380 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3381
3382 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3383
3384 CpuRegister rax = eax;
3385 CpuRegister rdx = edx;
3386
3387 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3388
3389 // Save the numerator.
3390 __ movq(numerator, rax);
3391
3392 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003393 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003394
3395 // RDX:RAX = magic * numerator
3396 __ imulq(numerator);
3397
3398 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003399 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003400 __ addq(rdx, numerator);
3401 } else if (imm < 0 && magic > 0) {
3402 // RDX -= numerator
3403 __ subq(rdx, numerator);
3404 }
3405
3406 // Shift if needed.
3407 if (shift != 0) {
3408 __ sarq(rdx, Immediate(shift));
3409 }
3410
3411 // RDX += 1 if RDX < 0
3412 __ movq(rax, rdx);
3413 __ shrq(rdx, Immediate(63));
3414 __ addq(rdx, rax);
3415
3416 if (instruction->IsRem()) {
3417 __ movq(rax, numerator);
3418
3419 if (IsInt<32>(imm)) {
3420 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3421 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003422 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003423 }
3424
3425 __ subq(rax, rdx);
3426 __ movq(rdx, rax);
3427 } else {
3428 __ movq(rax, rdx);
3429 }
3430 }
3431}
3432
Calin Juravlebacfec32014-11-14 15:54:36 +00003433void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3434 DCHECK(instruction->IsDiv() || instruction->IsRem());
3435 Primitive::Type type = instruction->GetResultType();
3436 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3437
3438 bool is_div = instruction->IsDiv();
3439 LocationSummary* locations = instruction->GetLocations();
3440
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003441 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3442 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003443
Roland Levillain271ab9c2014-11-27 15:23:57 +00003444 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003445 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003446
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003447 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003448 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003449
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003450 if (imm == 0) {
3451 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3452 } else if (imm == 1 || imm == -1) {
3453 DivRemOneOrMinusOne(instruction);
3454 } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003455 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003456 } else {
3457 DCHECK(imm <= -2 || imm >= 2);
3458 GenerateDivRemWithAnyConstant(instruction);
3459 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003460 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003461 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003462 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
3463 out.AsRegister(), type, is_div);
3464 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003465
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003466 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3467 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3468 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3469 // so it's safe to just use negl instead of more complex comparisons.
3470 if (type == Primitive::kPrimInt) {
3471 __ cmpl(second_reg, Immediate(-1));
3472 __ j(kEqual, slow_path->GetEntryLabel());
3473 // edx:eax <- sign-extended of eax
3474 __ cdq();
3475 // eax = quotient, edx = remainder
3476 __ idivl(second_reg);
3477 } else {
3478 __ cmpq(second_reg, Immediate(-1));
3479 __ j(kEqual, slow_path->GetEntryLabel());
3480 // rdx:rax <- sign-extended of rax
3481 __ cqo();
3482 // rax = quotient, rdx = remainder
3483 __ idivq(second_reg);
3484 }
3485 __ Bind(slow_path->GetExitLabel());
3486 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003487}
3488
Calin Juravle7c4954d2014-10-28 16:57:40 +00003489void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3490 LocationSummary* locations =
3491 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3492 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003493 case Primitive::kPrimInt:
3494 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003495 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003496 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003497 locations->SetOut(Location::SameAsFirstInput());
3498 // Intel uses edx:eax as the dividend.
3499 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003500 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3501 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3502 // output and request another temp.
3503 if (div->InputAt(1)->IsConstant()) {
3504 locations->AddTemp(Location::RequiresRegister());
3505 }
Calin Juravled0d48522014-11-04 16:40:20 +00003506 break;
3507 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003508
Calin Juravle7c4954d2014-10-28 16:57:40 +00003509 case Primitive::kPrimFloat:
3510 case Primitive::kPrimDouble: {
3511 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003512 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003513 locations->SetOut(Location::SameAsFirstInput());
3514 break;
3515 }
3516
3517 default:
3518 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3519 }
3520}
3521
3522void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3523 LocationSummary* locations = div->GetLocations();
3524 Location first = locations->InAt(0);
3525 Location second = locations->InAt(1);
3526 DCHECK(first.Equals(locations->Out()));
3527
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003528 Primitive::Type type = div->GetResultType();
3529 switch (type) {
3530 case Primitive::kPrimInt:
3531 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003532 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003533 break;
3534 }
3535
Calin Juravle7c4954d2014-10-28 16:57:40 +00003536 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003537 if (second.IsFpuRegister()) {
3538 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3539 } else if (second.IsConstant()) {
3540 __ divss(first.AsFpuRegister<XmmRegister>(),
3541 codegen_->LiteralFloatAddress(second.GetConstant()->AsFloatConstant()->GetValue()));
3542 } else {
3543 DCHECK(second.IsStackSlot());
3544 __ divss(first.AsFpuRegister<XmmRegister>(),
3545 Address(CpuRegister(RSP), second.GetStackIndex()));
3546 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003547 break;
3548 }
3549
3550 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003551 if (second.IsFpuRegister()) {
3552 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3553 } else if (second.IsConstant()) {
3554 __ divsd(first.AsFpuRegister<XmmRegister>(),
3555 codegen_->LiteralDoubleAddress(second.GetConstant()->AsDoubleConstant()->GetValue()));
3556 } else {
3557 DCHECK(second.IsDoubleStackSlot());
3558 __ divsd(first.AsFpuRegister<XmmRegister>(),
3559 Address(CpuRegister(RSP), second.GetStackIndex()));
3560 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003561 break;
3562 }
3563
3564 default:
3565 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3566 }
3567}
3568
Calin Juravlebacfec32014-11-14 15:54:36 +00003569void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003570 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003571 LocationSummary* locations =
3572 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003573
3574 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003575 case Primitive::kPrimInt:
3576 case Primitive::kPrimLong: {
3577 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003578 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003579 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3580 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003581 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3582 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3583 // output and request another temp.
3584 if (rem->InputAt(1)->IsConstant()) {
3585 locations->AddTemp(Location::RequiresRegister());
3586 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003587 break;
3588 }
3589
3590 case Primitive::kPrimFloat:
3591 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003592 locations->SetInAt(0, Location::Any());
3593 locations->SetInAt(1, Location::Any());
3594 locations->SetOut(Location::RequiresFpuRegister());
3595 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003596 break;
3597 }
3598
3599 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003600 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003601 }
3602}
3603
3604void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3605 Primitive::Type type = rem->GetResultType();
3606 switch (type) {
3607 case Primitive::kPrimInt:
3608 case Primitive::kPrimLong: {
3609 GenerateDivRemIntegral(rem);
3610 break;
3611 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003612 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003613 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003614 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003615 break;
3616 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003617 default:
3618 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3619 }
3620}
3621
Calin Juravled0d48522014-11-04 16:40:20 +00003622void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003623 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3624 ? LocationSummary::kCallOnSlowPath
3625 : LocationSummary::kNoCall;
3626 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled0d48522014-11-04 16:40:20 +00003627 locations->SetInAt(0, Location::Any());
3628 if (instruction->HasUses()) {
3629 locations->SetOut(Location::SameAsFirstInput());
3630 }
3631}
3632
3633void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003634 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003635 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3636 codegen_->AddSlowPath(slow_path);
3637
3638 LocationSummary* locations = instruction->GetLocations();
3639 Location value = locations->InAt(0);
3640
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003641 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003642 case Primitive::kPrimByte:
3643 case Primitive::kPrimChar:
3644 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003645 case Primitive::kPrimInt: {
3646 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003647 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003648 __ j(kEqual, slow_path->GetEntryLabel());
3649 } else if (value.IsStackSlot()) {
3650 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3651 __ j(kEqual, slow_path->GetEntryLabel());
3652 } else {
3653 DCHECK(value.IsConstant()) << value;
3654 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3655 __ jmp(slow_path->GetEntryLabel());
3656 }
3657 }
3658 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003659 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003660 case Primitive::kPrimLong: {
3661 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003662 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003663 __ j(kEqual, slow_path->GetEntryLabel());
3664 } else if (value.IsDoubleStackSlot()) {
3665 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3666 __ j(kEqual, slow_path->GetEntryLabel());
3667 } else {
3668 DCHECK(value.IsConstant()) << value;
3669 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3670 __ jmp(slow_path->GetEntryLabel());
3671 }
3672 }
3673 break;
3674 }
3675 default:
3676 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003677 }
Calin Juravled0d48522014-11-04 16:40:20 +00003678}
3679
Calin Juravle9aec02f2014-11-18 23:06:35 +00003680void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3681 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3682
3683 LocationSummary* locations =
3684 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3685
3686 switch (op->GetResultType()) {
3687 case Primitive::kPrimInt:
3688 case Primitive::kPrimLong: {
3689 locations->SetInAt(0, Location::RequiresRegister());
3690 // The shift count needs to be in CL.
3691 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3692 locations->SetOut(Location::SameAsFirstInput());
3693 break;
3694 }
3695 default:
3696 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3697 }
3698}
3699
3700void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3701 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3702
3703 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003704 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003705 Location second = locations->InAt(1);
3706
3707 switch (op->GetResultType()) {
3708 case Primitive::kPrimInt: {
3709 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003710 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003711 if (op->IsShl()) {
3712 __ shll(first_reg, second_reg);
3713 } else if (op->IsShr()) {
3714 __ sarl(first_reg, second_reg);
3715 } else {
3716 __ shrl(first_reg, second_reg);
3717 }
3718 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003719 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003720 if (op->IsShl()) {
3721 __ shll(first_reg, imm);
3722 } else if (op->IsShr()) {
3723 __ sarl(first_reg, imm);
3724 } else {
3725 __ shrl(first_reg, imm);
3726 }
3727 }
3728 break;
3729 }
3730 case Primitive::kPrimLong: {
3731 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003732 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003733 if (op->IsShl()) {
3734 __ shlq(first_reg, second_reg);
3735 } else if (op->IsShr()) {
3736 __ sarq(first_reg, second_reg);
3737 } else {
3738 __ shrq(first_reg, second_reg);
3739 }
3740 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00003741 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003742 if (op->IsShl()) {
3743 __ shlq(first_reg, imm);
3744 } else if (op->IsShr()) {
3745 __ sarq(first_reg, imm);
3746 } else {
3747 __ shrq(first_reg, imm);
3748 }
3749 }
3750 break;
3751 }
3752 default:
3753 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3754 }
3755}
3756
3757void LocationsBuilderX86_64::VisitShl(HShl* shl) {
3758 HandleShift(shl);
3759}
3760
3761void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
3762 HandleShift(shl);
3763}
3764
3765void LocationsBuilderX86_64::VisitShr(HShr* shr) {
3766 HandleShift(shr);
3767}
3768
3769void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
3770 HandleShift(shr);
3771}
3772
3773void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
3774 HandleShift(ushr);
3775}
3776
3777void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
3778 HandleShift(ushr);
3779}
3780
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003781void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003782 LocationSummary* locations =
3783 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003784 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray729645a2015-11-19 13:29:02 +00003785 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3786 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003787 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003788}
3789
3790void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003791 // Note: if heap poisoning is enabled, the entry point takes cares
3792 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003793 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3794 instruction,
3795 instruction->GetDexPc(),
3796 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003797 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003798
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003799 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003800}
3801
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003802void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
3803 LocationSummary* locations =
3804 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3805 InvokeRuntimeCallingConvention calling_convention;
3806 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003807 locations->SetOut(Location::RegisterLocation(RAX));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003808 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003809 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003810}
3811
3812void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
3813 InvokeRuntimeCallingConvention calling_convention;
Mark Mendell92e83bf2015-05-07 11:25:03 -04003814 codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
3815 instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003816 // Note: if heap poisoning is enabled, the entry point takes cares
3817 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003818 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3819 instruction,
3820 instruction->GetDexPc(),
3821 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003822 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003823
3824 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003825}
3826
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003827void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003828 LocationSummary* locations =
3829 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003830 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3831 if (location.IsStackSlot()) {
3832 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3833 } else if (location.IsDoubleStackSlot()) {
3834 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3835 }
3836 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003837}
3838
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003839void InstructionCodeGeneratorX86_64::VisitParameterValue(
3840 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003841 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003842}
3843
3844void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
3845 LocationSummary* locations =
3846 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3847 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3848}
3849
3850void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
3851 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3852 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003853}
3854
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003855void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003856 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003857 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003858 locations->SetInAt(0, Location::RequiresRegister());
3859 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003860}
3861
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003862void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
3863 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003864 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3865 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003866 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003867 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003868 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003869 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003870 break;
3871
3872 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003873 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003874 break;
3875
3876 default:
3877 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3878 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003879}
3880
David Brazdil66d126e2015-04-03 16:02:44 +01003881void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
3882 LocationSummary* locations =
3883 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3884 locations->SetInAt(0, Location::RequiresRegister());
3885 locations->SetOut(Location::SameAsFirstInput());
3886}
3887
3888void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003889 LocationSummary* locations = bool_not->GetLocations();
3890 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
3891 locations->Out().AsRegister<CpuRegister>().AsRegister());
3892 Location out = locations->Out();
3893 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
3894}
3895
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003896void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003897 LocationSummary* locations =
3898 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003899 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3900 locations->SetInAt(i, Location::Any());
3901 }
3902 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003903}
3904
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003905void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003906 LOG(FATAL) << "Unimplemented";
3907}
3908
Calin Juravle52c48962014-12-16 17:02:57 +00003909void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
3910 /*
3911 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3912 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3913 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3914 */
3915 switch (kind) {
3916 case MemBarrierKind::kAnyAny: {
3917 __ mfence();
3918 break;
3919 }
3920 case MemBarrierKind::kAnyStore:
3921 case MemBarrierKind::kLoadAny:
3922 case MemBarrierKind::kStoreStore: {
3923 // nop
3924 break;
3925 }
3926 default:
3927 LOG(FATAL) << "Unexpected memory barier " << kind;
3928 }
3929}
3930
3931void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
3932 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3933
Roland Levillain0d5a2812015-11-13 10:07:31 +00003934 bool object_field_get_with_read_barrier =
3935 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003936 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00003937 new (GetGraph()->GetArena()) LocationSummary(instruction,
3938 object_field_get_with_read_barrier ?
3939 LocationSummary::kCallOnSlowPath :
3940 LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00003941 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003942 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3943 locations->SetOut(Location::RequiresFpuRegister());
3944 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00003945 // The output overlaps for an object field get when read barriers
3946 // are enabled: we do not want the move to overwrite the object's
3947 // location, as we need it to emit the read barrier.
3948 locations->SetOut(
3949 Location::RequiresRegister(),
3950 object_field_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003951 }
Calin Juravle52c48962014-12-16 17:02:57 +00003952}
3953
3954void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
3955 const FieldInfo& field_info) {
3956 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
3957
3958 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00003959 Location base_loc = locations->InAt(0);
3960 CpuRegister base = base_loc.AsRegister<CpuRegister>();
Calin Juravle52c48962014-12-16 17:02:57 +00003961 Location out = locations->Out();
3962 bool is_volatile = field_info.IsVolatile();
3963 Primitive::Type field_type = field_info.GetFieldType();
3964 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3965
3966 switch (field_type) {
3967 case Primitive::kPrimBoolean: {
3968 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3969 break;
3970 }
3971
3972 case Primitive::kPrimByte: {
3973 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
3974 break;
3975 }
3976
3977 case Primitive::kPrimShort: {
3978 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3979 break;
3980 }
3981
3982 case Primitive::kPrimChar: {
3983 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
3984 break;
3985 }
3986
3987 case Primitive::kPrimInt:
3988 case Primitive::kPrimNot: {
3989 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
3990 break;
3991 }
3992
3993 case Primitive::kPrimLong: {
3994 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
3995 break;
3996 }
3997
3998 case Primitive::kPrimFloat: {
3999 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4000 break;
4001 }
4002
4003 case Primitive::kPrimDouble: {
4004 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4005 break;
4006 }
4007
4008 case Primitive::kPrimVoid:
4009 LOG(FATAL) << "Unreachable type " << field_type;
4010 UNREACHABLE();
4011 }
4012
Calin Juravle77520bc2015-01-12 18:45:46 +00004013 codegen_->MaybeRecordImplicitNullCheck(instruction);
4014
Calin Juravle52c48962014-12-16 17:02:57 +00004015 if (is_volatile) {
4016 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4017 }
Roland Levillain4d027112015-07-01 15:41:14 +01004018
4019 if (field_type == Primitive::kPrimNot) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004020 codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004021 }
Calin Juravle52c48962014-12-16 17:02:57 +00004022}
4023
4024void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
4025 const FieldInfo& field_info) {
4026 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4027
4028 LocationSummary* locations =
4029 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01004030 Primitive::Type field_type = field_info.GetFieldType();
Mark Mendellea5af682015-10-22 17:35:49 -04004031 bool is_volatile = field_info.IsVolatile();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004032 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01004033 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004034
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004035 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004036 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
Mark Mendellea5af682015-10-22 17:35:49 -04004037 if (is_volatile) {
4038 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4039 locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
4040 } else {
4041 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
4042 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004043 } else {
Mark Mendellea5af682015-10-22 17:35:49 -04004044 if (is_volatile) {
4045 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4046 locations->SetInAt(1, Location::RegisterOrInt32Constant(instruction->InputAt(1)));
4047 } else {
4048 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4049 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004050 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004051 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004052 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01004053 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004054 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01004055 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4056 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004057 locations->AddTemp(Location::RequiresRegister());
4058 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004059}
4060
Calin Juravle52c48962014-12-16 17:02:57 +00004061void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004062 const FieldInfo& field_info,
4063 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004064 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4065
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004066 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004067 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
4068 Location value = locations->InAt(1);
4069 bool is_volatile = field_info.IsVolatile();
4070 Primitive::Type field_type = field_info.GetFieldType();
4071 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4072
4073 if (is_volatile) {
4074 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4075 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004076
Mark Mendellea5af682015-10-22 17:35:49 -04004077 bool maybe_record_implicit_null_check_done = false;
4078
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004079 switch (field_type) {
4080 case Primitive::kPrimBoolean:
4081 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04004082 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004083 int8_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004084 __ movb(Address(base, offset), Immediate(v));
4085 } else {
4086 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
4087 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004088 break;
4089 }
4090
4091 case Primitive::kPrimShort:
4092 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04004093 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004094 int16_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004095 __ movw(Address(base, offset), Immediate(v));
4096 } else {
4097 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
4098 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004099 break;
4100 }
4101
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004102 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004103 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04004104 if (value.IsConstant()) {
4105 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004106 // `field_type == Primitive::kPrimNot` implies `v == 0`.
4107 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
4108 // Note: if heap poisoning is enabled, no need to poison
4109 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01004110 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04004111 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01004112 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4113 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4114 __ movl(temp, value.AsRegister<CpuRegister>());
4115 __ PoisonHeapReference(temp);
4116 __ movl(Address(base, offset), temp);
4117 } else {
4118 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
4119 }
Mark Mendell40741f32015-04-20 22:10:34 -04004120 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004121 break;
4122 }
4123
4124 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04004125 if (value.IsConstant()) {
4126 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004127 codegen_->MoveInt64ToAddress(Address(base, offset),
4128 Address(base, offset + sizeof(int32_t)),
4129 v,
4130 instruction);
4131 maybe_record_implicit_null_check_done = true;
Mark Mendell40741f32015-04-20 22:10:34 -04004132 } else {
4133 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
4134 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004135 break;
4136 }
4137
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004138 case Primitive::kPrimFloat: {
Mark Mendellea5af682015-10-22 17:35:49 -04004139 if (value.IsConstant()) {
4140 int32_t v =
4141 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4142 __ movl(Address(base, offset), Immediate(v));
4143 } else {
4144 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4145 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004146 break;
4147 }
4148
4149 case Primitive::kPrimDouble: {
Mark Mendellea5af682015-10-22 17:35:49 -04004150 if (value.IsConstant()) {
4151 int64_t v =
4152 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4153 codegen_->MoveInt64ToAddress(Address(base, offset),
4154 Address(base, offset + sizeof(int32_t)),
4155 v,
4156 instruction);
4157 maybe_record_implicit_null_check_done = true;
4158 } else {
4159 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4160 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004161 break;
4162 }
4163
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004164 case Primitive::kPrimVoid:
4165 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004166 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004167 }
Calin Juravle52c48962014-12-16 17:02:57 +00004168
Mark Mendellea5af682015-10-22 17:35:49 -04004169 if (!maybe_record_implicit_null_check_done) {
4170 codegen_->MaybeRecordImplicitNullCheck(instruction);
4171 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004172
4173 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4174 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4175 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004176 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004177 }
4178
Calin Juravle52c48962014-12-16 17:02:57 +00004179 if (is_volatile) {
4180 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4181 }
4182}
4183
4184void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4185 HandleFieldSet(instruction, instruction->GetFieldInfo());
4186}
4187
4188void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004189 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004190}
4191
4192void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004193 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004194}
4195
4196void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004197 HandleFieldGet(instruction, instruction->GetFieldInfo());
4198}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004199
Calin Juravle52c48962014-12-16 17:02:57 +00004200void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4201 HandleFieldGet(instruction);
4202}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004203
Calin Juravle52c48962014-12-16 17:02:57 +00004204void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4205 HandleFieldGet(instruction, instruction->GetFieldInfo());
4206}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004207
Calin Juravle52c48962014-12-16 17:02:57 +00004208void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4209 HandleFieldSet(instruction, instruction->GetFieldInfo());
4210}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004211
Calin Juravle52c48962014-12-16 17:02:57 +00004212void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004213 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004214}
4215
Calin Juravlee460d1d2015-09-29 04:52:17 +01004216void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
4217 HUnresolvedInstanceFieldGet* instruction) {
4218 FieldAccessCallingConventionX86_64 calling_convention;
4219 codegen_->CreateUnresolvedFieldLocationSummary(
4220 instruction, instruction->GetFieldType(), calling_convention);
4221}
4222
4223void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
4224 HUnresolvedInstanceFieldGet* instruction) {
4225 FieldAccessCallingConventionX86_64 calling_convention;
4226 codegen_->GenerateUnresolvedFieldAccess(instruction,
4227 instruction->GetFieldType(),
4228 instruction->GetFieldIndex(),
4229 instruction->GetDexPc(),
4230 calling_convention);
4231}
4232
4233void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
4234 HUnresolvedInstanceFieldSet* instruction) {
4235 FieldAccessCallingConventionX86_64 calling_convention;
4236 codegen_->CreateUnresolvedFieldLocationSummary(
4237 instruction, instruction->GetFieldType(), calling_convention);
4238}
4239
4240void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
4241 HUnresolvedInstanceFieldSet* instruction) {
4242 FieldAccessCallingConventionX86_64 calling_convention;
4243 codegen_->GenerateUnresolvedFieldAccess(instruction,
4244 instruction->GetFieldType(),
4245 instruction->GetFieldIndex(),
4246 instruction->GetDexPc(),
4247 calling_convention);
4248}
4249
4250void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
4251 HUnresolvedStaticFieldGet* instruction) {
4252 FieldAccessCallingConventionX86_64 calling_convention;
4253 codegen_->CreateUnresolvedFieldLocationSummary(
4254 instruction, instruction->GetFieldType(), calling_convention);
4255}
4256
4257void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
4258 HUnresolvedStaticFieldGet* instruction) {
4259 FieldAccessCallingConventionX86_64 calling_convention;
4260 codegen_->GenerateUnresolvedFieldAccess(instruction,
4261 instruction->GetFieldType(),
4262 instruction->GetFieldIndex(),
4263 instruction->GetDexPc(),
4264 calling_convention);
4265}
4266
4267void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
4268 HUnresolvedStaticFieldSet* instruction) {
4269 FieldAccessCallingConventionX86_64 calling_convention;
4270 codegen_->CreateUnresolvedFieldLocationSummary(
4271 instruction, instruction->GetFieldType(), calling_convention);
4272}
4273
4274void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
4275 HUnresolvedStaticFieldSet* instruction) {
4276 FieldAccessCallingConventionX86_64 calling_convention;
4277 codegen_->GenerateUnresolvedFieldAccess(instruction,
4278 instruction->GetFieldType(),
4279 instruction->GetFieldIndex(),
4280 instruction->GetDexPc(),
4281 calling_convention);
4282}
4283
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004284void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004285 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4286 ? LocationSummary::kCallOnSlowPath
4287 : LocationSummary::kNoCall;
4288 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4289 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004290 ? Location::RequiresRegister()
4291 : Location::Any();
4292 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004293 if (instruction->HasUses()) {
4294 locations->SetOut(Location::SameAsFirstInput());
4295 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004296}
4297
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004298void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004299 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4300 return;
4301 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004302 LocationSummary* locations = instruction->GetLocations();
4303 Location obj = locations->InAt(0);
4304
4305 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
4306 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4307}
4308
4309void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004310 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004311 codegen_->AddSlowPath(slow_path);
4312
4313 LocationSummary* locations = instruction->GetLocations();
4314 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004315
4316 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004317 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004318 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004319 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004320 } else {
4321 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004322 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004323 __ jmp(slow_path->GetEntryLabel());
4324 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004325 }
4326 __ j(kEqual, slow_path->GetEntryLabel());
4327}
4328
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004329void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004330 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004331 GenerateImplicitNullCheck(instruction);
4332 } else {
4333 GenerateExplicitNullCheck(instruction);
4334 }
4335}
4336
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004337void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004338 bool object_array_get_with_read_barrier =
4339 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004340 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004341 new (GetGraph()->GetArena()) LocationSummary(instruction,
4342 object_array_get_with_read_barrier ?
4343 LocationSummary::kCallOnSlowPath :
4344 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004345 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004346 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004347 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4348 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4349 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004350 // The output overlaps for an object array get when read barriers
4351 // are enabled: we do not want the move to overwrite the array's
4352 // location, as we need it to emit the read barrier.
4353 locations->SetOut(
4354 Location::RequiresRegister(),
4355 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004356 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004357}
4358
4359void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4360 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004361 Location obj_loc = locations->InAt(0);
4362 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004363 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004364 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004365
Roland Levillain4d027112015-07-01 15:41:14 +01004366 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004367 case Primitive::kPrimBoolean: {
4368 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004369 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004370 if (index.IsConstant()) {
4371 __ movzxb(out, Address(obj,
4372 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4373 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004374 __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004375 }
4376 break;
4377 }
4378
4379 case Primitive::kPrimByte: {
4380 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004381 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004382 if (index.IsConstant()) {
4383 __ movsxb(out, Address(obj,
4384 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4385 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004386 __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004387 }
4388 break;
4389 }
4390
4391 case Primitive::kPrimShort: {
4392 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004393 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004394 if (index.IsConstant()) {
4395 __ movsxw(out, Address(obj,
4396 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4397 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004398 __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004399 }
4400 break;
4401 }
4402
4403 case Primitive::kPrimChar: {
4404 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004406 if (index.IsConstant()) {
4407 __ movzxw(out, Address(obj,
4408 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4409 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004410 __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004411 }
4412 break;
4413 }
4414
4415 case Primitive::kPrimInt:
4416 case Primitive::kPrimNot: {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004417 static_assert(
4418 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4419 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004420 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004421 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004422 if (index.IsConstant()) {
4423 __ movl(out, Address(obj,
4424 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4425 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004426 __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004427 }
4428 break;
4429 }
4430
4431 case Primitive::kPrimLong: {
4432 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004433 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004434 if (index.IsConstant()) {
4435 __ movq(out, Address(obj,
4436 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4437 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004438 __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004439 }
4440 break;
4441 }
4442
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004443 case Primitive::kPrimFloat: {
4444 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004445 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004446 if (index.IsConstant()) {
4447 __ movss(out, Address(obj,
4448 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4449 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004450 __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004451 }
4452 break;
4453 }
4454
4455 case Primitive::kPrimDouble: {
4456 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004457 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004458 if (index.IsConstant()) {
4459 __ movsd(out, Address(obj,
4460 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4461 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004462 __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004463 }
4464 break;
4465 }
4466
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004467 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004468 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004469 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004470 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004471 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004472
4473 if (type == Primitive::kPrimNot) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004474 static_assert(
4475 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4476 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4477 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4478 Location out = locations->Out();
4479 if (index.IsConstant()) {
4480 uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4481 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4482 } else {
4483 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4484 }
Roland Levillain4d027112015-07-01 15:41:14 +01004485 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004486}
4487
4488void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004489 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004490
4491 bool needs_write_barrier =
4492 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004493 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004494 bool object_array_set_with_read_barrier =
4495 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004496
Nicolas Geoffray39468442014-09-02 15:17:15 +01004497 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004498 instruction,
Roland Levillain0d5a2812015-11-13 10:07:31 +00004499 (may_need_runtime_call || object_array_set_with_read_barrier) ?
4500 LocationSummary::kCallOnSlowPath :
4501 LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004502
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004503 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04004504 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4505 if (Primitive::IsFloatingPointType(value_type)) {
4506 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004507 } else {
4508 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4509 }
4510
4511 if (needs_write_barrier) {
4512 // Temporary registers for the write barrier.
Roland Levillain0d5a2812015-11-13 10:07:31 +00004513
4514 // This first temporary register is possibly used for heap
4515 // reference poisoning and/or read barrier emission too.
4516 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004517 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004518 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004519}
4520
4521void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4522 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004523 Location array_loc = locations->InAt(0);
4524 CpuRegister array = array_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004525 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004526 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004527 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004528 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004529 bool needs_write_barrier =
4530 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004531 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4532 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4533 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004534
4535 switch (value_type) {
4536 case Primitive::kPrimBoolean:
4537 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004538 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4539 Address address = index.IsConstant()
4540 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4541 : Address(array, index.AsRegister<CpuRegister>(), TIMES_1, offset);
4542 if (value.IsRegister()) {
4543 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004544 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004545 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004546 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004547 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004548 break;
4549 }
4550
4551 case Primitive::kPrimShort:
4552 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004553 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4554 Address address = index.IsConstant()
4555 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4556 : Address(array, index.AsRegister<CpuRegister>(), TIMES_2, offset);
4557 if (value.IsRegister()) {
4558 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004559 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004560 DCHECK(value.IsConstant()) << value;
4561 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004562 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004563 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004564 break;
4565 }
4566
4567 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004568 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4569 Address address = index.IsConstant()
4570 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4571 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00004572
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004573 if (!value.IsRegister()) {
4574 // Just setting null.
4575 DCHECK(instruction->InputAt(2)->IsNullConstant());
4576 DCHECK(value.IsConstant()) << value;
4577 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004578 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004579 DCHECK(!needs_write_barrier);
4580 DCHECK(!may_need_runtime_call);
4581 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004582 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004583
4584 DCHECK(needs_write_barrier);
4585 CpuRegister register_value = value.AsRegister<CpuRegister>();
4586 NearLabel done, not_null, do_put;
4587 SlowPathCode* slow_path = nullptr;
4588 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4589 if (may_need_runtime_call) {
4590 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4591 codegen_->AddSlowPath(slow_path);
4592 if (instruction->GetValueCanBeNull()) {
4593 __ testl(register_value, register_value);
4594 __ j(kNotEqual, &not_null);
4595 __ movl(address, Immediate(0));
4596 codegen_->MaybeRecordImplicitNullCheck(instruction);
4597 __ jmp(&done);
4598 __ Bind(&not_null);
4599 }
4600
Roland Levillain0d5a2812015-11-13 10:07:31 +00004601 if (kEmitCompilerReadBarrier) {
4602 // When read barriers are enabled, the type checking
4603 // instrumentation requires two read barriers:
4604 //
4605 // __ movl(temp2, temp);
4606 // // /* HeapReference<Class> */ temp = temp->component_type_
4607 // __ movl(temp, Address(temp, component_offset));
4608 // codegen_->GenerateReadBarrier(
4609 // instruction, temp_loc, temp_loc, temp2_loc, component_offset);
4610 //
4611 // // /* HeapReference<Class> */ temp2 = register_value->klass_
4612 // __ movl(temp2, Address(register_value, class_offset));
4613 // codegen_->GenerateReadBarrier(
4614 // instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
4615 //
4616 // __ cmpl(temp, temp2);
4617 //
4618 // However, the second read barrier may trash `temp`, as it
4619 // is a temporary register, and as such would not be saved
4620 // along with live registers before calling the runtime (nor
4621 // restored afterwards). So in this case, we bail out and
4622 // delegate the work to the array set slow path.
4623 //
4624 // TODO: Extend the register allocator to support a new
4625 // "(locally) live temp" location so as to avoid always
4626 // going into the slow path when read barriers are enabled.
4627 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004628 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004629 // /* HeapReference<Class> */ temp = array->klass_
4630 __ movl(temp, Address(array, class_offset));
4631 codegen_->MaybeRecordImplicitNullCheck(instruction);
4632 __ MaybeUnpoisonHeapReference(temp);
4633
4634 // /* HeapReference<Class> */ temp = temp->component_type_
4635 __ movl(temp, Address(temp, component_offset));
4636 // If heap poisoning is enabled, no need to unpoison `temp`
4637 // nor the object reference in `register_value->klass`, as
4638 // we are comparing two poisoned references.
4639 __ cmpl(temp, Address(register_value, class_offset));
4640
4641 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4642 __ j(kEqual, &do_put);
4643 // If heap poisoning is enabled, the `temp` reference has
4644 // not been unpoisoned yet; unpoison it now.
4645 __ MaybeUnpoisonHeapReference(temp);
4646
4647 // /* HeapReference<Class> */ temp = temp->super_class_
4648 __ movl(temp, Address(temp, super_offset));
4649 // If heap poisoning is enabled, no need to unpoison
4650 // `temp`, as we are comparing against null below.
4651 __ testl(temp, temp);
4652 __ j(kNotEqual, slow_path->GetEntryLabel());
4653 __ Bind(&do_put);
4654 } else {
4655 __ j(kNotEqual, slow_path->GetEntryLabel());
4656 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004657 }
4658 }
4659
4660 if (kPoisonHeapReferences) {
4661 __ movl(temp, register_value);
4662 __ PoisonHeapReference(temp);
4663 __ movl(address, temp);
4664 } else {
4665 __ movl(address, register_value);
4666 }
4667 if (!may_need_runtime_call) {
4668 codegen_->MaybeRecordImplicitNullCheck(instruction);
4669 }
4670
4671 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4672 codegen_->MarkGCCard(
4673 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4674 __ Bind(&done);
4675
4676 if (slow_path != nullptr) {
4677 __ Bind(slow_path->GetExitLabel());
4678 }
4679
4680 break;
4681 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00004682
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004683 case Primitive::kPrimInt: {
4684 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4685 Address address = index.IsConstant()
4686 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4687 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
4688 if (value.IsRegister()) {
4689 __ movl(address, value.AsRegister<CpuRegister>());
4690 } else {
4691 DCHECK(value.IsConstant()) << value;
4692 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4693 __ movl(address, Immediate(v));
4694 }
4695 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004696 break;
4697 }
4698
4699 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004700 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
4701 Address address = index.IsConstant()
4702 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4703 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
4704 if (value.IsRegister()) {
4705 __ movq(address, value.AsRegister<CpuRegister>());
Mark Mendellea5af682015-10-22 17:35:49 -04004706 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004707 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004708 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004709 Address address_high = index.IsConstant()
4710 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) +
4711 offset + sizeof(int32_t))
4712 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset + sizeof(int32_t));
4713 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004714 }
4715 break;
4716 }
4717
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004718 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004719 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4720 Address address = index.IsConstant()
4721 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4722 : Address(array, index.AsRegister<CpuRegister>(), TIMES_4, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04004723 if (value.IsFpuRegister()) {
4724 __ movss(address, value.AsFpuRegister<XmmRegister>());
4725 } else {
4726 DCHECK(value.IsConstant());
4727 int32_t v =
4728 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4729 __ movl(address, Immediate(v));
4730 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004731 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004732 break;
4733 }
4734
4735 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004736 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4737 Address address = index.IsConstant()
4738 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4739 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04004740 if (value.IsFpuRegister()) {
4741 __ movsd(address, value.AsFpuRegister<XmmRegister>());
4742 codegen_->MaybeRecordImplicitNullCheck(instruction);
4743 } else {
4744 int64_t v =
4745 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4746 Address address_high = index.IsConstant()
4747 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) +
4748 offset + sizeof(int32_t))
4749 : Address(array, index.AsRegister<CpuRegister>(), TIMES_8, offset + sizeof(int32_t));
4750 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
4751 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004752 break;
4753 }
4754
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004755 case Primitive::kPrimVoid:
4756 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004757 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004758 }
4759}
4760
4761void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004762 LocationSummary* locations =
4763 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004764 locations->SetInAt(0, Location::RequiresRegister());
4765 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004766}
4767
4768void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
4769 LocationSummary* locations = instruction->GetLocations();
4770 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004771 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
4772 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004773 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004774 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004775}
4776
4777void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004778 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4779 ? LocationSummary::kCallOnSlowPath
4780 : LocationSummary::kNoCall;
4781 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004782 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004783 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004784 if (instruction->HasUses()) {
4785 locations->SetOut(Location::SameAsFirstInput());
4786 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004787}
4788
4789void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
4790 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004791 Location index_loc = locations->InAt(0);
4792 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004793 SlowPathCode* slow_path =
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004794 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004795
Mark Mendell99dbd682015-04-22 16:18:52 -04004796 if (length_loc.IsConstant()) {
4797 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4798 if (index_loc.IsConstant()) {
4799 // BCE will remove the bounds check if we are guarenteed to pass.
4800 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4801 if (index < 0 || index >= length) {
4802 codegen_->AddSlowPath(slow_path);
4803 __ jmp(slow_path->GetEntryLabel());
4804 } else {
4805 // Some optimization after BCE may have generated this, and we should not
4806 // generate a bounds check if it is a valid range.
4807 }
4808 return;
4809 }
4810
4811 // We have to reverse the jump condition because the length is the constant.
4812 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
4813 __ cmpl(index_reg, Immediate(length));
4814 codegen_->AddSlowPath(slow_path);
4815 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004816 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004817 CpuRegister length = length_loc.AsRegister<CpuRegister>();
4818 if (index_loc.IsConstant()) {
4819 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4820 __ cmpl(length, Immediate(value));
4821 } else {
4822 __ cmpl(length, index_loc.AsRegister<CpuRegister>());
4823 }
4824 codegen_->AddSlowPath(slow_path);
4825 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004826 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004827}
4828
4829void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
4830 CpuRegister card,
4831 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004832 CpuRegister value,
4833 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004834 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004835 if (value_can_be_null) {
4836 __ testl(value, value);
4837 __ j(kEqual, &is_null);
4838 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004839 __ gs()->movq(card, Address::Absolute(
4840 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
4841 __ movq(temp, object);
4842 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01004843 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004844 if (value_can_be_null) {
4845 __ Bind(&is_null);
4846 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004847}
4848
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004849void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
4850 temp->SetLocations(nullptr);
4851}
4852
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004853void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004854 // Nothing to do, this is driven by the code generator.
4855}
4856
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004857void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004858 LOG(FATAL) << "Unimplemented";
4859}
4860
4861void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004862 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4863}
4864
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004865void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
4866 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4867}
4868
4869void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004870 HBasicBlock* block = instruction->GetBlock();
4871 if (block->GetLoopInformation() != nullptr) {
4872 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4873 // The back edge will generate the suspend check.
4874 return;
4875 }
4876 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4877 // The goto will generate the suspend check.
4878 return;
4879 }
4880 GenerateSuspendCheck(instruction, nullptr);
4881}
4882
4883void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
4884 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004885 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004886 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
4887 if (slow_path == nullptr) {
4888 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
4889 instruction->SetSlowPath(slow_path);
4890 codegen_->AddSlowPath(slow_path);
4891 if (successor != nullptr) {
4892 DCHECK(successor->IsLoopHeader());
4893 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4894 }
4895 } else {
4896 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4897 }
4898
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004899 __ gs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004900 Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004901 if (successor == nullptr) {
4902 __ j(kNotEqual, slow_path->GetEntryLabel());
4903 __ Bind(slow_path->GetReturnLabel());
4904 } else {
4905 __ j(kEqual, codegen_->GetLabelOf(successor));
4906 __ jmp(slow_path->GetEntryLabel());
4907 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004908}
4909
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004910X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
4911 return codegen_->GetAssembler();
4912}
4913
4914void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004915 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004916 Location source = move->GetSource();
4917 Location destination = move->GetDestination();
4918
4919 if (source.IsRegister()) {
4920 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004921 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004922 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004923 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004924 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004925 } else {
4926 DCHECK(destination.IsDoubleStackSlot());
4927 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004928 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004929 }
4930 } else if (source.IsStackSlot()) {
4931 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004932 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004933 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004934 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004935 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004936 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004937 } else {
4938 DCHECK(destination.IsStackSlot());
4939 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4940 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4941 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004942 } else if (source.IsDoubleStackSlot()) {
4943 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004944 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004945 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004946 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004947 __ movsd(destination.AsFpuRegister<XmmRegister>(),
4948 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004949 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01004950 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004951 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
4952 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
4953 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004954 } else if (source.IsConstant()) {
4955 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004956 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4957 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004958 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004959 if (value == 0) {
4960 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
4961 } else {
4962 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
4963 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004964 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004965 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004966 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004967 }
4968 } else if (constant->IsLongConstant()) {
4969 int64_t value = constant->AsLongConstant()->GetValue();
4970 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004971 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004972 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004973 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04004974 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004975 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004976 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004977 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004978 int32_t value = bit_cast<int32_t, float>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004979 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004980 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4981 if (value == 0) {
4982 // easy FP 0.0.
4983 __ xorps(dest, dest);
4984 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04004985 __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004986 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004987 } else {
4988 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell92e83bf2015-05-07 11:25:03 -04004989 Immediate imm(value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004990 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
4991 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004992 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004993 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004994 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004995 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004996 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004997 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4998 if (value == 0) {
4999 __ xorpd(dest, dest);
5000 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04005001 __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005002 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005003 } else {
5004 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005005 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005006 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005007 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005008 } else if (source.IsFpuRegister()) {
5009 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005010 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005011 } else if (destination.IsStackSlot()) {
5012 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005013 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005014 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00005015 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005016 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005017 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005018 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005019 }
5020}
5021
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005022void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005023 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005024 __ movl(Address(CpuRegister(RSP), mem), reg);
5025 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005026}
5027
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005028void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005029 ScratchRegisterScope ensure_scratch(
5030 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5031
5032 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5033 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5034 __ movl(CpuRegister(ensure_scratch.GetRegister()),
5035 Address(CpuRegister(RSP), mem2 + stack_offset));
5036 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5037 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
5038 CpuRegister(ensure_scratch.GetRegister()));
5039}
5040
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005041void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
5042 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5043 __ movq(Address(CpuRegister(RSP), mem), reg);
5044 __ movq(reg, CpuRegister(TMP));
5045}
5046
5047void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
5048 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005049 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005050
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005051 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5052 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5053 __ movq(CpuRegister(ensure_scratch.GetRegister()),
5054 Address(CpuRegister(RSP), mem2 + stack_offset));
5055 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5056 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
5057 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005058}
5059
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005060void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
5061 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5062 __ movss(Address(CpuRegister(RSP), mem), reg);
5063 __ movd(reg, CpuRegister(TMP));
5064}
5065
5066void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
5067 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5068 __ movsd(Address(CpuRegister(RSP), mem), reg);
5069 __ movd(reg, CpuRegister(TMP));
5070}
5071
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005072void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005073 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005074 Location source = move->GetSource();
5075 Location destination = move->GetDestination();
5076
5077 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005078 __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005079 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005080 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005081 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005082 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005083 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005084 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
5085 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005086 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005087 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005088 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005089 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5090 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005091 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005092 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
5093 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5094 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005095 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005096 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005097 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005098 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005099 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005100 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005101 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005102 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005103 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005104 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005105 }
5106}
5107
5108
5109void ParallelMoveResolverX86_64::SpillScratch(int reg) {
5110 __ pushq(CpuRegister(reg));
5111}
5112
5113
5114void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
5115 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005116}
5117
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005118void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005119 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005120 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5121 Immediate(mirror::Class::kStatusInitialized));
5122 __ j(kLess, slow_path->GetEntryLabel());
5123 __ Bind(slow_path->GetExitLabel());
5124 // No need for memory fence, thanks to the X86_64 memory model.
5125}
5126
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005127void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005128 InvokeRuntimeCallingConvention calling_convention;
5129 CodeGenerator::CreateLoadClassLocationSummary(
5130 cls,
5131 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain0d5a2812015-11-13 10:07:31 +00005132 Location::RegisterLocation(RAX),
5133 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005134}
5135
5136void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005137 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005138 if (cls->NeedsAccessCheck()) {
5139 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5140 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5141 cls,
5142 cls->GetDexPc(),
5143 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005144 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005145 return;
5146 }
5147
Roland Levillain0d5a2812015-11-13 10:07:31 +00005148 Location out_loc = locations->Out();
5149 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Calin Juravle580b6092015-10-06 17:35:58 +01005150 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005151
Calin Juravle580b6092015-10-06 17:35:58 +01005152 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005153 DCHECK(!cls->CanCallRuntime());
5154 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005155 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5156 if (kEmitCompilerReadBarrier) {
5157 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5158 __ leaq(out, Address(current_method, declaring_class_offset));
5159 // /* mirror::Class* */ out = out->Read()
5160 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5161 } else {
5162 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5163 __ movl(out, Address(current_method, declaring_class_offset));
5164 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005165 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005166 // /* GcRoot<mirror::Class>[] */ out =
5167 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
5168 __ movq(out, Address(current_method,
5169 ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
5170
5171 size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5172 if (kEmitCompilerReadBarrier) {
5173 // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5174 __ leaq(out, Address(out, cache_offset));
5175 // /* mirror::Class* */ out = out->Read()
5176 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5177 } else {
5178 // /* GcRoot<mirror::Class> */ out = out[type_index]
5179 __ movl(out, Address(out, cache_offset));
5180 }
Roland Levillain4d027112015-07-01 15:41:14 +01005181
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005182 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5183 DCHECK(cls->CanCallRuntime());
5184 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
5185 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5186 codegen_->AddSlowPath(slow_path);
5187 if (!cls->IsInDexCache()) {
5188 __ testl(out, out);
5189 __ j(kEqual, slow_path->GetEntryLabel());
5190 }
5191 if (cls->MustGenerateClinitCheck()) {
5192 GenerateClassInitializationCheck(slow_path, out);
5193 } else {
5194 __ Bind(slow_path->GetExitLabel());
5195 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005196 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005197 }
5198}
5199
5200void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
5201 LocationSummary* locations =
5202 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5203 locations->SetInAt(0, Location::RequiresRegister());
5204 if (check->HasUses()) {
5205 locations->SetOut(Location::SameAsFirstInput());
5206 }
5207}
5208
5209void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005210 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005211 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005212 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005213 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005214 GenerateClassInitializationCheck(slow_path,
5215 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005216}
5217
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005218void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
5219 LocationSummary* locations =
5220 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005221 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005222 locations->SetOut(Location::RequiresRegister());
5223}
5224
5225void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005226 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005227 codegen_->AddSlowPath(slow_path);
5228
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005229 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005230 Location out_loc = locations->Out();
5231 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005232 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005233
5234 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5235 if (kEmitCompilerReadBarrier) {
5236 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5237 __ leaq(out, Address(current_method, declaring_class_offset));
5238 // /* mirror::Class* */ out = out->Read()
5239 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5240 } else {
5241 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5242 __ movl(out, Address(current_method, declaring_class_offset));
5243 }
5244
5245 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5246 __ movq(out, Address(out, mirror::Class::DexCacheStringsOffset().Uint32Value()));
5247
5248 size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5249 if (kEmitCompilerReadBarrier) {
5250 // /* GcRoot<mirror::String>* */ out = &out[string_index]
5251 __ leaq(out, Address(out, cache_offset));
5252 // /* mirror::String* */ out = out->Read()
5253 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5254 } else {
5255 // /* GcRoot<mirror::String> */ out = out[string_index]
5256 __ movl(out, Address(out, cache_offset));
5257 }
5258
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005259 __ testl(out, out);
5260 __ j(kEqual, slow_path->GetEntryLabel());
5261 __ Bind(slow_path->GetExitLabel());
5262}
5263
David Brazdilcb1c0552015-08-04 16:22:25 +01005264static Address GetExceptionTlsAddress() {
5265 return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
5266}
5267
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005268void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
5269 LocationSummary* locations =
5270 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5271 locations->SetOut(Location::RequiresRegister());
5272}
5273
5274void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005275 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
5276}
5277
5278void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
5279 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5280}
5281
5282void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5283 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005284}
5285
5286void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
5287 LocationSummary* locations =
5288 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5289 InvokeRuntimeCallingConvention calling_convention;
5290 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5291}
5292
5293void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005294 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5295 instruction,
5296 instruction->GetDexPc(),
5297 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005298 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005299}
5300
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005301void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005302 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005303 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5304 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005305 case TypeCheckKind::kExactCheck:
5306 case TypeCheckKind::kAbstractClassCheck:
5307 case TypeCheckKind::kClassHierarchyCheck:
5308 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005309 call_kind =
5310 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005311 break;
5312 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005313 case TypeCheckKind::kUnresolvedCheck:
5314 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005315 call_kind = LocationSummary::kCallOnSlowPath;
5316 break;
5317 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005318
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005319 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005320 locations->SetInAt(0, Location::RequiresRegister());
5321 locations->SetInAt(1, Location::Any());
5322 // Note that TypeCheckSlowPathX86_64 uses this "out" register too.
5323 locations->SetOut(Location::RequiresRegister());
5324 // When read barriers are enabled, we need a temporary register for
5325 // some cases.
5326 if (kEmitCompilerReadBarrier &&
5327 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5328 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5329 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5330 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005331 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005332}
5333
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005334void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005335 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005336 Location obj_loc = locations->InAt(0);
5337 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005338 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005339 Location out_loc = locations->Out();
5340 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005341 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005342 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5343 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5344 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005345 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005346 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005347
5348 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005349 // Avoid null check if we know obj is not null.
5350 if (instruction->MustDoNullCheck()) {
5351 __ testl(obj, obj);
5352 __ j(kEqual, &zero);
5353 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005354
Roland Levillain0d5a2812015-11-13 10:07:31 +00005355 // /* HeapReference<Class> */ out = obj->klass_
5356 __ movl(out, Address(obj, class_offset));
5357 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005358
5359 switch (instruction->GetTypeCheckKind()) {
5360 case TypeCheckKind::kExactCheck: {
5361 if (cls.IsRegister()) {
5362 __ cmpl(out, cls.AsRegister<CpuRegister>());
5363 } else {
5364 DCHECK(cls.IsStackSlot()) << cls;
5365 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5366 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005367 if (zero.IsLinked()) {
5368 // Classes must be equal for the instanceof to succeed.
5369 __ j(kNotEqual, &zero);
5370 __ movl(out, Immediate(1));
5371 __ jmp(&done);
5372 } else {
5373 __ setcc(kEqual, out);
5374 // setcc only sets the low byte.
5375 __ andl(out, Immediate(1));
5376 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005377 break;
5378 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005379
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005380 case TypeCheckKind::kAbstractClassCheck: {
5381 // If the class is abstract, we eagerly fetch the super class of the
5382 // object to avoid doing a comparison we know will fail.
5383 NearLabel loop, success;
5384 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005385 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5386 if (kEmitCompilerReadBarrier) {
5387 // Save the value of `out` into `temp` before overwriting it
5388 // in the following move operation, as we will need it for the
5389 // read barrier below.
5390 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5391 __ movl(temp, out);
5392 }
5393 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005394 __ movl(out, Address(out, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005395 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005396 __ testl(out, out);
5397 // If `out` is null, we use it for the result, and jump to `done`.
5398 __ j(kEqual, &done);
5399 if (cls.IsRegister()) {
5400 __ cmpl(out, cls.AsRegister<CpuRegister>());
5401 } else {
5402 DCHECK(cls.IsStackSlot()) << cls;
5403 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5404 }
5405 __ j(kNotEqual, &loop);
5406 __ movl(out, Immediate(1));
5407 if (zero.IsLinked()) {
5408 __ jmp(&done);
5409 }
5410 break;
5411 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005412
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005413 case TypeCheckKind::kClassHierarchyCheck: {
5414 // Walk over the class hierarchy to find a match.
5415 NearLabel loop, success;
5416 __ Bind(&loop);
5417 if (cls.IsRegister()) {
5418 __ cmpl(out, cls.AsRegister<CpuRegister>());
5419 } else {
5420 DCHECK(cls.IsStackSlot()) << cls;
5421 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5422 }
5423 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005424 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5425 if (kEmitCompilerReadBarrier) {
5426 // Save the value of `out` into `temp` before overwriting it
5427 // in the following move operation, as we will need it for the
5428 // read barrier below.
5429 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5430 __ movl(temp, out);
5431 }
5432 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005433 __ movl(out, Address(out, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005434 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005435 __ testl(out, out);
5436 __ j(kNotEqual, &loop);
5437 // If `out` is null, we use it for the result, and jump to `done`.
5438 __ jmp(&done);
5439 __ Bind(&success);
5440 __ movl(out, Immediate(1));
5441 if (zero.IsLinked()) {
5442 __ jmp(&done);
5443 }
5444 break;
5445 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005446
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005447 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005448 // Do an exact check.
5449 NearLabel exact_check;
5450 if (cls.IsRegister()) {
5451 __ cmpl(out, cls.AsRegister<CpuRegister>());
5452 } else {
5453 DCHECK(cls.IsStackSlot()) << cls;
5454 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5455 }
5456 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005457 // Otherwise, we need to check that the object's class is a non-primitive array.
5458 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5459 if (kEmitCompilerReadBarrier) {
5460 // Save the value of `out` into `temp` before overwriting it
5461 // in the following move operation, as we will need it for the
5462 // read barrier below.
5463 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
5464 __ movl(temp, out);
5465 }
5466 // /* HeapReference<Class> */ out = out->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005467 __ movl(out, Address(out, component_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005468 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005469 __ testl(out, out);
5470 // If `out` is null, we use it for the result, and jump to `done`.
5471 __ j(kEqual, &done);
5472 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5473 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005474 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005475 __ movl(out, Immediate(1));
5476 __ jmp(&done);
5477 break;
5478 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005479
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005480 case TypeCheckKind::kArrayCheck: {
5481 if (cls.IsRegister()) {
5482 __ cmpl(out, cls.AsRegister<CpuRegister>());
5483 } else {
5484 DCHECK(cls.IsStackSlot()) << cls;
5485 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5486 }
5487 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005488 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5489 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005490 codegen_->AddSlowPath(slow_path);
5491 __ j(kNotEqual, slow_path->GetEntryLabel());
5492 __ movl(out, Immediate(1));
5493 if (zero.IsLinked()) {
5494 __ jmp(&done);
5495 }
5496 break;
5497 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005498
Calin Juravle98893e12015-10-02 21:05:03 +01005499 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005500 case TypeCheckKind::kInterfaceCheck: {
5501 // Note that we indeed only call on slow path, but we always go
5502 // into the slow path for the unresolved & interface check
5503 // cases.
5504 //
5505 // We cannot directly call the InstanceofNonTrivial runtime
5506 // entry point without resorting to a type checking slow path
5507 // here (i.e. by calling InvokeRuntime directly), as it would
5508 // require to assign fixed registers for the inputs of this
5509 // HInstanceOf instruction (following the runtime calling
5510 // convention), which might be cluttered by the potential first
5511 // read barrier emission at the beginning of this method.
5512 DCHECK(locations->OnlyCallsOnSlowPath());
5513 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5514 /* is_fatal */ false);
5515 codegen_->AddSlowPath(slow_path);
5516 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005517 if (zero.IsLinked()) {
5518 __ jmp(&done);
5519 }
5520 break;
5521 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005522 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005523
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005524 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005525 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005526 __ xorl(out, out);
5527 }
5528
5529 if (done.IsLinked()) {
5530 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005531 }
5532
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005533 if (slow_path != nullptr) {
5534 __ Bind(slow_path->GetExitLabel());
5535 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005536}
5537
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005538void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005539 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5540 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005541 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5542 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005543 case TypeCheckKind::kExactCheck:
5544 case TypeCheckKind::kAbstractClassCheck:
5545 case TypeCheckKind::kClassHierarchyCheck:
5546 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005547 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5548 LocationSummary::kCallOnSlowPath :
5549 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005550 break;
5551 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005552 case TypeCheckKind::kUnresolvedCheck:
5553 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005554 call_kind = LocationSummary::kCallOnSlowPath;
5555 break;
5556 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005557 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5558 locations->SetInAt(0, Location::RequiresRegister());
5559 locations->SetInAt(1, Location::Any());
5560 // Note that TypeCheckSlowPathX86_64 uses this "temp" register too.
5561 locations->AddTemp(Location::RequiresRegister());
5562 // When read barriers are enabled, we need an additional temporary
5563 // register for some cases.
5564 if (kEmitCompilerReadBarrier &&
5565 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5566 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5567 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005568 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005569 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005570}
5571
5572void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
5573 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005574 Location obj_loc = locations->InAt(0);
5575 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005576 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005577 Location temp_loc = locations->GetTemp(0);
5578 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005579 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5580 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5581 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5582 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005583
Roland Levillain0d5a2812015-11-13 10:07:31 +00005584 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5585 bool is_type_check_slow_path_fatal =
5586 (type_check_kind == TypeCheckKind::kExactCheck ||
5587 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5588 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5589 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5590 !instruction->CanThrowIntoCatchBlock();
5591 SlowPathCode* type_check_slow_path =
5592 new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5593 is_type_check_slow_path_fatal);
5594 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005595
5596 NearLabel done;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005597 // Avoid null check if we know obj is not null.
5598 if (instruction->MustDoNullCheck()) {
5599 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005600 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005601 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005602
Roland Levillain0d5a2812015-11-13 10:07:31 +00005603 // /* HeapReference<Class> */ temp = obj->klass_
5604 __ movl(temp, Address(obj, class_offset));
5605 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005606
Roland Levillain0d5a2812015-11-13 10:07:31 +00005607 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005608 case TypeCheckKind::kExactCheck:
5609 case TypeCheckKind::kArrayCheck: {
5610 if (cls.IsRegister()) {
5611 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5612 } else {
5613 DCHECK(cls.IsStackSlot()) << cls;
5614 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5615 }
5616 // Jump to slow path for throwing the exception or doing a
5617 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005618 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005619 break;
5620 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005621
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005622 case TypeCheckKind::kAbstractClassCheck: {
5623 // If the class is abstract, we eagerly fetch the super class of the
5624 // object to avoid doing a comparison we know will fail.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005625 NearLabel loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005626 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005627 Location temp2_loc =
5628 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5629 if (kEmitCompilerReadBarrier) {
5630 // Save the value of `temp` into `temp2` before overwriting it
5631 // in the following move operation, as we will need it for the
5632 // read barrier below.
5633 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5634 __ movl(temp2, temp);
5635 }
5636 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005637 __ movl(temp, Address(temp, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005638 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5639
5640 // If the class reference currently in `temp` is not null, jump
5641 // to the `compare_classes` label to compare it with the checked
5642 // class.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005643 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005644 __ j(kNotEqual, &compare_classes);
5645 // Otherwise, jump to the slow path to throw the exception.
5646 //
5647 // But before, move back the object's class into `temp` before
5648 // going into the slow path, as it has been overwritten in the
5649 // meantime.
5650 // /* HeapReference<Class> */ temp = obj->klass_
5651 __ movl(temp, Address(obj, class_offset));
5652 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5653 __ jmp(type_check_slow_path->GetEntryLabel());
5654
5655 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005656 if (cls.IsRegister()) {
5657 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5658 } else {
5659 DCHECK(cls.IsStackSlot()) << cls;
5660 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5661 }
5662 __ j(kNotEqual, &loop);
5663 break;
5664 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005665
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005666 case TypeCheckKind::kClassHierarchyCheck: {
5667 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005668 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005669 __ Bind(&loop);
5670 if (cls.IsRegister()) {
5671 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5672 } else {
5673 DCHECK(cls.IsStackSlot()) << cls;
5674 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5675 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005676 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005677
5678 Location temp2_loc =
5679 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5680 if (kEmitCompilerReadBarrier) {
5681 // Save the value of `temp` into `temp2` before overwriting it
5682 // in the following move operation, as we will need it for the
5683 // read barrier below.
5684 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5685 __ movl(temp2, temp);
5686 }
5687 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005688 __ movl(temp, Address(temp, super_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005689 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5690
5691 // If the class reference currently in `temp` is not null, jump
5692 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005693 __ testl(temp, temp);
5694 __ j(kNotEqual, &loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005695 // Otherwise, jump to the slow path to throw the exception.
5696 //
5697 // But before, move back the object's class into `temp` before
5698 // going into the slow path, as it has been overwritten in the
5699 // meantime.
5700 // /* HeapReference<Class> */ temp = obj->klass_
5701 __ movl(temp, Address(obj, class_offset));
5702 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5703 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005704 break;
5705 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005706
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005707 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005708 // Do an exact check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005709 NearLabel check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005710 if (cls.IsRegister()) {
5711 __ cmpl(temp, cls.AsRegister<CpuRegister>());
5712 } else {
5713 DCHECK(cls.IsStackSlot()) << cls;
5714 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
5715 }
5716 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005717
5718 // Otherwise, we need to check that the object's class is a non-primitive array.
5719 Location temp2_loc =
5720 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5721 if (kEmitCompilerReadBarrier) {
5722 // Save the value of `temp` into `temp2` before overwriting it
5723 // in the following move operation, as we will need it for the
5724 // read barrier below.
5725 CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
5726 __ movl(temp2, temp);
5727 }
5728 // /* HeapReference<Class> */ temp = temp->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005729 __ movl(temp, Address(temp, component_offset));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005730 codegen_->MaybeGenerateReadBarrier(
5731 instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5732
5733 // If the component type is not null (i.e. the object is indeed
5734 // an array), jump to label `check_non_primitive_component_type`
5735 // to further check that this component type is not a primitive
5736 // type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005737 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005738 __ j(kNotEqual, &check_non_primitive_component_type);
5739 // Otherwise, jump to the slow path to throw the exception.
5740 //
5741 // But before, move back the object's class into `temp` before
5742 // going into the slow path, as it has been overwritten in the
5743 // meantime.
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());
5748
5749 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005750 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Roland Levillain0d5a2812015-11-13 10:07:31 +00005751 __ j(kEqual, &done);
5752 // Same comment as above regarding `temp` and the slow path.
5753 // /* HeapReference<Class> */ temp = obj->klass_
5754 __ movl(temp, Address(obj, class_offset));
5755 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5756 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005757 break;
5758 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005759
Calin Juravle98893e12015-10-02 21:05:03 +01005760 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005761 case TypeCheckKind::kInterfaceCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005762 // We always go into the type check slow path for the unresolved &
5763 // interface check cases.
5764 //
5765 // We cannot directly call the CheckCast runtime entry point
5766 // without resorting to a type checking slow path here (i.e. by
5767 // calling InvokeRuntime directly), as it would require to
5768 // assign fixed registers for the inputs of this HInstanceOf
5769 // instruction (following the runtime calling convention), which
5770 // might be cluttered by the potential first read barrier
5771 // emission at the beginning of this method.
5772 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005773 break;
5774 }
5775 __ Bind(&done);
5776
Roland Levillain0d5a2812015-11-13 10:07:31 +00005777 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005778}
5779
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005780void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
5781 LocationSummary* locations =
5782 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5783 InvokeRuntimeCallingConvention calling_convention;
5784 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5785}
5786
5787void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005788 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5789 : QUICK_ENTRY_POINT(pUnlockObject),
5790 instruction,
5791 instruction->GetDexPc(),
5792 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005793 if (instruction->IsEnter()) {
5794 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5795 } else {
5796 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5797 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005798}
5799
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005800void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5801void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5802void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5803
5804void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5805 LocationSummary* locations =
5806 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5807 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5808 || instruction->GetResultType() == Primitive::kPrimLong);
5809 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04005810 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005811 locations->SetOut(Location::SameAsFirstInput());
5812}
5813
5814void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
5815 HandleBitwiseOperation(instruction);
5816}
5817
5818void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
5819 HandleBitwiseOperation(instruction);
5820}
5821
5822void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
5823 HandleBitwiseOperation(instruction);
5824}
5825
5826void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
5827 LocationSummary* locations = instruction->GetLocations();
5828 Location first = locations->InAt(0);
5829 Location second = locations->InAt(1);
5830 DCHECK(first.Equals(locations->Out()));
5831
5832 if (instruction->GetResultType() == Primitive::kPrimInt) {
5833 if (second.IsRegister()) {
5834 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005835 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005836 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005837 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005838 } else {
5839 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005840 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005841 }
5842 } else if (second.IsConstant()) {
5843 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
5844 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005845 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005846 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005847 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005848 } else {
5849 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005850 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005851 }
5852 } else {
5853 Address address(CpuRegister(RSP), second.GetStackIndex());
5854 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005855 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005856 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005857 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005858 } else {
5859 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005860 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005861 }
5862 }
5863 } else {
5864 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005865 CpuRegister first_reg = first.AsRegister<CpuRegister>();
5866 bool second_is_constant = false;
5867 int64_t value = 0;
5868 if (second.IsConstant()) {
5869 second_is_constant = true;
5870 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005871 }
Mark Mendell40741f32015-04-20 22:10:34 -04005872 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005873
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005874 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005875 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005876 if (is_int32_value) {
5877 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
5878 } else {
5879 __ andq(first_reg, codegen_->LiteralInt64Address(value));
5880 }
5881 } else if (second.IsDoubleStackSlot()) {
5882 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005883 } else {
5884 __ andq(first_reg, second.AsRegister<CpuRegister>());
5885 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005886 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005887 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005888 if (is_int32_value) {
5889 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
5890 } else {
5891 __ orq(first_reg, codegen_->LiteralInt64Address(value));
5892 }
5893 } else if (second.IsDoubleStackSlot()) {
5894 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005895 } else {
5896 __ orq(first_reg, second.AsRegister<CpuRegister>());
5897 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005898 } else {
5899 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005900 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04005901 if (is_int32_value) {
5902 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
5903 } else {
5904 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
5905 }
5906 } else if (second.IsDoubleStackSlot()) {
5907 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005908 } else {
5909 __ xorq(first_reg, second.AsRegister<CpuRegister>());
5910 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005911 }
5912 }
5913}
5914
Roland Levillain0d5a2812015-11-13 10:07:31 +00005915void CodeGeneratorX86_64::GenerateReadBarrier(HInstruction* instruction,
5916 Location out,
5917 Location ref,
5918 Location obj,
5919 uint32_t offset,
5920 Location index) {
5921 DCHECK(kEmitCompilerReadBarrier);
5922
5923 // If heap poisoning is enabled, the unpoisoning of the loaded
5924 // reference will be carried out by the runtime within the slow
5925 // path.
5926 //
5927 // Note that `ref` currently does not get unpoisoned (when heap
5928 // poisoning is enabled), which is alright as the `ref` argument is
5929 // not used by the artReadBarrierSlow entry point.
5930 //
5931 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5932 SlowPathCode* slow_path = new (GetGraph()->GetArena())
5933 ReadBarrierForHeapReferenceSlowPathX86_64(instruction, out, ref, obj, offset, index);
5934 AddSlowPath(slow_path);
5935
5936 // TODO: When read barrier has a fast path, add it here.
5937 /* Currently the read barrier call is inserted after the original load.
5938 * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5939 * original load. This load-load ordering is required by the read barrier.
5940 * The fast path/slow path (for Baker's algorithm) should look like:
5941 *
5942 * bool isGray = obj.LockWord & kReadBarrierMask;
5943 * lfence; // load fence or artificial data dependence to prevent load-load reordering
5944 * ref = obj.field; // this is the original load
5945 * if (isGray) {
5946 * ref = Mark(ref); // ideally the slow path just does Mark(ref)
5947 * }
5948 */
5949
5950 __ jmp(slow_path->GetEntryLabel());
5951 __ Bind(slow_path->GetExitLabel());
5952}
5953
5954void CodeGeneratorX86_64::MaybeGenerateReadBarrier(HInstruction* instruction,
5955 Location out,
5956 Location ref,
5957 Location obj,
5958 uint32_t offset,
5959 Location index) {
5960 if (kEmitCompilerReadBarrier) {
5961 // If heap poisoning is enabled, unpoisoning will be taken care of
5962 // by the runtime within the slow path.
5963 GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5964 } else if (kPoisonHeapReferences) {
5965 __ UnpoisonHeapReference(out.AsRegister<CpuRegister>());
5966 }
5967}
5968
5969void CodeGeneratorX86_64::GenerateReadBarrierForRoot(HInstruction* instruction,
5970 Location out,
5971 Location root) {
5972 DCHECK(kEmitCompilerReadBarrier);
5973
5974 // Note that GC roots are not affected by heap poisoning, so we do
5975 // not need to do anything special for this here.
5976 SlowPathCode* slow_path =
5977 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathX86_64(instruction, out, root);
5978 AddSlowPath(slow_path);
5979
5980 // TODO: Implement a fast path for ReadBarrierForRoot, performing
5981 // the following operation (for Baker's algorithm):
5982 //
5983 // if (thread.tls32_.is_gc_marking) {
5984 // root = Mark(root);
5985 // }
5986
5987 __ jmp(slow_path->GetEntryLabel());
5988 __ Bind(slow_path->GetExitLabel());
5989}
5990
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005991void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005992 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005993 LOG(FATAL) << "Unreachable";
5994}
5995
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005996void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005997 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005998 LOG(FATAL) << "Unreachable";
5999}
6000
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01006001void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
6002 DCHECK(codegen_->IsBaseline());
6003 LocationSummary* locations =
6004 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6005 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
6006}
6007
6008void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6009 DCHECK(codegen_->IsBaseline());
6010 // Will be generated at use site.
6011}
6012
Mark Mendellfe57faa2015-09-18 09:26:15 -04006013// Simple implementation of packed switch - generate cascaded compare/jumps.
6014void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6015 LocationSummary* locations =
6016 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6017 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04006018 locations->AddTemp(Location::RequiresRegister());
6019 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04006020}
6021
6022void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6023 int32_t lower_bound = switch_instr->GetStartValue();
6024 int32_t num_entries = switch_instr->GetNumEntries();
6025 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04006026 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
6027 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
6028 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
6029
6030 // Remove the bias, if needed.
6031 Register value_reg_out = value_reg_in.AsRegister();
6032 if (lower_bound != 0) {
6033 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
6034 value_reg_out = temp_reg.AsRegister();
6035 }
6036 CpuRegister value_reg(value_reg_out);
6037
6038 // Is the value in range?
Mark Mendellfe57faa2015-09-18 09:26:15 -04006039 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
Mark Mendell9c86b482015-09-18 13:36:07 -04006040 __ cmpl(value_reg, Immediate(num_entries - 1));
6041 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006042
Mark Mendell9c86b482015-09-18 13:36:07 -04006043 // We are in the range of the table.
6044 // Load the address of the jump table in the constant area.
6045 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006046
Mark Mendell9c86b482015-09-18 13:36:07 -04006047 // Load the (signed) offset from the jump table.
6048 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
6049
6050 // Add the offset to the address of the table base.
6051 __ addq(temp_reg, base_reg);
6052
6053 // And jump.
6054 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006055}
6056
Mark Mendell92e83bf2015-05-07 11:25:03 -04006057void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
6058 if (value == 0) {
6059 __ xorl(dest, dest);
6060 } else if (value > 0 && IsInt<32>(value)) {
6061 // We can use a 32 bit move, as it will zero-extend and is one byte shorter.
6062 __ movl(dest, Immediate(static_cast<int32_t>(value)));
6063 } else {
6064 __ movq(dest, Immediate(value));
6065 }
6066}
6067
Mark Mendellcfa410b2015-05-25 16:02:44 -04006068void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
6069 DCHECK(dest.IsDoubleStackSlot());
6070 if (IsInt<32>(value)) {
6071 // Can move directly as an int32 constant.
6072 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
6073 Immediate(static_cast<int32_t>(value)));
6074 } else {
6075 Load64BitValue(CpuRegister(TMP), value);
6076 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
6077 }
6078}
6079
Mark Mendell9c86b482015-09-18 13:36:07 -04006080/**
6081 * Class to handle late fixup of offsets into constant area.
6082 */
6083class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
6084 public:
6085 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
6086 : codegen_(&codegen), offset_into_constant_area_(offset) {}
6087
6088 protected:
6089 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
6090
6091 CodeGeneratorX86_64* codegen_;
6092
6093 private:
6094 void Process(const MemoryRegion& region, int pos) OVERRIDE {
6095 // Patch the correct offset for the instruction. We use the address of the
6096 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
6097 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
6098 int32_t relative_position = constant_offset - pos;
6099
6100 // Patch in the right value.
6101 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
6102 }
6103
6104 // Location in constant area that the fixup refers to.
6105 size_t offset_into_constant_area_;
6106};
6107
6108/**
6109 t * Class to handle late fixup of offsets to a jump table that will be created in the
6110 * constant area.
6111 */
6112class JumpTableRIPFixup : public RIPFixup {
6113 public:
6114 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
6115 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
6116
6117 void CreateJumpTable() {
6118 X86_64Assembler* assembler = codegen_->GetAssembler();
6119
6120 // Ensure that the reference to the jump table has the correct offset.
6121 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
6122 SetOffset(offset_in_constant_table);
6123
6124 // Compute the offset from the start of the function to this jump table.
6125 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
6126
6127 // Populate the jump table with the correct values for the jump table.
6128 int32_t num_entries = switch_instr_->GetNumEntries();
6129 HBasicBlock* block = switch_instr_->GetBlock();
6130 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
6131 // The value that we want is the target offset - the position of the table.
6132 for (int32_t i = 0; i < num_entries; i++) {
6133 HBasicBlock* b = successors[i];
6134 Label* l = codegen_->GetLabelOf(b);
6135 DCHECK(l->IsBound());
6136 int32_t offset_to_block = l->Position() - current_table_offset;
6137 assembler->AppendInt32(offset_to_block);
6138 }
6139 }
6140
6141 private:
6142 const HPackedSwitch* switch_instr_;
6143};
6144
Mark Mendellf55c3e02015-03-26 21:07:46 -04006145void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
6146 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04006147 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04006148 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
6149 // 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 -04006150 assembler->Align(4, 0);
6151 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04006152
6153 // Populate any jump tables.
6154 for (auto jump_table : fixups_to_jump_tables_) {
6155 jump_table->CreateJumpTable();
6156 }
6157
6158 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04006159 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04006160 }
6161
6162 // And finish up.
6163 CodeGenerator::Finalize(allocator);
6164}
6165
Mark Mendellf55c3e02015-03-26 21:07:46 -04006166Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
6167 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
6168 return Address::RIP(fixup);
6169}
6170
6171Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
6172 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
6173 return Address::RIP(fixup);
6174}
6175
6176Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
6177 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
6178 return Address::RIP(fixup);
6179}
6180
6181Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
6182 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
6183 return Address::RIP(fixup);
6184}
6185
Andreas Gampe85b62f22015-09-09 13:15:38 -07006186// TODO: trg as memory.
6187void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6188 if (!trg.IsValid()) {
6189 DCHECK(type == Primitive::kPrimVoid);
6190 return;
6191 }
6192
6193 DCHECK_NE(type, Primitive::kPrimVoid);
6194
6195 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
6196 if (trg.Equals(return_loc)) {
6197 return;
6198 }
6199
6200 // Let the parallel move resolver take care of all of this.
6201 HParallelMove parallel_move(GetGraph()->GetArena());
6202 parallel_move.AddMove(return_loc, trg, type, nullptr);
6203 GetMoveResolver()->EmitNativeCode(&parallel_move);
6204}
6205
Mark Mendell9c86b482015-09-18 13:36:07 -04006206Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
6207 // Create a fixup to be used to create and address the jump table.
6208 JumpTableRIPFixup* table_fixup =
6209 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
6210
6211 // We have to populate the jump tables.
6212 fixups_to_jump_tables_.push_back(table_fixup);
6213 return Address::RIP(table_fixup);
6214}
6215
Mark Mendellea5af682015-10-22 17:35:49 -04006216void CodeGeneratorX86_64::MoveInt64ToAddress(const Address& addr_low,
6217 const Address& addr_high,
6218 int64_t v,
6219 HInstruction* instruction) {
6220 if (IsInt<32>(v)) {
6221 int32_t v_32 = v;
6222 __ movq(addr_low, Immediate(v_32));
6223 MaybeRecordImplicitNullCheck(instruction);
6224 } else {
6225 // Didn't fit in a register. Do it in pieces.
6226 int32_t low_v = Low32Bits(v);
6227 int32_t high_v = High32Bits(v);
6228 __ movl(addr_low, Immediate(low_v));
6229 MaybeRecordImplicitNullCheck(instruction);
6230 __ movl(addr_high, Immediate(high_v));
6231 }
6232}
6233
Roland Levillain4d027112015-07-01 15:41:14 +01006234#undef __
6235
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01006236} // namespace x86_64
6237} // namespace art