blob: c4caf4bf9d0088fc411f63d2333515be346a2688 [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;
Vladimir Markof3e0ee22015-12-17 15:23:13 +000044// The compare/jump sequence will generate about (1.5 * num_entries) instructions. A jump
45// table version generates 7 instructions and num_entries literals. Compare/jump sequence will
46// generates less code/data with a small num_entries.
47static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010048
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000049static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000050static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010051
Mark Mendell24f2dfa2015-01-14 19:51:45 -050052static constexpr int kC2ConditionMask = 0x400;
53
Roland Levillain7cbd27f2016-08-11 23:53:33 +010054// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
55#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070056#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64PointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010057
Andreas Gampe85b62f22015-09-09 13:15:38 -070058class NullCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000060 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061
Alexandre Rames2ed20af2015-03-06 13:55:35 +000062 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +000063 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000065 if (instruction_->CanThrowIntoCatchBlock()) {
66 // Live registers will be restored in the catch block if caught.
67 SaveLiveRegisters(codegen, instruction_->GetLocations());
68 }
Serban Constantinescuba45db02016-07-12 22:53:02 +010069 x86_64_codegen->InvokeRuntime(kQuickThrowNullPointer,
Roland Levillain0d5a2812015-11-13 10:07:31 +000070 instruction_,
71 instruction_->GetDexPc(),
72 this);
Roland Levillain888d0672015-11-23 18:53:50 +000073 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074 }
75
Alexandre Rames8158f282015-08-07 10:26:17 +010076 bool IsFatal() const OVERRIDE { return true; }
77
Alexandre Rames9931f312015-06-19 14:47:01 +010078 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
79
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
82};
83
Andreas Gampe85b62f22015-09-09 13:15:38 -070084class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000085 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000086 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +000087
Alexandre Rames2ed20af2015-03-06 13:55:35 +000088 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +000089 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000090 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +010091 x86_64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000092 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +000093 }
94
Alexandre Rames8158f282015-08-07 10:26:17 +010095 bool IsFatal() const OVERRIDE { return true; }
96
Alexandre Rames9931f312015-06-19 14:47:01 +010097 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
98
Calin Juravled0d48522014-11-04 16:40:20 +000099 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000100 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
101};
102
Andreas Gampe85b62f22015-09-09 13:15:38 -0700103class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000104 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000105 DivRemMinusOneSlowPathX86_64(HInstruction* at, Register reg, Primitive::Type type, bool is_div)
106 : SlowPathCode(at), cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000107
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000108 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000109 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000110 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000111 if (is_div_) {
112 __ negl(cpu_reg_);
113 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400114 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000115 }
116
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000117 } else {
118 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000119 if (is_div_) {
120 __ negq(cpu_reg_);
121 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400122 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000123 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000124 }
Calin Juravled0d48522014-11-04 16:40:20 +0000125 __ jmp(GetExitLabel());
126 }
127
Alexandre Rames9931f312015-06-19 14:47:01 +0100128 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
129
Calin Juravled0d48522014-11-04 16:40:20 +0000130 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000131 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000132 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000133 const bool is_div_;
134 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000135};
136
Andreas Gampe85b62f22015-09-09 13:15:38 -0700137class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100139 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000140 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000141
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000142 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000143 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000144 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +0100145 x86_64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000146 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100147 if (successor_ == nullptr) {
148 __ jmp(GetReturnLabel());
149 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000150 __ jmp(x86_64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100151 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000152 }
153
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100154 Label* GetReturnLabel() {
155 DCHECK(successor_ == nullptr);
156 return &return_label_;
157 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000158
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100159 HBasicBlock* GetSuccessor() const {
160 return successor_;
161 }
162
Alexandre Rames9931f312015-06-19 14:47:01 +0100163 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
164
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000165 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100166 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000167 Label return_label_;
168
169 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
170};
171
Andreas Gampe85b62f22015-09-09 13:15:38 -0700172class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100174 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000175 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100176
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000177 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100178 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000179 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000181 if (instruction_->CanThrowIntoCatchBlock()) {
182 // Live registers will be restored in the catch block if caught.
183 SaveLiveRegisters(codegen, instruction_->GetLocations());
184 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400185 // Are we using an array length from memory?
186 HInstruction* array_length = instruction_->InputAt(1);
187 Location length_loc = locations->InAt(1);
188 InvokeRuntimeCallingConvention calling_convention;
189 if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
190 // Load the array length into our temporary.
191 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
192 Location array_loc = array_length->GetLocations()->InAt(0);
193 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
194 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
195 // Check for conflicts with index.
196 if (length_loc.Equals(locations->InAt(0))) {
197 // We know we aren't using parameter 2.
198 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
199 }
200 __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
jessicahandojo4877b792016-09-08 19:49:13 -0700201 if (mirror::kUseStringCompression) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +0100202 __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -0700203 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400204 }
205
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000206 // We're moving two locations to locations that could overlap, so we need a parallel
207 // move resolver.
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000208 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100209 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000210 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100211 Primitive::kPrimInt,
Mark Mendellee8d9712016-07-12 11:13:15 -0400212 length_loc,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100213 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
214 Primitive::kPrimInt);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100215 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
216 ? kQuickThrowStringBounds
217 : kQuickThrowArrayBounds;
218 x86_64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100219 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000220 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100221 }
222
Alexandre Rames8158f282015-08-07 10:26:17 +0100223 bool IsFatal() const OVERRIDE { return true; }
224
Alexandre Rames9931f312015-06-19 14:47:01 +0100225 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
226
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100227 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100228 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
229};
230
Andreas Gampe85b62f22015-09-09 13:15:38 -0700231class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100232 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000233 LoadClassSlowPathX86_64(HLoadClass* cls,
234 HInstruction* at,
235 uint32_t dex_pc,
236 bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000237 : SlowPathCode(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000238 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
239 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100240
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000241 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000242 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000243 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100244 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100245
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000246 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000247
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100248 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampea5b09a62016-11-17 15:21:22 -0800249 __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
250 Immediate(cls_->GetTypeIndex().index_));
Serban Constantinescuba45db02016-07-12 22:53:02 +0100251 x86_64_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage : kQuickInitializeType,
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000252 instruction_,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000253 dex_pc_,
254 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000255 if (do_clinit_) {
256 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
257 } else {
258 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
259 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100260
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000261 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000262 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000263 if (out.IsValid()) {
264 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000265 x86_64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000266 }
267
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000268 RestoreLiveRegisters(codegen, locations);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000269 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
270 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
271 if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
272 DCHECK(out.IsValid());
273 __ movl(Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false),
274 locations->Out().AsRegister<CpuRegister>());
275 Label* fixup_label = x86_64_codegen->NewTypeBssEntryPatch(cls_);
276 __ Bind(fixup_label);
277 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100278 __ jmp(GetExitLabel());
279 }
280
Alexandre Rames9931f312015-06-19 14:47:01 +0100281 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
282
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100283 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000284 // The class this slow path will load.
285 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100286
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000287 // The dex PC of `at_`.
288 const uint32_t dex_pc_;
289
290 // Whether to initialize the class.
291 const bool do_clinit_;
292
293 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100294};
295
Vladimir Markoaad75c62016-10-03 08:46:48 +0000296class LoadStringSlowPathX86_64 : public SlowPathCode {
297 public:
298 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : SlowPathCode(instruction) {}
299
300 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
301 LocationSummary* locations = instruction_->GetLocations();
302 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
303
304 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
305 __ Bind(GetEntryLabel());
306 SaveLiveRegisters(codegen, locations);
307
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000308 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100309 // Custom calling convention: RAX serves as both input and output.
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000310 __ movl(CpuRegister(RAX), Immediate(string_index.index_));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000311 x86_64_codegen->InvokeRuntime(kQuickResolveString,
312 instruction_,
313 instruction_->GetDexPc(),
314 this);
315 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
316 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
317 RestoreLiveRegisters(codegen, locations);
318
319 // Store the resolved String to the BSS entry.
320 __ movl(Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false),
321 locations->Out().AsRegister<CpuRegister>());
322 Label* fixup_label = x86_64_codegen->NewStringBssEntryPatch(instruction_->AsLoadString());
323 __ Bind(fixup_label);
324
325 __ jmp(GetExitLabel());
326 }
327
328 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
329
330 private:
331 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
332};
333
Andreas Gampe85b62f22015-09-09 13:15:38 -0700334class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000335 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000336 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000337 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000338
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000339 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100341 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000342 DCHECK(instruction_->IsCheckCast()
343 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000344
Roland Levillain0d5a2812015-11-13 10:07:31 +0000345 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000346 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000347
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000348 if (!is_fatal_) {
349 SaveLiveRegisters(codegen, locations);
350 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000351
352 // We're moving two locations to locations that could overlap, so we need a parallel
353 // move resolver.
354 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800355 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800356 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
357 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800358 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800359 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
360 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000361 if (instruction_->IsInstanceOf()) {
Serban Constantinescuba45db02016-07-12 22:53:02 +0100362 x86_64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800363 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000364 } else {
365 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800366 x86_64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
367 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000368 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000369
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000370 if (!is_fatal_) {
371 if (instruction_->IsInstanceOf()) {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000372 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000373 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000374
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000375 RestoreLiveRegisters(codegen, locations);
376 __ jmp(GetExitLabel());
377 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000378 }
379
Alexandre Rames9931f312015-06-19 14:47:01 +0100380 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
381
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000382 bool IsFatal() const OVERRIDE { return is_fatal_; }
383
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000384 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000385 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000386
387 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
388};
389
Andreas Gampe85b62f22015-09-09 13:15:38 -0700390class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700391 public:
Aart Bik42249c32016-01-07 15:33:50 -0800392 explicit DeoptimizationSlowPathX86_64(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000393 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700394
395 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000396 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700397 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +0100398 x86_64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), 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:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700405 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
406};
407
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100408class ArraySetSlowPathX86_64 : public SlowPathCode {
409 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000410 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100411
412 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
413 LocationSummary* locations = instruction_->GetLocations();
414 __ Bind(GetEntryLabel());
415 SaveLiveRegisters(codegen, locations);
416
417 InvokeRuntimeCallingConvention calling_convention;
418 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
419 parallel_move.AddMove(
420 locations->InAt(0),
421 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
422 Primitive::kPrimNot,
423 nullptr);
424 parallel_move.AddMove(
425 locations->InAt(1),
426 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
427 Primitive::kPrimInt,
428 nullptr);
429 parallel_move.AddMove(
430 locations->InAt(2),
431 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
432 Primitive::kPrimNot,
433 nullptr);
434 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
435
Roland Levillain0d5a2812015-11-13 10:07:31 +0000436 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100437 x86_64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000438 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100439 RestoreLiveRegisters(codegen, locations);
440 __ jmp(GetExitLabel());
441 }
442
443 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86_64"; }
444
445 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100446 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
447};
448
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100449// Slow path marking an object reference `ref` during a read
450// barrier. The field `obj.field` in the object `obj` holding this
451// reference does not get updated by this slow path after marking (see
452// ReadBarrierMarkAndUpdateFieldSlowPathX86_64 below for that).
453//
454// This means that after the execution of this slow path, `ref` will
455// always be up-to-date, but `obj.field` may not; i.e., after the
456// flip, `ref` will be a to-space reference, but `obj.field` will
457// probably still be a from-space reference (unless it gets updated by
458// another thread, or if another thread installed another object
459// reference (different from `ref`) in `obj.field`).
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000460class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode {
461 public:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100462 ReadBarrierMarkSlowPathX86_64(HInstruction* instruction,
463 Location ref,
464 bool unpoison_ref_before_marking)
465 : SlowPathCode(instruction),
466 ref_(ref),
467 unpoison_ref_before_marking_(unpoison_ref_before_marking) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000468 DCHECK(kEmitCompilerReadBarrier);
469 }
470
471 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathX86_64"; }
472
473 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
474 LocationSummary* locations = instruction_->GetLocations();
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100475 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
476 Register ref_reg = ref_cpu_reg.AsRegister();
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000477 DCHECK(locations->CanCall());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100478 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000479 DCHECK(instruction_->IsInstanceFieldGet() ||
480 instruction_->IsStaticFieldGet() ||
481 instruction_->IsArrayGet() ||
Roland Levillain16d9f942016-08-25 17:27:56 +0100482 instruction_->IsArraySet() ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000483 instruction_->IsLoadClass() ||
484 instruction_->IsLoadString() ||
485 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100486 instruction_->IsCheckCast() ||
Roland Levillain0b671c02016-08-19 12:02:34 +0100487 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
488 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000489 << "Unexpected instruction in read barrier marking slow path: "
490 << instruction_->DebugName();
491
492 __ Bind(GetEntryLabel());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100493 if (unpoison_ref_before_marking_) {
Vladimir Marko953437b2016-08-24 08:30:46 +0000494 // Object* ref = ref_addr->AsMirrorPtr()
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100495 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
Vladimir Marko953437b2016-08-24 08:30:46 +0000496 }
Roland Levillain4359e612016-07-20 11:32:19 +0100497 // No need to save live registers; it's taken care of by the
498 // entrypoint. Also, there is no need to update the stack mask,
499 // as this runtime call will not trigger a garbage collection.
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000500 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100501 DCHECK_NE(ref_reg, RSP);
502 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
Roland Levillain02b75802016-07-13 11:54:35 +0100503 // "Compact" slow path, saving two moves.
504 //
505 // Instead of using the standard runtime calling convention (input
506 // and output in R0):
507 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100508 // RDI <- ref
Roland Levillain02b75802016-07-13 11:54:35 +0100509 // RAX <- ReadBarrierMark(RDI)
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100510 // ref <- RAX
Roland Levillain02b75802016-07-13 11:54:35 +0100511 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100512 // we just use rX (the register containing `ref`) as input and output
Roland Levillain02b75802016-07-13 11:54:35 +0100513 // of a dedicated entrypoint:
514 //
515 // rX <- ReadBarrierMarkRegX(rX)
516 //
517 int32_t entry_point_offset =
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100518 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
Roland Levillaindec8f632016-07-22 17:10:06 +0100519 // This runtime call does not require a stack map.
520 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000521 __ jmp(GetExitLabel());
522 }
523
524 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100525 // The location (register) of the marked object reference.
526 const Location ref_;
527 // Should the reference in `ref_` be unpoisoned prior to marking it?
528 const bool unpoison_ref_before_marking_;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000529
530 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86_64);
531};
532
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100533// Slow path marking an object reference `ref` during a read barrier,
534// and if needed, atomically updating the field `obj.field` in the
535// object `obj` holding this reference after marking (contrary to
536// ReadBarrierMarkSlowPathX86_64 above, which never tries to update
537// `obj.field`).
538//
539// This means that after the execution of this slow path, both `ref`
540// and `obj.field` will be up-to-date; i.e., after the flip, both will
541// hold the same to-space reference (unless another thread installed
542// another object reference (different from `ref`) in `obj.field`).
543class ReadBarrierMarkAndUpdateFieldSlowPathX86_64 : public SlowPathCode {
544 public:
545 ReadBarrierMarkAndUpdateFieldSlowPathX86_64(HInstruction* instruction,
546 Location ref,
547 CpuRegister obj,
548 const Address& field_addr,
549 bool unpoison_ref_before_marking,
550 CpuRegister temp1,
551 CpuRegister temp2)
552 : SlowPathCode(instruction),
553 ref_(ref),
554 obj_(obj),
555 field_addr_(field_addr),
556 unpoison_ref_before_marking_(unpoison_ref_before_marking),
557 temp1_(temp1),
558 temp2_(temp2) {
559 DCHECK(kEmitCompilerReadBarrier);
560 }
561
562 const char* GetDescription() const OVERRIDE {
563 return "ReadBarrierMarkAndUpdateFieldSlowPathX86_64";
564 }
565
566 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
567 LocationSummary* locations = instruction_->GetLocations();
568 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
569 Register ref_reg = ref_cpu_reg.AsRegister();
570 DCHECK(locations->CanCall());
571 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
572 // This slow path is only used by the UnsafeCASObject intrinsic.
573 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
574 << "Unexpected instruction in read barrier marking and field updating slow path: "
575 << instruction_->DebugName();
576 DCHECK(instruction_->GetLocations()->Intrinsified());
577 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
578
579 __ Bind(GetEntryLabel());
580 if (unpoison_ref_before_marking_) {
581 // Object* ref = ref_addr->AsMirrorPtr()
582 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
583 }
584
585 // Save the old (unpoisoned) reference.
586 __ movl(temp1_, ref_cpu_reg);
587
588 // No need to save live registers; it's taken care of by the
589 // entrypoint. Also, there is no need to update the stack mask,
590 // as this runtime call will not trigger a garbage collection.
591 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
592 DCHECK_NE(ref_reg, RSP);
593 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
594 // "Compact" slow path, saving two moves.
595 //
596 // Instead of using the standard runtime calling convention (input
597 // and output in R0):
598 //
599 // RDI <- ref
600 // RAX <- ReadBarrierMark(RDI)
601 // ref <- RAX
602 //
603 // we just use rX (the register containing `ref`) as input and output
604 // of a dedicated entrypoint:
605 //
606 // rX <- ReadBarrierMarkRegX(rX)
607 //
608 int32_t entry_point_offset =
609 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
610 // This runtime call does not require a stack map.
611 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
612
613 // If the new reference is different from the old reference,
614 // update the field in the holder (`*field_addr`).
615 //
616 // Note that this field could also hold a different object, if
617 // another thread had concurrently changed it. In that case, the
618 // LOCK CMPXCHGL instruction in the compare-and-set (CAS)
619 // operation below would abort the CAS, leaving the field as-is.
620 NearLabel done;
621 __ cmpl(temp1_, ref_cpu_reg);
622 __ j(kEqual, &done);
623
624 // Update the the holder's field atomically. This may fail if
625 // mutator updates before us, but it's OK. This is achived
626 // using a strong compare-and-set (CAS) operation with relaxed
627 // memory synchronization ordering, where the expected value is
628 // the old reference and the desired value is the new reference.
629 // This operation is implemented with a 32-bit LOCK CMPXLCHG
630 // instruction, which requires the expected value (the old
631 // reference) to be in EAX. Save RAX beforehand, and move the
632 // expected value (stored in `temp1_`) into EAX.
633 __ movq(temp2_, CpuRegister(RAX));
634 __ movl(CpuRegister(RAX), temp1_);
635
636 // Convenience aliases.
637 CpuRegister base = obj_;
638 CpuRegister expected = CpuRegister(RAX);
639 CpuRegister value = ref_cpu_reg;
640
641 bool base_equals_value = (base.AsRegister() == value.AsRegister());
642 Register value_reg = ref_reg;
643 if (kPoisonHeapReferences) {
644 if (base_equals_value) {
645 // If `base` and `value` are the same register location, move
646 // `value_reg` to a temporary register. This way, poisoning
647 // `value_reg` won't invalidate `base`.
648 value_reg = temp1_.AsRegister();
649 __ movl(CpuRegister(value_reg), base);
650 }
651
652 // Check that the register allocator did not assign the location
653 // of `expected` (RAX) to `value` nor to `base`, so that heap
654 // poisoning (when enabled) works as intended below.
655 // - If `value` were equal to `expected`, both references would
656 // be poisoned twice, meaning they would not be poisoned at
657 // all, as heap poisoning uses address negation.
658 // - If `base` were equal to `expected`, poisoning `expected`
659 // would invalidate `base`.
660 DCHECK_NE(value_reg, expected.AsRegister());
661 DCHECK_NE(base.AsRegister(), expected.AsRegister());
662
663 __ PoisonHeapReference(expected);
664 __ PoisonHeapReference(CpuRegister(value_reg));
665 }
666
667 __ LockCmpxchgl(field_addr_, CpuRegister(value_reg));
668
669 // If heap poisoning is enabled, we need to unpoison the values
670 // that were poisoned earlier.
671 if (kPoisonHeapReferences) {
672 if (base_equals_value) {
673 // `value_reg` has been moved to a temporary register, no need
674 // to unpoison it.
675 } else {
676 __ UnpoisonHeapReference(CpuRegister(value_reg));
677 }
678 // No need to unpoison `expected` (RAX), as it is be overwritten below.
679 }
680
681 // Restore RAX.
682 __ movq(CpuRegister(RAX), temp2_);
683
684 __ Bind(&done);
685 __ jmp(GetExitLabel());
686 }
687
688 private:
689 // The location (register) of the marked object reference.
690 const Location ref_;
691 // The register containing the object holding the marked object reference field.
692 const CpuRegister obj_;
693 // The address of the marked reference field. The base of this address must be `obj_`.
694 const Address field_addr_;
695
696 // Should the reference in `ref_` be unpoisoned prior to marking it?
697 const bool unpoison_ref_before_marking_;
698
699 const CpuRegister temp1_;
700 const CpuRegister temp2_;
701
702 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathX86_64);
703};
704
Roland Levillain0d5a2812015-11-13 10:07:31 +0000705// Slow path generating a read barrier for a heap reference.
706class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
707 public:
708 ReadBarrierForHeapReferenceSlowPathX86_64(HInstruction* instruction,
709 Location out,
710 Location ref,
711 Location obj,
712 uint32_t offset,
713 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000714 : SlowPathCode(instruction),
Roland Levillain0d5a2812015-11-13 10:07:31 +0000715 out_(out),
716 ref_(ref),
717 obj_(obj),
718 offset_(offset),
719 index_(index) {
720 DCHECK(kEmitCompilerReadBarrier);
721 // If `obj` is equal to `out` or `ref`, it means the initial
722 // object has been overwritten by (or after) the heap object
723 // reference load to be instrumented, e.g.:
724 //
725 // __ movl(out, Address(out, offset));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000726 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000727 //
728 // In that case, we have lost the information about the original
729 // object, and the emitted read barrier cannot work properly.
730 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
731 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
732}
733
734 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
735 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
736 LocationSummary* locations = instruction_->GetLocations();
737 CpuRegister reg_out = out_.AsRegister<CpuRegister>();
738 DCHECK(locations->CanCall());
739 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_;
Roland Levillain3d312422016-06-23 13:53:42 +0100740 DCHECK(instruction_->IsInstanceFieldGet() ||
741 instruction_->IsStaticFieldGet() ||
742 instruction_->IsArrayGet() ||
743 instruction_->IsInstanceOf() ||
744 instruction_->IsCheckCast() ||
Roland Levillaindec8f632016-07-22 17:10:06 +0100745 (instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000746 << "Unexpected instruction in read barrier for heap reference slow path: "
747 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000748
749 __ Bind(GetEntryLabel());
750 SaveLiveRegisters(codegen, locations);
751
752 // We may have to change the index's value, but as `index_` is a
753 // constant member (like other "inputs" of this slow path),
754 // introduce a copy of it, `index`.
755 Location index = index_;
756 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100757 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain0d5a2812015-11-13 10:07:31 +0000758 if (instruction_->IsArrayGet()) {
759 // Compute real offset and store it in index_.
760 Register index_reg = index_.AsRegister<CpuRegister>().AsRegister();
761 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
762 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
763 // We are about to change the value of `index_reg` (see the
764 // calls to art::x86_64::X86_64Assembler::shll and
765 // art::x86_64::X86_64Assembler::AddImmediate below), but it
766 // has not been saved by the previous call to
767 // art::SlowPathCode::SaveLiveRegisters, as it is a
768 // callee-save register --
769 // art::SlowPathCode::SaveLiveRegisters does not consider
770 // callee-save registers, as it has been designed with the
771 // assumption that callee-save registers are supposed to be
772 // handled by the called function. So, as a callee-save
773 // register, `index_reg` _would_ eventually be saved onto
774 // the stack, but it would be too late: we would have
775 // changed its value earlier. Therefore, we manually save
776 // it here into another freely available register,
777 // `free_reg`, chosen of course among the caller-save
778 // registers (as a callee-save `free_reg` register would
779 // exhibit the same problem).
780 //
781 // Note we could have requested a temporary register from
782 // the register allocator instead; but we prefer not to, as
783 // this is a slow path, and we know we can find a
784 // caller-save register that is available.
785 Register free_reg = FindAvailableCallerSaveRegister(codegen).AsRegister();
786 __ movl(CpuRegister(free_reg), CpuRegister(index_reg));
787 index_reg = free_reg;
788 index = Location::RegisterLocation(index_reg);
789 } else {
790 // The initial register stored in `index_` has already been
791 // saved in the call to art::SlowPathCode::SaveLiveRegisters
792 // (as it is not a callee-save register), so we can freely
793 // use it.
794 }
795 // Shifting the index value contained in `index_reg` by the
796 // scale factor (2) cannot overflow in practice, as the
797 // runtime is unable to allocate object arrays with a size
798 // larger than 2^26 - 1 (that is, 2^28 - 4 bytes).
799 __ shll(CpuRegister(index_reg), Immediate(TIMES_4));
800 static_assert(
801 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
802 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
803 __ AddImmediate(CpuRegister(index_reg), Immediate(offset_));
804 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100805 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
806 // intrinsics, `index_` is not shifted by a scale factor of 2
807 // (as in the case of ArrayGet), as it is actually an offset
808 // to an object field within an object.
809 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000810 DCHECK(instruction_->GetLocations()->Intrinsified());
811 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
812 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
813 << instruction_->AsInvoke()->GetIntrinsic();
814 DCHECK_EQ(offset_, 0U);
815 DCHECK(index_.IsRegister());
816 }
817 }
818
819 // We're moving two or three locations to locations that could
820 // overlap, so we need a parallel move resolver.
821 InvokeRuntimeCallingConvention calling_convention;
822 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
823 parallel_move.AddMove(ref_,
824 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
825 Primitive::kPrimNot,
826 nullptr);
827 parallel_move.AddMove(obj_,
828 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
829 Primitive::kPrimNot,
830 nullptr);
831 if (index.IsValid()) {
832 parallel_move.AddMove(index,
833 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
834 Primitive::kPrimInt,
835 nullptr);
836 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
837 } else {
838 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
839 __ movl(CpuRegister(calling_convention.GetRegisterAt(2)), Immediate(offset_));
840 }
Serban Constantinescuba45db02016-07-12 22:53:02 +0100841 x86_64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000842 instruction_,
843 instruction_->GetDexPc(),
844 this);
845 CheckEntrypointTypes<
846 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
847 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
848
849 RestoreLiveRegisters(codegen, locations);
850 __ jmp(GetExitLabel());
851 }
852
853 const char* GetDescription() const OVERRIDE {
854 return "ReadBarrierForHeapReferenceSlowPathX86_64";
855 }
856
857 private:
858 CpuRegister FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
859 size_t ref = static_cast<int>(ref_.AsRegister<CpuRegister>().AsRegister());
860 size_t obj = static_cast<int>(obj_.AsRegister<CpuRegister>().AsRegister());
861 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
862 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
863 return static_cast<CpuRegister>(i);
864 }
865 }
866 // We shall never fail to find a free caller-save register, as
867 // there are more than two core caller-save registers on x86-64
868 // (meaning it is possible to find one which is different from
869 // `ref` and `obj`).
870 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
871 LOG(FATAL) << "Could not find a free caller-save register";
872 UNREACHABLE();
873 }
874
Roland Levillain0d5a2812015-11-13 10:07:31 +0000875 const Location out_;
876 const Location ref_;
877 const Location obj_;
878 const uint32_t offset_;
879 // An additional location containing an index to an array.
880 // Only used for HArrayGet and the UnsafeGetObject &
881 // UnsafeGetObjectVolatile intrinsics.
882 const Location index_;
883
884 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86_64);
885};
886
887// Slow path generating a read barrier for a GC root.
888class ReadBarrierForRootSlowPathX86_64 : public SlowPathCode {
889 public:
890 ReadBarrierForRootSlowPathX86_64(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000891 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000892 DCHECK(kEmitCompilerReadBarrier);
893 }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000894
895 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
896 LocationSummary* locations = instruction_->GetLocations();
897 DCHECK(locations->CanCall());
898 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000899 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
900 << "Unexpected instruction in read barrier for GC root slow path: "
901 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000902
903 __ Bind(GetEntryLabel());
904 SaveLiveRegisters(codegen, locations);
905
906 InvokeRuntimeCallingConvention calling_convention;
907 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
908 x86_64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100909 x86_64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000910 instruction_,
911 instruction_->GetDexPc(),
912 this);
913 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
914 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
915
916 RestoreLiveRegisters(codegen, locations);
917 __ jmp(GetExitLabel());
918 }
919
920 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathX86_64"; }
921
922 private:
Roland Levillain0d5a2812015-11-13 10:07:31 +0000923 const Location out_;
924 const Location root_;
925
926 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86_64);
927};
928
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100929#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100930// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
931#define __ down_cast<X86_64Assembler*>(GetAssembler())-> // NOLINT
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100932
Roland Levillain4fa13f62015-07-06 18:11:54 +0100933inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700934 switch (cond) {
935 case kCondEQ: return kEqual;
936 case kCondNE: return kNotEqual;
937 case kCondLT: return kLess;
938 case kCondLE: return kLessEqual;
939 case kCondGT: return kGreater;
940 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700941 case kCondB: return kBelow;
942 case kCondBE: return kBelowEqual;
943 case kCondA: return kAbove;
944 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700945 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100946 LOG(FATAL) << "Unreachable";
947 UNREACHABLE();
948}
949
Aart Bike9f37602015-10-09 11:15:55 -0700950// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100951inline Condition X86_64FPCondition(IfCondition cond) {
952 switch (cond) {
953 case kCondEQ: return kEqual;
954 case kCondNE: return kNotEqual;
955 case kCondLT: return kBelow;
956 case kCondLE: return kBelowEqual;
957 case kCondGT: return kAbove;
958 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700959 default: break; // should not happen
Roland Levillain4fa13f62015-07-06 18:11:54 +0100960 };
961 LOG(FATAL) << "Unreachable";
962 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700963}
964
Vladimir Markodc151b22015-10-15 18:02:30 +0100965HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
966 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100967 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +0000968 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +0100969}
970
Serguei Katkov288c7a82016-05-16 11:53:15 +0600971Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
972 Location temp) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800973 // All registers are assumed to be correctly set up.
Vladimir Marko58155012015-08-19 12:49:41 +0000974 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
975 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100976 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Vladimir Marko58155012015-08-19 12:49:41 +0000977 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100978 uint32_t offset =
979 GetThreadOffset<kX86_64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
980 __ gs()->movq(temp.AsRegister<CpuRegister>(), Address::Absolute(offset, /* no_rip */ true));
Vladimir Marko58155012015-08-19 12:49:41 +0000981 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100982 }
Vladimir Marko58155012015-08-19 12:49:41 +0000983 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +0000984 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +0000985 break;
986 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
987 __ movq(temp.AsRegister<CpuRegister>(), Immediate(invoke->GetMethodAddress()));
988 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000989 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
Vladimir Marko58155012015-08-19 12:49:41 +0000990 __ movq(temp.AsRegister<CpuRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000991 Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000992 // Bind a new fixup label at the end of the "movl" insn.
993 uint32_t offset = invoke->GetDexCacheArrayOffset();
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000994 __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset));
Vladimir Marko58155012015-08-19 12:49:41 +0000995 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000996 }
Vladimir Marko58155012015-08-19 12:49:41 +0000997 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +0000998 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +0000999 Register method_reg;
1000 CpuRegister reg = temp.AsRegister<CpuRegister>();
1001 if (current_method.IsRegister()) {
1002 method_reg = current_method.AsRegister<Register>();
1003 } else {
1004 DCHECK(invoke->GetLocations()->Intrinsified());
1005 DCHECK(!current_method.IsValid());
1006 method_reg = reg.AsRegister();
1007 __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
1008 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00001009 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01001010 __ movq(reg,
1011 Address(CpuRegister(method_reg),
1012 ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
Vladimir Marko40ecb122016-04-06 17:33:41 +01001013 // temp = temp[index_in_cache];
1014 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
1015 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00001016 __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
1017 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01001018 }
Vladimir Marko58155012015-08-19 12:49:41 +00001019 }
Serguei Katkov288c7a82016-05-16 11:53:15 +06001020 return callee_method;
1021}
1022
1023void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
1024 Location temp) {
1025 // All registers are assumed to be correctly set up.
1026 Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
Vladimir Marko58155012015-08-19 12:49:41 +00001027
1028 switch (invoke->GetCodePtrLocation()) {
1029 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
1030 __ call(&frame_entry_label_);
1031 break;
Vladimir Marko58155012015-08-19 12:49:41 +00001032 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
1033 // (callee_method + offset_of_quick_compiled_code)()
1034 __ call(Address(callee_method.AsRegister<CpuRegister>(),
1035 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001036 kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +00001037 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001038 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001039
1040 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001041}
1042
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001043void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
1044 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
1045 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1046 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001047
1048 // Use the calling convention instead of the location of the receiver, as
1049 // intrinsics may have put the receiver in a different register. In the intrinsics
1050 // slow path, the arguments have been moved to the right place, so here we are
1051 // guaranteed that the receiver is the first register of the calling convention.
1052 InvokeDexCallingConvention calling_convention;
1053 Register receiver = calling_convention.GetRegisterAt(0);
1054
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001055 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
Roland Levillain0d5a2812015-11-13 10:07:31 +00001056 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001057 __ movl(temp, Address(CpuRegister(receiver), class_offset));
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001058 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00001059 // Instead of simply (possibly) unpoisoning `temp` here, we should
1060 // emit a read barrier for the previous class reference load.
1061 // However this is not required in practice, as this is an
1062 // intermediate/temporary reference and because the current
1063 // concurrent copying collector keeps the from-space memory
1064 // intact/accessible until the end of the marking phase (the
1065 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001066 __ MaybeUnpoisonHeapReference(temp);
1067 // temp = temp->GetMethodAt(method_offset);
1068 __ movq(temp, Address(temp, method_offset));
1069 // call temp->GetEntryPoint();
1070 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001071 kX86_64PointerSize).SizeValue()));
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001072}
1073
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001074void CodeGeneratorX86_64::RecordSimplePatch() {
1075 if (GetCompilerOptions().GetIncludePatchInformation()) {
1076 simple_patches_.emplace_back();
1077 __ Bind(&simple_patches_.back());
1078 }
1079}
1080
Vladimir Markoaad75c62016-10-03 08:46:48 +00001081void CodeGeneratorX86_64::RecordBootStringPatch(HLoadString* load_string) {
1082 DCHECK(GetCompilerOptions().IsBootImage());
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001083 string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex().index_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001084 __ Bind(&string_patches_.back().label);
1085}
1086
Vladimir Marko1998cd02017-01-13 13:02:58 +00001087void CodeGeneratorX86_64::RecordBootTypePatch(HLoadClass* load_class) {
1088 boot_image_type_patches_.emplace_back(load_class->GetDexFile(),
1089 load_class->GetTypeIndex().index_);
1090 __ Bind(&boot_image_type_patches_.back().label);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001091}
1092
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001093Label* CodeGeneratorX86_64::NewTypeBssEntryPatch(HLoadClass* load_class) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001094 type_bss_entry_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
1095 return &type_bss_entry_patches_.back().label;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001096}
1097
Vladimir Markoaad75c62016-10-03 08:46:48 +00001098Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) {
1099 DCHECK(!GetCompilerOptions().IsBootImage());
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001100 string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex().index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001101 return &string_patches_.back().label;
1102}
1103
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001104Label* CodeGeneratorX86_64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
1105 uint32_t element_offset) {
1106 // Add a patch entry and return the label.
1107 pc_relative_dex_cache_patches_.emplace_back(dex_file, element_offset);
1108 return &pc_relative_dex_cache_patches_.back().label;
1109}
1110
Vladimir Markoaad75c62016-10-03 08:46:48 +00001111// The label points to the end of the "movl" or another instruction but the literal offset
1112// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
1113constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
1114
1115template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1116inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
1117 const ArenaDeque<PatchInfo<Label>>& infos,
1118 ArenaVector<LinkerPatch>* linker_patches) {
1119 for (const PatchInfo<Label>& info : infos) {
1120 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
1121 linker_patches->push_back(
1122 Factory(literal_offset, &info.dex_file, info.label.Position(), info.index));
1123 }
1124}
1125
Vladimir Marko58155012015-08-19 12:49:41 +00001126void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
1127 DCHECK(linker_patches->empty());
1128 size_t size =
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001129 pc_relative_dex_cache_patches_.size() +
1130 simple_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001131 string_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00001132 boot_image_type_patches_.size() +
1133 type_bss_entry_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00001134 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001135 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
1136 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001137 for (const Label& label : simple_patches_) {
1138 uint32_t literal_offset = label.Position() - kLabelPositionToLiteralOffsetAdjustment;
1139 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
1140 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00001141 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001142 DCHECK(boot_image_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00001143 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches);
1144 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001145 // These are always PC-relative, see GetSupportedLoadClassKind()/GetSupportedLoadStringKind().
Vladimir Marko1998cd02017-01-13 13:02:58 +00001146 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(boot_image_type_patches_,
1147 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001148 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001149 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00001150 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
1151 linker_patches);
1152 DCHECK_EQ(size, linker_patches->size());
Vladimir Marko58155012015-08-19 12:49:41 +00001153}
1154
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001155void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001156 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001157}
1158
1159void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001160 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001161}
1162
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001163size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1164 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
1165 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001166}
1167
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001168size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1169 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1170 return kX86_64WordSize;
1171}
1172
1173size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1174 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
1175 return kX86_64WordSize;
1176}
1177
1178size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1179 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1180 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001181}
1182
Calin Juravle175dc732015-08-25 15:42:32 +01001183void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
1184 HInstruction* instruction,
1185 uint32_t dex_pc,
1186 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001187 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001188 GenerateInvokeRuntime(GetThreadOffset<kX86_64PointerSize>(entrypoint).Int32Value());
1189 if (EntrypointRequiresStackMap(entrypoint)) {
1190 RecordPcInfo(instruction, dex_pc, slow_path);
1191 }
Alexandre Rames8158f282015-08-07 10:26:17 +01001192}
1193
Roland Levillaindec8f632016-07-22 17:10:06 +01001194void CodeGeneratorX86_64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1195 HInstruction* instruction,
1196 SlowPathCode* slow_path) {
1197 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001198 GenerateInvokeRuntime(entry_point_offset);
1199}
1200
1201void CodeGeneratorX86_64::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01001202 __ gs()->call(Address::Absolute(entry_point_offset, /* no_rip */ true));
1203}
1204
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001205static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001206// Use a fake return address register to mimic Quick.
1207static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -04001208CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +00001209 const X86_64InstructionSetFeatures& isa_features,
1210 const CompilerOptions& compiler_options,
1211 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +00001212 : CodeGenerator(graph,
1213 kNumberOfCpuRegisters,
1214 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001215 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001216 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1217 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001218 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001219 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1220 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001221 compiler_options,
1222 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001223 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001224 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001225 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -04001226 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01001227 assembler_(graph->GetArena()),
Mark Mendellf55c3e02015-03-26 21:07:46 -04001228 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +00001229 constant_area_start_(0),
Vladimir Marko0f7dca42015-11-02 14:36:43 +00001230 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001231 simple_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1232 string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00001233 boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1234 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00001235 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00001236 jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1237 jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001238 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
1239}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001240
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001241InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
1242 CodeGeneratorX86_64* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001243 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001244 assembler_(codegen->GetAssembler()),
1245 codegen_(codegen) {}
1246
David Brazdil58282f42016-01-14 12:45:10 +00001247void CodeGeneratorX86_64::SetupBlockedRegisters() const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001248 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001249 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001250
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001251 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001252 blocked_core_registers_[TMP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001253}
1254
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001255static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001256 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001257}
David Srbecky9d8606d2015-04-12 09:35:32 +01001258
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001259static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001260 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001261}
1262
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001263void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001264 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001265 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001266 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -07001267 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001268 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001269
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001270 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001271 __ testq(CpuRegister(RAX), Address(
1272 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001273 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001274 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +00001275
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001276 if (HasEmptyFrame()) {
1277 return;
1278 }
1279
Nicolas Geoffray98893962015-01-21 12:32:32 +00001280 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001281 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001282 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001283 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001284 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1285 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +00001286 }
1287 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001288
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001289 int adjust = GetFrameSize() - GetCoreSpillSize();
1290 __ subq(CpuRegister(RSP), Immediate(adjust));
1291 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001292 uint32_t xmm_spill_location = GetFpuSpillStart();
1293 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001294
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001295 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1296 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001297 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1298 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
1299 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001300 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001301 }
1302
Mingyao Yang063fc772016-08-02 11:02:54 -07001303 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1304 // Initialize should_deoptimize flag to 0.
1305 __ movl(Address(CpuRegister(RSP), xmm_spill_location - kShouldDeoptimizeFlagSize),
1306 Immediate(0));
1307 }
1308
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01001309 // Save the current method if we need it. Note that we do not
1310 // do this in HCurrentMethod, as the instruction might have been removed
1311 // in the SSA graph.
1312 if (RequiresCurrentMethod()) {
1313 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
1314 CpuRegister(kMethodRegisterArgument));
1315 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001316}
1317
1318void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001319 __ cfi().RememberState();
1320 if (!HasEmptyFrame()) {
1321 uint32_t xmm_spill_location = GetFpuSpillStart();
1322 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
1323 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1324 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1325 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1326 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
1327 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
1328 }
1329 }
1330
1331 int adjust = GetFrameSize() - GetCoreSpillSize();
1332 __ addq(CpuRegister(RSP), Immediate(adjust));
1333 __ cfi().AdjustCFAOffset(-adjust);
1334
1335 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1336 Register reg = kCoreCalleeSaves[i];
1337 if (allocated_registers_.ContainsCoreRegister(reg)) {
1338 __ popq(CpuRegister(reg));
1339 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1340 __ cfi().Restore(DWARFReg(reg));
1341 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001342 }
1343 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001344 __ ret();
1345 __ cfi().RestoreState();
1346 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001347}
1348
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001349void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
1350 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001351}
1352
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001353void CodeGeneratorX86_64::Move(Location destination, Location source) {
1354 if (source.Equals(destination)) {
1355 return;
1356 }
1357 if (destination.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001358 CpuRegister dest = destination.AsRegister<CpuRegister>();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001359 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001360 __ movq(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001361 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001362 __ movd(dest, source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001363 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001364 __ movl(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
1365 } else if (source.IsConstant()) {
1366 HConstant* constant = source.GetConstant();
1367 if (constant->IsLongConstant()) {
1368 Load64BitValue(dest, constant->AsLongConstant()->GetValue());
1369 } else {
1370 Load32BitValue(dest, GetInt32ValueOf(constant));
1371 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001372 } else {
1373 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001374 __ movq(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001375 }
1376 } else if (destination.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001377 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001378 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001379 __ movd(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001380 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001381 __ movaps(dest, source.AsFpuRegister<XmmRegister>());
1382 } else if (source.IsConstant()) {
1383 HConstant* constant = source.GetConstant();
1384 int64_t value = CodeGenerator::GetInt64ValueOf(constant);
1385 if (constant->IsFloatConstant()) {
1386 Load32BitValue(dest, static_cast<int32_t>(value));
1387 } else {
1388 Load64BitValue(dest, value);
1389 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001390 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001391 __ movss(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001392 } else {
1393 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001394 __ movsd(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001395 }
1396 } else if (destination.IsStackSlot()) {
1397 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001398 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001399 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001400 } else if (source.IsFpuRegister()) {
1401 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001402 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001403 } else if (source.IsConstant()) {
1404 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001405 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001406 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001407 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001408 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001409 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1410 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001411 }
1412 } else {
1413 DCHECK(destination.IsDoubleStackSlot());
1414 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001415 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001416 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001417 } else if (source.IsFpuRegister()) {
1418 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001419 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001420 } else if (source.IsConstant()) {
1421 HConstant* constant = source.GetConstant();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001422 DCHECK(constant->IsLongConstant() || constant->IsDoubleConstant());
1423 int64_t value = GetInt64ValueOf(constant);
Mark Mendellcfa410b2015-05-25 16:02:44 -04001424 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001425 } else {
1426 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001427 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1428 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001429 }
1430 }
1431}
1432
Calin Juravle175dc732015-08-25 15:42:32 +01001433void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
1434 DCHECK(location.IsRegister());
1435 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
1436}
1437
Calin Juravlee460d1d2015-09-29 04:52:17 +01001438void CodeGeneratorX86_64::MoveLocation(
1439 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
1440 Move(dst, src);
1441}
1442
1443void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1444 if (location.IsRegister()) {
1445 locations->AddTemp(location);
1446 } else {
1447 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1448 }
1449}
1450
David Brazdilfc6a86a2015-06-26 10:33:45 +00001451void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001452 DCHECK(!successor->IsExitBlock());
1453
1454 HBasicBlock* block = got->GetBlock();
1455 HInstruction* previous = got->GetPrevious();
1456
1457 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001458 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001459 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1460 return;
1461 }
1462
1463 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1464 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1465 }
1466 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001467 __ jmp(codegen_->GetLabelOf(successor));
1468 }
1469}
1470
David Brazdilfc6a86a2015-06-26 10:33:45 +00001471void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1472 got->SetLocations(nullptr);
1473}
1474
1475void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1476 HandleGoto(got, got->GetSuccessor());
1477}
1478
1479void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1480 try_boundary->SetLocations(nullptr);
1481}
1482
1483void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1484 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1485 if (!successor->IsExitBlock()) {
1486 HandleGoto(try_boundary, successor);
1487 }
1488}
1489
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001490void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1491 exit->SetLocations(nullptr);
1492}
1493
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001494void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001495}
1496
Mark Mendell152408f2015-12-31 12:28:50 -05001497template<class LabelType>
Mark Mendellc4701932015-04-10 13:18:51 -04001498void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
Mark Mendell152408f2015-12-31 12:28:50 -05001499 LabelType* true_label,
1500 LabelType* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001501 if (cond->IsFPConditionTrueIfNaN()) {
1502 __ j(kUnordered, true_label);
1503 } else if (cond->IsFPConditionFalseIfNaN()) {
1504 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001505 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001506 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001507}
1508
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001509void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition) {
Mark Mendellc4701932015-04-10 13:18:51 -04001510 LocationSummary* locations = condition->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001511
Mark Mendellc4701932015-04-10 13:18:51 -04001512 Location left = locations->InAt(0);
1513 Location right = locations->InAt(1);
Mark Mendellc4701932015-04-10 13:18:51 -04001514 Primitive::Type type = condition->InputAt(0)->GetType();
1515 switch (type) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001516 case Primitive::kPrimBoolean:
1517 case Primitive::kPrimByte:
1518 case Primitive::kPrimChar:
1519 case Primitive::kPrimShort:
1520 case Primitive::kPrimInt:
1521 case Primitive::kPrimNot: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001522 codegen_->GenerateIntCompare(left, right);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001523 break;
1524 }
Mark Mendellc4701932015-04-10 13:18:51 -04001525 case Primitive::kPrimLong: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001526 codegen_->GenerateLongCompare(left, right);
Mark Mendellc4701932015-04-10 13:18:51 -04001527 break;
1528 }
1529 case Primitive::kPrimFloat: {
1530 if (right.IsFpuRegister()) {
1531 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1532 } else if (right.IsConstant()) {
1533 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1534 codegen_->LiteralFloatAddress(
1535 right.GetConstant()->AsFloatConstant()->GetValue()));
1536 } else {
1537 DCHECK(right.IsStackSlot());
1538 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1539 Address(CpuRegister(RSP), right.GetStackIndex()));
1540 }
Mark Mendellc4701932015-04-10 13:18:51 -04001541 break;
1542 }
1543 case Primitive::kPrimDouble: {
1544 if (right.IsFpuRegister()) {
1545 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1546 } else if (right.IsConstant()) {
1547 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1548 codegen_->LiteralDoubleAddress(
1549 right.GetConstant()->AsDoubleConstant()->GetValue()));
1550 } else {
1551 DCHECK(right.IsDoubleStackSlot());
1552 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1553 Address(CpuRegister(RSP), right.GetStackIndex()));
1554 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001555 break;
1556 }
1557 default:
1558 LOG(FATAL) << "Unexpected condition type " << type;
1559 }
1560}
1561
1562template<class LabelType>
1563void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
1564 LabelType* true_target_in,
1565 LabelType* false_target_in) {
1566 // Generated branching requires both targets to be explicit. If either of the
1567 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1568 LabelType fallthrough_target;
1569 LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1570 LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1571
1572 // Generate the comparison to set the CC.
1573 GenerateCompareTest(condition);
1574
1575 // Now generate the correct jump(s).
1576 Primitive::Type type = condition->InputAt(0)->GetType();
1577 switch (type) {
1578 case Primitive::kPrimLong: {
1579 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
1580 break;
1581 }
1582 case Primitive::kPrimFloat: {
1583 GenerateFPJumps(condition, true_target, false_target);
1584 break;
1585 }
1586 case Primitive::kPrimDouble: {
Mark Mendellc4701932015-04-10 13:18:51 -04001587 GenerateFPJumps(condition, true_target, false_target);
1588 break;
1589 }
1590 default:
1591 LOG(FATAL) << "Unexpected condition type " << type;
1592 }
1593
David Brazdil0debae72015-11-12 18:37:00 +00001594 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001595 __ jmp(false_target);
1596 }
David Brazdil0debae72015-11-12 18:37:00 +00001597
1598 if (fallthrough_target.IsLinked()) {
1599 __ Bind(&fallthrough_target);
1600 }
Mark Mendellc4701932015-04-10 13:18:51 -04001601}
1602
David Brazdil0debae72015-11-12 18:37:00 +00001603static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1604 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1605 // are set only strictly before `branch`. We can't use the eflags on long
1606 // conditions if they are materialized due to the complex branching.
1607 return cond->IsCondition() &&
1608 cond->GetNext() == branch &&
1609 !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
1610}
1611
Mark Mendell152408f2015-12-31 12:28:50 -05001612template<class LabelType>
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001613void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001614 size_t condition_input_index,
Mark Mendell152408f2015-12-31 12:28:50 -05001615 LabelType* true_target,
1616 LabelType* false_target) {
David Brazdil0debae72015-11-12 18:37:00 +00001617 HInstruction* cond = instruction->InputAt(condition_input_index);
1618
1619 if (true_target == nullptr && false_target == nullptr) {
1620 // Nothing to do. The code always falls through.
1621 return;
1622 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001623 // Constant condition, statically compared against "true" (integer value 1).
1624 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001625 if (true_target != nullptr) {
1626 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001627 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001628 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001629 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001630 if (false_target != nullptr) {
1631 __ jmp(false_target);
1632 }
1633 }
1634 return;
1635 }
1636
1637 // The following code generates these patterns:
1638 // (1) true_target == nullptr && false_target != nullptr
1639 // - opposite condition true => branch to false_target
1640 // (2) true_target != nullptr && false_target == nullptr
1641 // - condition true => branch to true_target
1642 // (3) true_target != nullptr && false_target != nullptr
1643 // - condition true => branch to true_target
1644 // - branch to false_target
1645 if (IsBooleanValueOrMaterializedCondition(cond)) {
1646 if (AreEflagsSetFrom(cond, instruction)) {
1647 if (true_target == nullptr) {
1648 __ j(X86_64IntegerCondition(cond->AsCondition()->GetOppositeCondition()), false_target);
1649 } else {
1650 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
1651 }
1652 } else {
1653 // Materialized condition, compare against 0.
1654 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
1655 if (lhs.IsRegister()) {
1656 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1657 } else {
1658 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
1659 }
1660 if (true_target == nullptr) {
1661 __ j(kEqual, false_target);
1662 } else {
1663 __ j(kNotEqual, true_target);
1664 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001665 }
1666 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001667 // Condition has not been materialized, use its inputs as the
1668 // comparison and its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001669 HCondition* condition = cond->AsCondition();
Mark Mendellc4701932015-04-10 13:18:51 -04001670
David Brazdil0debae72015-11-12 18:37:00 +00001671 // If this is a long or FP comparison that has been folded into
1672 // the HCondition, generate the comparison directly.
1673 Primitive::Type type = condition->InputAt(0)->GetType();
1674 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1675 GenerateCompareTestAndBranch(condition, true_target, false_target);
1676 return;
1677 }
1678
1679 Location lhs = condition->GetLocations()->InAt(0);
1680 Location rhs = condition->GetLocations()->InAt(1);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001681 codegen_->GenerateIntCompare(lhs, rhs);
David Brazdil0debae72015-11-12 18:37:00 +00001682 if (true_target == nullptr) {
1683 __ j(X86_64IntegerCondition(condition->GetOppositeCondition()), false_target);
1684 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001685 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001686 }
Dave Allison20dfc792014-06-16 20:44:29 -07001687 }
David Brazdil0debae72015-11-12 18:37:00 +00001688
1689 // If neither branch falls through (case 3), the conditional branch to `true_target`
1690 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1691 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001692 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001693 }
1694}
1695
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001696void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001697 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1698 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001699 locations->SetInAt(0, Location::Any());
1700 }
1701}
1702
1703void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001704 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1705 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1706 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1707 nullptr : codegen_->GetLabelOf(true_successor);
1708 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1709 nullptr : codegen_->GetLabelOf(false_successor);
1710 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001711}
1712
1713void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1714 LocationSummary* locations = new (GetGraph()->GetArena())
1715 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01001716 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00001717 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001718 locations->SetInAt(0, Location::Any());
1719 }
1720}
1721
1722void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001723 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathX86_64>(deoptimize);
David Brazdil74eb1b22015-12-14 11:44:01 +00001724 GenerateTestAndBranch<Label>(deoptimize,
1725 /* condition_input_index */ 0,
1726 slow_path->GetEntryLabel(),
1727 /* false_target */ nullptr);
1728}
1729
Mingyao Yang063fc772016-08-02 11:02:54 -07001730void LocationsBuilderX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1731 LocationSummary* locations = new (GetGraph()->GetArena())
1732 LocationSummary(flag, LocationSummary::kNoCall);
1733 locations->SetOut(Location::RequiresRegister());
1734}
1735
1736void InstructionCodeGeneratorX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1737 __ movl(flag->GetLocations()->Out().AsRegister<CpuRegister>(),
1738 Address(CpuRegister(RSP), codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
1739}
1740
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001741static bool SelectCanUseCMOV(HSelect* select) {
1742 // There are no conditional move instructions for XMMs.
1743 if (Primitive::IsFloatingPointType(select->GetType())) {
1744 return false;
1745 }
1746
1747 // A FP condition doesn't generate the single CC that we need.
1748 HInstruction* condition = select->GetCondition();
1749 if (condition->IsCondition() &&
1750 Primitive::IsFloatingPointType(condition->InputAt(0)->GetType())) {
1751 return false;
1752 }
1753
1754 // We can generate a CMOV for this Select.
1755 return true;
1756}
1757
David Brazdil74eb1b22015-12-14 11:44:01 +00001758void LocationsBuilderX86_64::VisitSelect(HSelect* select) {
1759 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1760 if (Primitive::IsFloatingPointType(select->GetType())) {
1761 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001762 locations->SetInAt(1, Location::Any());
David Brazdil74eb1b22015-12-14 11:44:01 +00001763 } else {
1764 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001765 if (SelectCanUseCMOV(select)) {
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001766 if (select->InputAt(1)->IsConstant()) {
1767 locations->SetInAt(1, Location::RequiresRegister());
1768 } else {
1769 locations->SetInAt(1, Location::Any());
1770 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001771 } else {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001772 locations->SetInAt(1, Location::Any());
1773 }
David Brazdil74eb1b22015-12-14 11:44:01 +00001774 }
1775 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1776 locations->SetInAt(2, Location::RequiresRegister());
1777 }
1778 locations->SetOut(Location::SameAsFirstInput());
1779}
1780
1781void InstructionCodeGeneratorX86_64::VisitSelect(HSelect* select) {
1782 LocationSummary* locations = select->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001783 if (SelectCanUseCMOV(select)) {
1784 // If both the condition and the source types are integer, we can generate
1785 // a CMOV to implement Select.
1786 CpuRegister value_false = locations->InAt(0).AsRegister<CpuRegister>();
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001787 Location value_true_loc = locations->InAt(1);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001788 DCHECK(locations->InAt(0).Equals(locations->Out()));
1789
1790 HInstruction* select_condition = select->GetCondition();
1791 Condition cond = kNotEqual;
1792
1793 // Figure out how to test the 'condition'.
1794 if (select_condition->IsCondition()) {
1795 HCondition* condition = select_condition->AsCondition();
1796 if (!condition->IsEmittedAtUseSite()) {
1797 // This was a previously materialized condition.
1798 // Can we use the existing condition code?
1799 if (AreEflagsSetFrom(condition, select)) {
1800 // Materialization was the previous instruction. Condition codes are right.
1801 cond = X86_64IntegerCondition(condition->GetCondition());
1802 } else {
1803 // No, we have to recreate the condition code.
1804 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1805 __ testl(cond_reg, cond_reg);
1806 }
1807 } else {
1808 GenerateCompareTest(condition);
1809 cond = X86_64IntegerCondition(condition->GetCondition());
1810 }
1811 } else {
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001812 // Must be a Boolean condition, which needs to be compared to 0.
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001813 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1814 __ testl(cond_reg, cond_reg);
1815 }
1816
1817 // If the condition is true, overwrite the output, which already contains false.
1818 // Generate the correct sized CMOV.
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001819 bool is_64_bit = Primitive::Is64BitType(select->GetType());
1820 if (value_true_loc.IsRegister()) {
1821 __ cmov(cond, value_false, value_true_loc.AsRegister<CpuRegister>(), is_64_bit);
1822 } else {
1823 __ cmov(cond,
1824 value_false,
1825 Address(CpuRegister(RSP), value_true_loc.GetStackIndex()), is_64_bit);
1826 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001827 } else {
1828 NearLabel false_target;
1829 GenerateTestAndBranch<NearLabel>(select,
1830 /* condition_input_index */ 2,
1831 /* true_target */ nullptr,
1832 &false_target);
1833 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1834 __ Bind(&false_target);
1835 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001836}
1837
David Srbecky0cf44932015-12-09 14:09:59 +00001838void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1839 new (GetGraph()->GetArena()) LocationSummary(info);
1840}
1841
David Srbeckyd28f4a02016-03-14 17:14:24 +00001842void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo*) {
1843 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001844}
1845
1846void CodeGeneratorX86_64::GenerateNop() {
1847 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001848}
1849
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001850void LocationsBuilderX86_64::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001851 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001852 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001853 // Handle the long/FP comparisons made in instruction simplification.
1854 switch (cond->InputAt(0)->GetType()) {
1855 case Primitive::kPrimLong:
1856 locations->SetInAt(0, Location::RequiresRegister());
1857 locations->SetInAt(1, Location::Any());
1858 break;
1859 case Primitive::kPrimFloat:
1860 case Primitive::kPrimDouble:
1861 locations->SetInAt(0, Location::RequiresFpuRegister());
1862 locations->SetInAt(1, Location::Any());
1863 break;
1864 default:
1865 locations->SetInAt(0, Location::RequiresRegister());
1866 locations->SetInAt(1, Location::Any());
1867 break;
1868 }
David Brazdilb3e773e2016-01-26 11:28:37 +00001869 if (!cond->IsEmittedAtUseSite()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001870 locations->SetOut(Location::RequiresRegister());
1871 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001872}
1873
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001874void InstructionCodeGeneratorX86_64::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001875 if (cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04001876 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001877 }
Mark Mendellc4701932015-04-10 13:18:51 -04001878
1879 LocationSummary* locations = cond->GetLocations();
1880 Location lhs = locations->InAt(0);
1881 Location rhs = locations->InAt(1);
1882 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Mark Mendell152408f2015-12-31 12:28:50 -05001883 NearLabel true_label, false_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001884
1885 switch (cond->InputAt(0)->GetType()) {
1886 default:
1887 // Integer case.
1888
1889 // Clear output register: setcc only sets the low byte.
1890 __ xorl(reg, reg);
1891
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001892 codegen_->GenerateIntCompare(lhs, rhs);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001893 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001894 return;
1895 case Primitive::kPrimLong:
1896 // Clear output register: setcc only sets the low byte.
1897 __ xorl(reg, reg);
1898
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001899 codegen_->GenerateLongCompare(lhs, rhs);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001900 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001901 return;
1902 case Primitive::kPrimFloat: {
1903 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1904 if (rhs.IsConstant()) {
1905 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1906 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1907 } else if (rhs.IsStackSlot()) {
1908 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1909 } else {
1910 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1911 }
1912 GenerateFPJumps(cond, &true_label, &false_label);
1913 break;
1914 }
1915 case Primitive::kPrimDouble: {
1916 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1917 if (rhs.IsConstant()) {
1918 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1919 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1920 } else if (rhs.IsDoubleStackSlot()) {
1921 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1922 } else {
1923 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1924 }
1925 GenerateFPJumps(cond, &true_label, &false_label);
1926 break;
1927 }
1928 }
1929
1930 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001931 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001932
Roland Levillain4fa13f62015-07-06 18:11:54 +01001933 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001934 __ Bind(&false_label);
1935 __ xorl(reg, reg);
1936 __ jmp(&done_label);
1937
Roland Levillain4fa13f62015-07-06 18:11:54 +01001938 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001939 __ Bind(&true_label);
1940 __ movl(reg, Immediate(1));
1941 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001942}
1943
1944void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001945 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001946}
1947
1948void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001949 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001950}
1951
1952void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001953 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001954}
1955
1956void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001957 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001958}
1959
1960void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001961 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001962}
1963
1964void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001965 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001966}
1967
1968void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001969 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001970}
1971
1972void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001973 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001974}
1975
1976void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001977 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001978}
1979
1980void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001981 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001982}
1983
1984void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001985 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001986}
1987
1988void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001989 HandleCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001990}
1991
Aart Bike9f37602015-10-09 11:15:55 -07001992void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001993 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001994}
1995
1996void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001997 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001998}
1999
2000void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002001 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002002}
2003
2004void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002005 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002006}
2007
2008void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002009 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002010}
2011
2012void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002013 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002014}
2015
2016void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002017 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002018}
2019
2020void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002021 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002022}
2023
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002024void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002025 LocationSummary* locations =
2026 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002027 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002028 case Primitive::kPrimBoolean:
2029 case Primitive::kPrimByte:
2030 case Primitive::kPrimShort:
2031 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002032 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00002033 case Primitive::kPrimLong: {
2034 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04002035 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00002036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2037 break;
2038 }
2039 case Primitive::kPrimFloat:
2040 case Primitive::kPrimDouble: {
2041 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04002042 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00002043 locations->SetOut(Location::RequiresRegister());
2044 break;
2045 }
2046 default:
2047 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2048 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002049}
2050
2051void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002052 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002053 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002054 Location left = locations->InAt(0);
2055 Location right = locations->InAt(1);
2056
Mark Mendell0c9497d2015-08-21 09:30:05 -04002057 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00002058 Primitive::Type type = compare->InputAt(0)->GetType();
Aart Bika19616e2016-02-01 18:57:58 -08002059 Condition less_cond = kLess;
2060
Calin Juravleddb7df22014-11-25 20:56:51 +00002061 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002062 case Primitive::kPrimBoolean:
2063 case Primitive::kPrimByte:
2064 case Primitive::kPrimShort:
2065 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002066 case Primitive::kPrimInt: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002067 codegen_->GenerateIntCompare(left, right);
Aart Bika19616e2016-02-01 18:57:58 -08002068 break;
2069 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002070 case Primitive::kPrimLong: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002071 codegen_->GenerateLongCompare(left, right);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002072 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00002073 }
2074 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04002075 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2076 if (right.IsConstant()) {
2077 float value = right.GetConstant()->AsFloatConstant()->GetValue();
2078 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
2079 } else if (right.IsStackSlot()) {
2080 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2081 } else {
2082 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
2083 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002084 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002085 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002086 break;
2087 }
2088 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04002089 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2090 if (right.IsConstant()) {
2091 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
2092 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
2093 } else if (right.IsDoubleStackSlot()) {
2094 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2095 } else {
2096 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
2097 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002098 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002099 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002100 break;
2101 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002102 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002103 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002104 }
Aart Bika19616e2016-02-01 18:57:58 -08002105
Calin Juravleddb7df22014-11-25 20:56:51 +00002106 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00002107 __ j(kEqual, &done);
Aart Bika19616e2016-02-01 18:57:58 -08002108 __ j(less_cond, &less);
Calin Juravlefd861242014-11-25 20:56:51 +00002109
Calin Juravle91debbc2014-11-26 19:01:09 +00002110 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00002111 __ movl(out, Immediate(1));
2112 __ jmp(&done);
2113
2114 __ Bind(&less);
2115 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002116
2117 __ Bind(&done);
2118}
2119
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002120void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002121 LocationSummary* locations =
2122 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002123 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002124}
2125
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002126void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002127 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002128}
2129
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002130void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
2131 LocationSummary* locations =
2132 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2133 locations->SetOut(Location::ConstantLocation(constant));
2134}
2135
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002136void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002137 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002138}
2139
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002140void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002141 LocationSummary* locations =
2142 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002143 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002144}
2145
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002146void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002147 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002148}
2149
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002150void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
2151 LocationSummary* locations =
2152 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2153 locations->SetOut(Location::ConstantLocation(constant));
2154}
2155
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002156void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002157 // Will be generated at use site.
2158}
2159
2160void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
2161 LocationSummary* locations =
2162 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2163 locations->SetOut(Location::ConstantLocation(constant));
2164}
2165
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002166void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
2167 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002168 // Will be generated at use site.
2169}
2170
Calin Juravle27df7582015-04-17 19:12:31 +01002171void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2172 memory_barrier->SetLocations(nullptr);
2173}
2174
2175void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00002176 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01002177}
2178
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002179void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
2180 ret->SetLocations(nullptr);
2181}
2182
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002183void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002184 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002185}
2186
2187void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002188 LocationSummary* locations =
2189 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002190 switch (ret->InputAt(0)->GetType()) {
2191 case Primitive::kPrimBoolean:
2192 case Primitive::kPrimByte:
2193 case Primitive::kPrimChar:
2194 case Primitive::kPrimShort:
2195 case Primitive::kPrimInt:
2196 case Primitive::kPrimNot:
2197 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002198 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002199 break;
2200
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002201 case Primitive::kPrimFloat:
2202 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04002203 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002204 break;
2205
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002206 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002207 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002208 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002209}
2210
2211void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
2212 if (kIsDebugBuild) {
2213 switch (ret->InputAt(0)->GetType()) {
2214 case Primitive::kPrimBoolean:
2215 case Primitive::kPrimByte:
2216 case Primitive::kPrimChar:
2217 case Primitive::kPrimShort:
2218 case Primitive::kPrimInt:
2219 case Primitive::kPrimNot:
2220 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002221 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002222 break;
2223
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002224 case Primitive::kPrimFloat:
2225 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002226 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002227 XMM0);
2228 break;
2229
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002230 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002231 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002232 }
2233 }
2234 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002235}
2236
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002237Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
2238 switch (type) {
2239 case Primitive::kPrimBoolean:
2240 case Primitive::kPrimByte:
2241 case Primitive::kPrimChar:
2242 case Primitive::kPrimShort:
2243 case Primitive::kPrimInt:
2244 case Primitive::kPrimNot:
2245 case Primitive::kPrimLong:
2246 return Location::RegisterLocation(RAX);
2247
2248 case Primitive::kPrimVoid:
2249 return Location::NoLocation();
2250
2251 case Primitive::kPrimDouble:
2252 case Primitive::kPrimFloat:
2253 return Location::FpuRegisterLocation(XMM0);
2254 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002255
2256 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002257}
2258
2259Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
2260 return Location::RegisterLocation(kMethodRegisterArgument);
2261}
2262
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002263Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002264 switch (type) {
2265 case Primitive::kPrimBoolean:
2266 case Primitive::kPrimByte:
2267 case Primitive::kPrimChar:
2268 case Primitive::kPrimShort:
2269 case Primitive::kPrimInt:
2270 case Primitive::kPrimNot: {
2271 uint32_t index = gp_index_++;
2272 stack_index_++;
2273 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002274 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002275 } else {
2276 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2277 }
2278 }
2279
2280 case Primitive::kPrimLong: {
2281 uint32_t index = gp_index_;
2282 stack_index_ += 2;
2283 if (index < calling_convention.GetNumberOfRegisters()) {
2284 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002285 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002286 } else {
2287 gp_index_ += 2;
2288 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2289 }
2290 }
2291
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002292 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002293 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002294 stack_index_++;
2295 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002296 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002297 } else {
2298 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2299 }
2300 }
2301
2302 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002303 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002304 stack_index_ += 2;
2305 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002306 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002307 } else {
2308 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2309 }
2310 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002311
2312 case Primitive::kPrimVoid:
2313 LOG(FATAL) << "Unexpected parameter type " << type;
2314 break;
2315 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00002316 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002317}
2318
Calin Juravle175dc732015-08-25 15:42:32 +01002319void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2320 // The trampoline uses the same calling convention as dex calling conventions,
2321 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2322 // the method_idx.
2323 HandleInvoke(invoke);
2324}
2325
2326void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2327 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2328}
2329
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002330void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002331 // Explicit clinit checks triggered by static invokes must have been pruned by
2332 // art::PrepareForRegisterAllocation.
2333 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002334
Mark Mendellfb8d2792015-03-31 22:16:59 -04002335 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002336 if (intrinsic.TryDispatch(invoke)) {
2337 return;
2338 }
2339
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002340 HandleInvoke(invoke);
2341}
2342
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002343static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
2344 if (invoke->GetLocations()->Intrinsified()) {
2345 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
2346 intrinsic.Dispatch(invoke);
2347 return true;
2348 }
2349 return false;
2350}
2351
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002352void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002353 // Explicit clinit checks triggered by static invokes must have been pruned by
2354 // art::PrepareForRegisterAllocation.
2355 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002356
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002357 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2358 return;
2359 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002360
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002361 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002362 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002363 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00002364 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002365}
2366
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002367void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002368 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002369 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002370}
2371
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002372void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04002373 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002374 if (intrinsic.TryDispatch(invoke)) {
2375 return;
2376 }
2377
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002378 HandleInvoke(invoke);
2379}
2380
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002381void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002382 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2383 return;
2384 }
2385
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002386 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002387 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002388 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002389}
2390
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002391void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2392 HandleInvoke(invoke);
2393 // Add the hidden argument.
2394 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
2395}
2396
2397void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2398 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002399 LocationSummary* locations = invoke->GetLocations();
2400 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2401 CpuRegister hidden_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002402 Location receiver = locations->InAt(0);
2403 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
2404
Roland Levillain0d5a2812015-11-13 10:07:31 +00002405 // Set the hidden argument. This is safe to do this here, as RAX
2406 // won't be modified thereafter, before the `call` instruction.
2407 DCHECK_EQ(RAX, hidden_reg.AsRegister());
Mark Mendell92e83bf2015-05-07 11:25:03 -04002408 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002409
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002410 if (receiver.IsStackSlot()) {
2411 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002412 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002413 __ movl(temp, Address(temp, class_offset));
2414 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002415 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002416 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002417 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002418 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002419 // Instead of simply (possibly) unpoisoning `temp` here, we should
2420 // emit a read barrier for the previous class reference load.
2421 // However this is not required in practice, as this is an
2422 // intermediate/temporary reference and because the current
2423 // concurrent copying collector keeps the from-space memory
2424 // intact/accessible until the end of the marking phase (the
2425 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002426 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002427 // temp = temp->GetAddressOfIMT()
2428 __ movq(temp,
2429 Address(temp, mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
2430 // temp = temp->GetImtEntryAt(method_offset);
2431 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00002432 invoke->GetImtIndex(), kX86_64PointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002433 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002434 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002435 // call temp->GetEntryPoint();
Andreas Gampe542451c2016-07-26 09:02:02 -07002436 __ call(Address(
2437 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64PointerSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002438
2439 DCHECK(!codegen_->IsLeafMethod());
2440 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2441}
2442
Orion Hodsonac141392017-01-13 11:53:47 +00002443void LocationsBuilderX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2444 HandleInvoke(invoke);
2445}
2446
2447void InstructionCodeGeneratorX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2448 codegen_->GenerateInvokePolymorphicCall(invoke);
2449}
2450
Roland Levillain88cb1752014-10-20 16:36:47 +01002451void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
2452 LocationSummary* locations =
2453 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2454 switch (neg->GetResultType()) {
2455 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002456 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01002457 locations->SetInAt(0, Location::RequiresRegister());
2458 locations->SetOut(Location::SameAsFirstInput());
2459 break;
2460
Roland Levillain88cb1752014-10-20 16:36:47 +01002461 case Primitive::kPrimFloat:
2462 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002463 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002464 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00002465 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002466 break;
2467
2468 default:
2469 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2470 }
2471}
2472
2473void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
2474 LocationSummary* locations = neg->GetLocations();
2475 Location out = locations->Out();
2476 Location in = locations->InAt(0);
2477 switch (neg->GetResultType()) {
2478 case Primitive::kPrimInt:
2479 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002480 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002481 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002482 break;
2483
2484 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002485 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002486 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002487 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002488 break;
2489
Roland Levillain5368c212014-11-27 15:03:41 +00002490 case Primitive::kPrimFloat: {
2491 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002492 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002493 // Implement float negation with an exclusive or with value
2494 // 0x80000000 (mask for bit 31, representing the sign of a
2495 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002496 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002497 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002498 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002499 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002500
Roland Levillain5368c212014-11-27 15:03:41 +00002501 case Primitive::kPrimDouble: {
2502 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002503 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002504 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00002505 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00002506 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002507 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002508 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002509 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002510 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002511
2512 default:
2513 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2514 }
2515}
2516
Roland Levillaindff1f282014-11-05 14:15:05 +00002517void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2518 LocationSummary* locations =
2519 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2520 Primitive::Type result_type = conversion->GetResultType();
2521 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002522 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00002523
David Brazdilb2bd1c52015-03-25 11:17:37 +00002524 // The Java language does not allow treating boolean as an integral type but
2525 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002526
Roland Levillaindff1f282014-11-05 14:15:05 +00002527 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002528 case Primitive::kPrimByte:
2529 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002530 case Primitive::kPrimLong:
2531 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002532 case Primitive::kPrimBoolean:
2533 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002534 case Primitive::kPrimShort:
2535 case Primitive::kPrimInt:
2536 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002537 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002538 locations->SetInAt(0, Location::Any());
2539 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2540 break;
2541
2542 default:
2543 LOG(FATAL) << "Unexpected type conversion from " << input_type
2544 << " to " << result_type;
2545 }
2546 break;
2547
Roland Levillain01a8d712014-11-14 16:27:39 +00002548 case Primitive::kPrimShort:
2549 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002550 case Primitive::kPrimLong:
2551 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002552 case Primitive::kPrimBoolean:
2553 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002554 case Primitive::kPrimByte:
2555 case Primitive::kPrimInt:
2556 case Primitive::kPrimChar:
2557 // Processing a Dex `int-to-short' instruction.
2558 locations->SetInAt(0, Location::Any());
2559 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2560 break;
2561
2562 default:
2563 LOG(FATAL) << "Unexpected type conversion from " << input_type
2564 << " to " << result_type;
2565 }
2566 break;
2567
Roland Levillain946e1432014-11-11 17:35:19 +00002568 case Primitive::kPrimInt:
2569 switch (input_type) {
2570 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002571 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002572 locations->SetInAt(0, Location::Any());
2573 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2574 break;
2575
2576 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002577 // Processing a Dex `float-to-int' instruction.
2578 locations->SetInAt(0, Location::RequiresFpuRegister());
2579 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002580 break;
2581
Roland Levillain946e1432014-11-11 17:35:19 +00002582 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002583 // Processing a Dex `double-to-int' instruction.
2584 locations->SetInAt(0, Location::RequiresFpuRegister());
2585 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002586 break;
2587
2588 default:
2589 LOG(FATAL) << "Unexpected type conversion from " << input_type
2590 << " to " << result_type;
2591 }
2592 break;
2593
Roland Levillaindff1f282014-11-05 14:15:05 +00002594 case Primitive::kPrimLong:
2595 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002596 case Primitive::kPrimBoolean:
2597 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002598 case Primitive::kPrimByte:
2599 case Primitive::kPrimShort:
2600 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002601 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002602 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002603 // TODO: We would benefit from a (to-be-implemented)
2604 // Location::RegisterOrStackSlot requirement for this input.
2605 locations->SetInAt(0, Location::RequiresRegister());
2606 locations->SetOut(Location::RequiresRegister());
2607 break;
2608
2609 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002610 // Processing a Dex `float-to-long' instruction.
2611 locations->SetInAt(0, Location::RequiresFpuRegister());
2612 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002613 break;
2614
Roland Levillaindff1f282014-11-05 14:15:05 +00002615 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002616 // Processing a Dex `double-to-long' instruction.
2617 locations->SetInAt(0, Location::RequiresFpuRegister());
2618 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002619 break;
2620
2621 default:
2622 LOG(FATAL) << "Unexpected type conversion from " << input_type
2623 << " to " << result_type;
2624 }
2625 break;
2626
Roland Levillain981e4542014-11-14 11:47:14 +00002627 case Primitive::kPrimChar:
2628 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002629 case Primitive::kPrimLong:
2630 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002631 case Primitive::kPrimBoolean:
2632 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002633 case Primitive::kPrimByte:
2634 case Primitive::kPrimShort:
2635 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002636 // Processing a Dex `int-to-char' instruction.
2637 locations->SetInAt(0, Location::Any());
2638 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2639 break;
2640
2641 default:
2642 LOG(FATAL) << "Unexpected type conversion from " << input_type
2643 << " to " << result_type;
2644 }
2645 break;
2646
Roland Levillaindff1f282014-11-05 14:15:05 +00002647 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002648 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002649 case Primitive::kPrimBoolean:
2650 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002651 case Primitive::kPrimByte:
2652 case Primitive::kPrimShort:
2653 case Primitive::kPrimInt:
2654 case Primitive::kPrimChar:
2655 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002656 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002657 locations->SetOut(Location::RequiresFpuRegister());
2658 break;
2659
2660 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002661 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002662 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002663 locations->SetOut(Location::RequiresFpuRegister());
2664 break;
2665
Roland Levillaincff13742014-11-17 14:32:17 +00002666 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002667 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002668 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002669 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002670 break;
2671
2672 default:
2673 LOG(FATAL) << "Unexpected type conversion from " << input_type
2674 << " to " << result_type;
2675 };
2676 break;
2677
Roland Levillaindff1f282014-11-05 14:15:05 +00002678 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002679 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002680 case Primitive::kPrimBoolean:
2681 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002682 case Primitive::kPrimByte:
2683 case Primitive::kPrimShort:
2684 case Primitive::kPrimInt:
2685 case Primitive::kPrimChar:
2686 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002687 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002688 locations->SetOut(Location::RequiresFpuRegister());
2689 break;
2690
2691 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002692 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002693 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002694 locations->SetOut(Location::RequiresFpuRegister());
2695 break;
2696
Roland Levillaincff13742014-11-17 14:32:17 +00002697 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002698 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002699 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002700 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002701 break;
2702
2703 default:
2704 LOG(FATAL) << "Unexpected type conversion from " << input_type
2705 << " to " << result_type;
2706 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002707 break;
2708
2709 default:
2710 LOG(FATAL) << "Unexpected type conversion from " << input_type
2711 << " to " << result_type;
2712 }
2713}
2714
2715void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2716 LocationSummary* locations = conversion->GetLocations();
2717 Location out = locations->Out();
2718 Location in = locations->InAt(0);
2719 Primitive::Type result_type = conversion->GetResultType();
2720 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002721 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002722 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002723 case Primitive::kPrimByte:
2724 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002725 case Primitive::kPrimLong:
2726 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002727 case Primitive::kPrimBoolean:
2728 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002729 case Primitive::kPrimShort:
2730 case Primitive::kPrimInt:
2731 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002732 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002733 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002734 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002735 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002736 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002737 Address(CpuRegister(RSP), in.GetStackIndex()));
2738 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002739 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002740 Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain51d3fc42014-11-13 14:11:42 +00002741 }
2742 break;
2743
2744 default:
2745 LOG(FATAL) << "Unexpected type conversion from " << input_type
2746 << " to " << result_type;
2747 }
2748 break;
2749
Roland Levillain01a8d712014-11-14 16:27:39 +00002750 case Primitive::kPrimShort:
2751 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002752 case Primitive::kPrimLong:
2753 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002754 case Primitive::kPrimBoolean:
2755 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002756 case Primitive::kPrimByte:
2757 case Primitive::kPrimInt:
2758 case Primitive::kPrimChar:
2759 // Processing a Dex `int-to-short' instruction.
2760 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002761 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002762 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002763 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002764 Address(CpuRegister(RSP), in.GetStackIndex()));
2765 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002766 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002767 Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain01a8d712014-11-14 16:27:39 +00002768 }
2769 break;
2770
2771 default:
2772 LOG(FATAL) << "Unexpected type conversion from " << input_type
2773 << " to " << result_type;
2774 }
2775 break;
2776
Roland Levillain946e1432014-11-11 17:35:19 +00002777 case Primitive::kPrimInt:
2778 switch (input_type) {
2779 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002780 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002781 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002782 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002783 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002784 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002785 Address(CpuRegister(RSP), in.GetStackIndex()));
2786 } else {
2787 DCHECK(in.IsConstant());
2788 DCHECK(in.GetConstant()->IsLongConstant());
2789 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002790 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002791 }
2792 break;
2793
Roland Levillain3f8f9362014-12-02 17:45:01 +00002794 case Primitive::kPrimFloat: {
2795 // Processing a Dex `float-to-int' instruction.
2796 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2797 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002798 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002799
2800 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002801 // if input >= (float)INT_MAX goto done
2802 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002803 __ j(kAboveEqual, &done);
2804 // if input == NaN goto nan
2805 __ j(kUnordered, &nan);
2806 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002807 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002808 __ jmp(&done);
2809 __ Bind(&nan);
2810 // output = 0
2811 __ xorl(output, output);
2812 __ Bind(&done);
2813 break;
2814 }
2815
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002816 case Primitive::kPrimDouble: {
2817 // Processing a Dex `double-to-int' instruction.
2818 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2819 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002820 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002821
2822 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002823 // if input >= (double)INT_MAX goto done
2824 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002825 __ j(kAboveEqual, &done);
2826 // if input == NaN goto nan
2827 __ j(kUnordered, &nan);
2828 // output = double-to-int-truncate(input)
2829 __ cvttsd2si(output, input);
2830 __ jmp(&done);
2831 __ Bind(&nan);
2832 // output = 0
2833 __ xorl(output, output);
2834 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002835 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002836 }
Roland Levillain946e1432014-11-11 17:35:19 +00002837
2838 default:
2839 LOG(FATAL) << "Unexpected type conversion from " << input_type
2840 << " to " << result_type;
2841 }
2842 break;
2843
Roland Levillaindff1f282014-11-05 14:15:05 +00002844 case Primitive::kPrimLong:
2845 switch (input_type) {
2846 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002847 case Primitive::kPrimBoolean:
2848 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002849 case Primitive::kPrimByte:
2850 case Primitive::kPrimShort:
2851 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002852 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002853 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002854 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002855 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002856 break;
2857
Roland Levillain624279f2014-12-04 11:54:28 +00002858 case Primitive::kPrimFloat: {
2859 // Processing a Dex `float-to-long' instruction.
2860 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2861 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002862 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002863
Mark Mendell92e83bf2015-05-07 11:25:03 -04002864 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002865 // if input >= (float)LONG_MAX goto done
2866 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002867 __ j(kAboveEqual, &done);
2868 // if input == NaN goto nan
2869 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002870 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002871 __ cvttss2si(output, input, true);
2872 __ jmp(&done);
2873 __ Bind(&nan);
2874 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002875 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002876 __ Bind(&done);
2877 break;
2878 }
2879
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002880 case Primitive::kPrimDouble: {
2881 // Processing a Dex `double-to-long' instruction.
2882 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2883 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002884 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002885
Mark Mendell92e83bf2015-05-07 11:25:03 -04002886 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002887 // if input >= (double)LONG_MAX goto done
2888 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002889 __ j(kAboveEqual, &done);
2890 // if input == NaN goto nan
2891 __ j(kUnordered, &nan);
2892 // output = double-to-long-truncate(input)
2893 __ cvttsd2si(output, input, true);
2894 __ jmp(&done);
2895 __ Bind(&nan);
2896 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002897 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002898 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002899 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002900 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002901
2902 default:
2903 LOG(FATAL) << "Unexpected type conversion from " << input_type
2904 << " to " << result_type;
2905 }
2906 break;
2907
Roland Levillain981e4542014-11-14 11:47:14 +00002908 case Primitive::kPrimChar:
2909 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002910 case Primitive::kPrimLong:
2911 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002912 case Primitive::kPrimBoolean:
2913 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002914 case Primitive::kPrimByte:
2915 case Primitive::kPrimShort:
2916 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002917 // Processing a Dex `int-to-char' instruction.
2918 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002919 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002920 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002921 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002922 Address(CpuRegister(RSP), in.GetStackIndex()));
2923 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002924 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002925 Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain981e4542014-11-14 11:47:14 +00002926 }
2927 break;
2928
2929 default:
2930 LOG(FATAL) << "Unexpected type conversion from " << input_type
2931 << " to " << result_type;
2932 }
2933 break;
2934
Roland Levillaindff1f282014-11-05 14:15:05 +00002935 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002936 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002937 case Primitive::kPrimBoolean:
2938 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002939 case Primitive::kPrimByte:
2940 case Primitive::kPrimShort:
2941 case Primitive::kPrimInt:
2942 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002943 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002944 if (in.IsRegister()) {
2945 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2946 } else if (in.IsConstant()) {
2947 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2948 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05002949 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04002950 } else {
2951 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2952 Address(CpuRegister(RSP), in.GetStackIndex()), false);
2953 }
Roland Levillaincff13742014-11-17 14:32:17 +00002954 break;
2955
2956 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002957 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002958 if (in.IsRegister()) {
2959 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2960 } else if (in.IsConstant()) {
2961 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2962 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Pavel Vyssotski4c858cd2016-03-16 13:59:53 +06002963 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04002964 } else {
2965 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2966 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2967 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002968 break;
2969
Roland Levillaincff13742014-11-17 14:32:17 +00002970 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002971 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002972 if (in.IsFpuRegister()) {
2973 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2974 } else if (in.IsConstant()) {
2975 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2976 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05002977 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04002978 } else {
2979 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2980 Address(CpuRegister(RSP), in.GetStackIndex()));
2981 }
Roland Levillaincff13742014-11-17 14:32:17 +00002982 break;
2983
2984 default:
2985 LOG(FATAL) << "Unexpected type conversion from " << input_type
2986 << " to " << result_type;
2987 };
2988 break;
2989
Roland Levillaindff1f282014-11-05 14:15:05 +00002990 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002991 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002992 case Primitive::kPrimBoolean:
2993 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002994 case Primitive::kPrimByte:
2995 case Primitive::kPrimShort:
2996 case Primitive::kPrimInt:
2997 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002998 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002999 if (in.IsRegister()) {
3000 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
3001 } else if (in.IsConstant()) {
3002 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
3003 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003004 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003005 } else {
3006 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
3007 Address(CpuRegister(RSP), in.GetStackIndex()), false);
3008 }
Roland Levillaincff13742014-11-17 14:32:17 +00003009 break;
3010
3011 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003012 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04003013 if (in.IsRegister()) {
3014 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
3015 } else if (in.IsConstant()) {
3016 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
3017 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003018 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003019 } else {
3020 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
3021 Address(CpuRegister(RSP), in.GetStackIndex()), true);
3022 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00003023 break;
3024
Roland Levillaincff13742014-11-17 14:32:17 +00003025 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003026 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04003027 if (in.IsFpuRegister()) {
3028 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3029 } else if (in.IsConstant()) {
3030 float v = in.GetConstant()->AsFloatConstant()->GetValue();
3031 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003032 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003033 } else {
3034 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
3035 Address(CpuRegister(RSP), in.GetStackIndex()));
3036 }
Roland Levillaincff13742014-11-17 14:32:17 +00003037 break;
3038
3039 default:
3040 LOG(FATAL) << "Unexpected type conversion from " << input_type
3041 << " to " << result_type;
3042 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003043 break;
3044
3045 default:
3046 LOG(FATAL) << "Unexpected type conversion from " << input_type
3047 << " to " << result_type;
3048 }
3049}
3050
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003051void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003052 LocationSummary* locations =
3053 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003054 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003055 case Primitive::kPrimInt: {
3056 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003057 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3058 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003059 break;
3060 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003061
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003062 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003063 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05003064 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendellea5af682015-10-22 17:35:49 -04003065 locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05003066 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003067 break;
3068 }
3069
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003070 case Primitive::kPrimDouble:
3071 case Primitive::kPrimFloat: {
3072 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003073 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003074 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003075 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003076 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003077
3078 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003079 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003080 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003081}
3082
3083void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
3084 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003085 Location first = locations->InAt(0);
3086 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003087 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01003088
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003089 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003090 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003091 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003092 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3093 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003094 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3095 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003096 } else {
3097 __ leal(out.AsRegister<CpuRegister>(), Address(
3098 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3099 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003100 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003101 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3102 __ addl(out.AsRegister<CpuRegister>(),
3103 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
3104 } else {
3105 __ leal(out.AsRegister<CpuRegister>(), Address(
3106 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
3107 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003108 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003109 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003110 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003111 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003112 break;
3113 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003114
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003115 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05003116 if (second.IsRegister()) {
3117 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3118 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003119 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3120 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05003121 } else {
3122 __ leaq(out.AsRegister<CpuRegister>(), Address(
3123 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3124 }
3125 } else {
3126 DCHECK(second.IsConstant());
3127 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3128 int32_t int32_value = Low32Bits(value);
3129 DCHECK_EQ(int32_value, value);
3130 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3131 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
3132 } else {
3133 __ leaq(out.AsRegister<CpuRegister>(), Address(
3134 first.AsRegister<CpuRegister>(), int32_value));
3135 }
3136 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003137 break;
3138 }
3139
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003140 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003141 if (second.IsFpuRegister()) {
3142 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3143 } else if (second.IsConstant()) {
3144 __ addss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003145 codegen_->LiteralFloatAddress(
3146 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003147 } else {
3148 DCHECK(second.IsStackSlot());
3149 __ addss(first.AsFpuRegister<XmmRegister>(),
3150 Address(CpuRegister(RSP), second.GetStackIndex()));
3151 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003152 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003153 }
3154
3155 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003156 if (second.IsFpuRegister()) {
3157 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3158 } else if (second.IsConstant()) {
3159 __ addsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003160 codegen_->LiteralDoubleAddress(
3161 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003162 } else {
3163 DCHECK(second.IsDoubleStackSlot());
3164 __ addsd(first.AsFpuRegister<XmmRegister>(),
3165 Address(CpuRegister(RSP), second.GetStackIndex()));
3166 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003167 break;
3168 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003169
3170 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003171 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003172 }
3173}
3174
3175void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003176 LocationSummary* locations =
3177 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003178 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003179 case Primitive::kPrimInt: {
3180 locations->SetInAt(0, Location::RequiresRegister());
3181 locations->SetInAt(1, Location::Any());
3182 locations->SetOut(Location::SameAsFirstInput());
3183 break;
3184 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003185 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003186 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04003187 locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003188 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003189 break;
3190 }
Calin Juravle11351682014-10-23 15:38:15 +01003191 case Primitive::kPrimFloat:
3192 case Primitive::kPrimDouble: {
3193 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003194 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01003195 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003196 break;
Calin Juravle11351682014-10-23 15:38:15 +01003197 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003198 default:
Calin Juravle11351682014-10-23 15:38:15 +01003199 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003200 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003201}
3202
3203void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
3204 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003205 Location first = locations->InAt(0);
3206 Location second = locations->InAt(1);
3207 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003208 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003209 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01003210 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003211 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01003212 } else if (second.IsConstant()) {
3213 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003214 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003215 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003216 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003217 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003218 break;
3219 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003220 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003221 if (second.IsConstant()) {
3222 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3223 DCHECK(IsInt<32>(value));
3224 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
3225 } else {
3226 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
3227 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003228 break;
3229 }
3230
Calin Juravle11351682014-10-23 15:38:15 +01003231 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003232 if (second.IsFpuRegister()) {
3233 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3234 } else if (second.IsConstant()) {
3235 __ subss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003236 codegen_->LiteralFloatAddress(
3237 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003238 } else {
3239 DCHECK(second.IsStackSlot());
3240 __ subss(first.AsFpuRegister<XmmRegister>(),
3241 Address(CpuRegister(RSP), second.GetStackIndex()));
3242 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003243 break;
Calin Juravle11351682014-10-23 15:38:15 +01003244 }
3245
3246 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003247 if (second.IsFpuRegister()) {
3248 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3249 } else if (second.IsConstant()) {
3250 __ subsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003251 codegen_->LiteralDoubleAddress(
3252 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003253 } else {
3254 DCHECK(second.IsDoubleStackSlot());
3255 __ subsd(first.AsFpuRegister<XmmRegister>(),
3256 Address(CpuRegister(RSP), second.GetStackIndex()));
3257 }
Calin Juravle11351682014-10-23 15:38:15 +01003258 break;
3259 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003260
3261 default:
Calin Juravle11351682014-10-23 15:38:15 +01003262 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003263 }
3264}
3265
Calin Juravle34bacdf2014-10-07 20:23:36 +01003266void LocationsBuilderX86_64::VisitMul(HMul* mul) {
3267 LocationSummary* locations =
3268 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3269 switch (mul->GetResultType()) {
3270 case Primitive::kPrimInt: {
3271 locations->SetInAt(0, Location::RequiresRegister());
3272 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003273 if (mul->InputAt(1)->IsIntConstant()) {
3274 // Can use 3 operand multiply.
3275 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3276 } else {
3277 locations->SetOut(Location::SameAsFirstInput());
3278 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003279 break;
3280 }
3281 case Primitive::kPrimLong: {
3282 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003283 locations->SetInAt(1, Location::Any());
3284 if (mul->InputAt(1)->IsLongConstant() &&
3285 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003286 // Can use 3 operand multiply.
3287 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3288 } else {
3289 locations->SetOut(Location::SameAsFirstInput());
3290 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003291 break;
3292 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003293 case Primitive::kPrimFloat:
3294 case Primitive::kPrimDouble: {
3295 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003296 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01003297 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003298 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003299 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003300
3301 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003302 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003303 }
3304}
3305
3306void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
3307 LocationSummary* locations = mul->GetLocations();
3308 Location first = locations->InAt(0);
3309 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003310 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003311 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003312 case Primitive::kPrimInt:
3313 // The constant may have ended up in a register, so test explicitly to avoid
3314 // problems where the output may not be the same as the first operand.
3315 if (mul->InputAt(1)->IsIntConstant()) {
3316 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3317 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
3318 } else if (second.IsRegister()) {
3319 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003320 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003321 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003322 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003323 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00003324 __ imull(first.AsRegister<CpuRegister>(),
3325 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003326 }
3327 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01003328 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003329 // The constant may have ended up in a register, so test explicitly to avoid
3330 // problems where the output may not be the same as the first operand.
3331 if (mul->InputAt(1)->IsLongConstant()) {
3332 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
3333 if (IsInt<32>(value)) {
3334 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
3335 Immediate(static_cast<int32_t>(value)));
3336 } else {
3337 // Have to use the constant area.
3338 DCHECK(first.Equals(out));
3339 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
3340 }
3341 } else if (second.IsRegister()) {
3342 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003343 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003344 } else {
3345 DCHECK(second.IsDoubleStackSlot());
3346 DCHECK(first.Equals(out));
3347 __ imulq(first.AsRegister<CpuRegister>(),
3348 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003349 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003350 break;
3351 }
3352
Calin Juravleb5bfa962014-10-21 18:02:24 +01003353 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003354 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003355 if (second.IsFpuRegister()) {
3356 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3357 } else if (second.IsConstant()) {
3358 __ mulss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003359 codegen_->LiteralFloatAddress(
3360 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003361 } else {
3362 DCHECK(second.IsStackSlot());
3363 __ mulss(first.AsFpuRegister<XmmRegister>(),
3364 Address(CpuRegister(RSP), second.GetStackIndex()));
3365 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003366 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003367 }
3368
3369 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003370 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003371 if (second.IsFpuRegister()) {
3372 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3373 } else if (second.IsConstant()) {
3374 __ mulsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003375 codegen_->LiteralDoubleAddress(
3376 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003377 } else {
3378 DCHECK(second.IsDoubleStackSlot());
3379 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3380 Address(CpuRegister(RSP), second.GetStackIndex()));
3381 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003382 break;
3383 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003384
3385 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003386 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003387 }
3388}
3389
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003390void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
3391 uint32_t stack_adjustment, bool is_float) {
3392 if (source.IsStackSlot()) {
3393 DCHECK(is_float);
3394 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3395 } else if (source.IsDoubleStackSlot()) {
3396 DCHECK(!is_float);
3397 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3398 } else {
3399 // Write the value to the temporary location on the stack and load to FP stack.
3400 if (is_float) {
3401 Location stack_temp = Location::StackSlot(temp_offset);
3402 codegen_->Move(stack_temp, source);
3403 __ flds(Address(CpuRegister(RSP), temp_offset));
3404 } else {
3405 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3406 codegen_->Move(stack_temp, source);
3407 __ fldl(Address(CpuRegister(RSP), temp_offset));
3408 }
3409 }
3410}
3411
3412void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
3413 Primitive::Type type = rem->GetResultType();
3414 bool is_float = type == Primitive::kPrimFloat;
3415 size_t elem_size = Primitive::ComponentSize(type);
3416 LocationSummary* locations = rem->GetLocations();
3417 Location first = locations->InAt(0);
3418 Location second = locations->InAt(1);
3419 Location out = locations->Out();
3420
3421 // Create stack space for 2 elements.
3422 // TODO: enhance register allocator to ask for stack temporaries.
3423 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
3424
3425 // Load the values to the FP stack in reverse order, using temporaries if needed.
3426 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
3427 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
3428
3429 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003430 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003431 __ Bind(&retry);
3432 __ fprem();
3433
3434 // Move FP status to AX.
3435 __ fstsw();
3436
3437 // And see if the argument reduction is complete. This is signaled by the
3438 // C2 FPU flag bit set to 0.
3439 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
3440 __ j(kNotEqual, &retry);
3441
3442 // We have settled on the final value. Retrieve it into an XMM register.
3443 // Store FP top of stack to real stack.
3444 if (is_float) {
3445 __ fsts(Address(CpuRegister(RSP), 0));
3446 } else {
3447 __ fstl(Address(CpuRegister(RSP), 0));
3448 }
3449
3450 // Pop the 2 items from the FP stack.
3451 __ fucompp();
3452
3453 // Load the value from the stack into an XMM register.
3454 DCHECK(out.IsFpuRegister()) << out;
3455 if (is_float) {
3456 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3457 } else {
3458 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3459 }
3460
3461 // And remove the temporary stack space we allocated.
3462 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
3463}
3464
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003465void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3466 DCHECK(instruction->IsDiv() || instruction->IsRem());
3467
3468 LocationSummary* locations = instruction->GetLocations();
3469 Location second = locations->InAt(1);
3470 DCHECK(second.IsConstant());
3471
3472 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3473 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003474 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003475
3476 DCHECK(imm == 1 || imm == -1);
3477
3478 switch (instruction->GetResultType()) {
3479 case Primitive::kPrimInt: {
3480 if (instruction->IsRem()) {
3481 __ xorl(output_register, output_register);
3482 } else {
3483 __ movl(output_register, input_register);
3484 if (imm == -1) {
3485 __ negl(output_register);
3486 }
3487 }
3488 break;
3489 }
3490
3491 case Primitive::kPrimLong: {
3492 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003493 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003494 } else {
3495 __ movq(output_register, input_register);
3496 if (imm == -1) {
3497 __ negq(output_register);
3498 }
3499 }
3500 break;
3501 }
3502
3503 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003504 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003505 }
3506}
3507
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003508void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003509 LocationSummary* locations = instruction->GetLocations();
3510 Location second = locations->InAt(1);
3511
3512 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3513 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3514
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003515 int64_t imm = Int64FromConstant(second.GetConstant());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003516 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3517 uint64_t abs_imm = AbsOrMin(imm);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003518
3519 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3520
3521 if (instruction->GetResultType() == Primitive::kPrimInt) {
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003522 __ leal(tmp, Address(numerator, abs_imm - 1));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003523 __ testl(numerator, numerator);
3524 __ cmov(kGreaterEqual, tmp, numerator);
3525 int shift = CTZ(imm);
3526 __ sarl(tmp, Immediate(shift));
3527
3528 if (imm < 0) {
3529 __ negl(tmp);
3530 }
3531
3532 __ movl(output_register, tmp);
3533 } else {
3534 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3535 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3536
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003537 codegen_->Load64BitValue(rdx, abs_imm - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003538 __ addq(rdx, numerator);
3539 __ testq(numerator, numerator);
3540 __ cmov(kGreaterEqual, rdx, numerator);
3541 int shift = CTZ(imm);
3542 __ sarq(rdx, Immediate(shift));
3543
3544 if (imm < 0) {
3545 __ negq(rdx);
3546 }
3547
3548 __ movq(output_register, rdx);
3549 }
3550}
3551
3552void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3553 DCHECK(instruction->IsDiv() || instruction->IsRem());
3554
3555 LocationSummary* locations = instruction->GetLocations();
3556 Location second = locations->InAt(1);
3557
3558 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3559 : locations->GetTemp(0).AsRegister<CpuRegister>();
3560 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3561 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3562 : locations->Out().AsRegister<CpuRegister>();
3563 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3564
3565 DCHECK_EQ(RAX, eax.AsRegister());
3566 DCHECK_EQ(RDX, edx.AsRegister());
3567 if (instruction->IsDiv()) {
3568 DCHECK_EQ(RAX, out.AsRegister());
3569 } else {
3570 DCHECK_EQ(RDX, out.AsRegister());
3571 }
3572
3573 int64_t magic;
3574 int shift;
3575
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003576 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003577 if (instruction->GetResultType() == Primitive::kPrimInt) {
3578 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3579
3580 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3581
3582 __ movl(numerator, eax);
3583
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003584 __ movl(eax, Immediate(magic));
3585 __ imull(numerator);
3586
3587 if (imm > 0 && magic < 0) {
3588 __ addl(edx, numerator);
3589 } else if (imm < 0 && magic > 0) {
3590 __ subl(edx, numerator);
3591 }
3592
3593 if (shift != 0) {
3594 __ sarl(edx, Immediate(shift));
3595 }
3596
3597 __ movl(eax, edx);
3598 __ shrl(edx, Immediate(31));
3599 __ addl(edx, eax);
3600
3601 if (instruction->IsRem()) {
3602 __ movl(eax, numerator);
3603 __ imull(edx, Immediate(imm));
3604 __ subl(eax, edx);
3605 __ movl(edx, eax);
3606 } else {
3607 __ movl(eax, edx);
3608 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003609 } else {
3610 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3611
3612 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3613
3614 CpuRegister rax = eax;
3615 CpuRegister rdx = edx;
3616
3617 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3618
3619 // Save the numerator.
3620 __ movq(numerator, rax);
3621
3622 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003623 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003624
3625 // RDX:RAX = magic * numerator
3626 __ imulq(numerator);
3627
3628 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003629 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003630 __ addq(rdx, numerator);
3631 } else if (imm < 0 && magic > 0) {
3632 // RDX -= numerator
3633 __ subq(rdx, numerator);
3634 }
3635
3636 // Shift if needed.
3637 if (shift != 0) {
3638 __ sarq(rdx, Immediate(shift));
3639 }
3640
3641 // RDX += 1 if RDX < 0
3642 __ movq(rax, rdx);
3643 __ shrq(rdx, Immediate(63));
3644 __ addq(rdx, rax);
3645
3646 if (instruction->IsRem()) {
3647 __ movq(rax, numerator);
3648
3649 if (IsInt<32>(imm)) {
3650 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3651 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003652 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003653 }
3654
3655 __ subq(rax, rdx);
3656 __ movq(rdx, rax);
3657 } else {
3658 __ movq(rax, rdx);
3659 }
3660 }
3661}
3662
Calin Juravlebacfec32014-11-14 15:54:36 +00003663void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3664 DCHECK(instruction->IsDiv() || instruction->IsRem());
3665 Primitive::Type type = instruction->GetResultType();
3666 DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
3667
3668 bool is_div = instruction->IsDiv();
3669 LocationSummary* locations = instruction->GetLocations();
3670
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003671 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3672 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003673
Roland Levillain271ab9c2014-11-27 15:23:57 +00003674 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003675 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003676
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003677 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003678 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003679
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003680 if (imm == 0) {
3681 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3682 } else if (imm == 1 || imm == -1) {
3683 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003684 } else if (instruction->IsDiv() && IsPowerOfTwo(AbsOrMin(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003685 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003686 } else {
3687 DCHECK(imm <= -2 || imm >= 2);
3688 GenerateDivRemWithAnyConstant(instruction);
3689 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003690 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003691 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003692 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
David Srbecky9cd6d372016-02-09 15:24:47 +00003693 instruction, out.AsRegister(), type, is_div);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003694 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003695
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003696 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3697 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3698 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3699 // so it's safe to just use negl instead of more complex comparisons.
3700 if (type == Primitive::kPrimInt) {
3701 __ cmpl(second_reg, Immediate(-1));
3702 __ j(kEqual, slow_path->GetEntryLabel());
3703 // edx:eax <- sign-extended of eax
3704 __ cdq();
3705 // eax = quotient, edx = remainder
3706 __ idivl(second_reg);
3707 } else {
3708 __ cmpq(second_reg, Immediate(-1));
3709 __ j(kEqual, slow_path->GetEntryLabel());
3710 // rdx:rax <- sign-extended of rax
3711 __ cqo();
3712 // rax = quotient, rdx = remainder
3713 __ idivq(second_reg);
3714 }
3715 __ Bind(slow_path->GetExitLabel());
3716 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003717}
3718
Calin Juravle7c4954d2014-10-28 16:57:40 +00003719void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3720 LocationSummary* locations =
3721 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3722 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003723 case Primitive::kPrimInt:
3724 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003725 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003726 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003727 locations->SetOut(Location::SameAsFirstInput());
3728 // Intel uses edx:eax as the dividend.
3729 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003730 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3731 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3732 // output and request another temp.
3733 if (div->InputAt(1)->IsConstant()) {
3734 locations->AddTemp(Location::RequiresRegister());
3735 }
Calin Juravled0d48522014-11-04 16:40:20 +00003736 break;
3737 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003738
Calin Juravle7c4954d2014-10-28 16:57:40 +00003739 case Primitive::kPrimFloat:
3740 case Primitive::kPrimDouble: {
3741 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003742 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003743 locations->SetOut(Location::SameAsFirstInput());
3744 break;
3745 }
3746
3747 default:
3748 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3749 }
3750}
3751
3752void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3753 LocationSummary* locations = div->GetLocations();
3754 Location first = locations->InAt(0);
3755 Location second = locations->InAt(1);
3756 DCHECK(first.Equals(locations->Out()));
3757
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003758 Primitive::Type type = div->GetResultType();
3759 switch (type) {
3760 case Primitive::kPrimInt:
3761 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003762 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003763 break;
3764 }
3765
Calin Juravle7c4954d2014-10-28 16:57:40 +00003766 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003767 if (second.IsFpuRegister()) {
3768 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3769 } else if (second.IsConstant()) {
3770 __ divss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003771 codegen_->LiteralFloatAddress(
3772 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003773 } else {
3774 DCHECK(second.IsStackSlot());
3775 __ divss(first.AsFpuRegister<XmmRegister>(),
3776 Address(CpuRegister(RSP), second.GetStackIndex()));
3777 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003778 break;
3779 }
3780
3781 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003782 if (second.IsFpuRegister()) {
3783 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3784 } else if (second.IsConstant()) {
3785 __ divsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003786 codegen_->LiteralDoubleAddress(
3787 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003788 } else {
3789 DCHECK(second.IsDoubleStackSlot());
3790 __ divsd(first.AsFpuRegister<XmmRegister>(),
3791 Address(CpuRegister(RSP), second.GetStackIndex()));
3792 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003793 break;
3794 }
3795
3796 default:
3797 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3798 }
3799}
3800
Calin Juravlebacfec32014-11-14 15:54:36 +00003801void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003802 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003803 LocationSummary* locations =
3804 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003805
3806 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003807 case Primitive::kPrimInt:
3808 case Primitive::kPrimLong: {
3809 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003810 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003811 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3812 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003813 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3814 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3815 // output and request another temp.
3816 if (rem->InputAt(1)->IsConstant()) {
3817 locations->AddTemp(Location::RequiresRegister());
3818 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003819 break;
3820 }
3821
3822 case Primitive::kPrimFloat:
3823 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003824 locations->SetInAt(0, Location::Any());
3825 locations->SetInAt(1, Location::Any());
3826 locations->SetOut(Location::RequiresFpuRegister());
3827 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003828 break;
3829 }
3830
3831 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003832 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003833 }
3834}
3835
3836void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3837 Primitive::Type type = rem->GetResultType();
3838 switch (type) {
3839 case Primitive::kPrimInt:
3840 case Primitive::kPrimLong: {
3841 GenerateDivRemIntegral(rem);
3842 break;
3843 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003844 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003845 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003846 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003847 break;
3848 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003849 default:
3850 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3851 }
3852}
3853
Calin Juravled0d48522014-11-04 16:40:20 +00003854void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003855 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003856 locations->SetInAt(0, Location::Any());
Calin Juravled0d48522014-11-04 16:40:20 +00003857}
3858
3859void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003860 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003861 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3862 codegen_->AddSlowPath(slow_path);
3863
3864 LocationSummary* locations = instruction->GetLocations();
3865 Location value = locations->InAt(0);
3866
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003867 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003868 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003869 case Primitive::kPrimByte:
3870 case Primitive::kPrimChar:
3871 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003872 case Primitive::kPrimInt: {
3873 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003874 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003875 __ j(kEqual, slow_path->GetEntryLabel());
3876 } else if (value.IsStackSlot()) {
3877 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3878 __ j(kEqual, slow_path->GetEntryLabel());
3879 } else {
3880 DCHECK(value.IsConstant()) << value;
3881 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01003882 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003883 }
3884 }
3885 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003886 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003887 case Primitive::kPrimLong: {
3888 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003889 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003890 __ j(kEqual, slow_path->GetEntryLabel());
3891 } else if (value.IsDoubleStackSlot()) {
3892 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3893 __ j(kEqual, slow_path->GetEntryLabel());
3894 } else {
3895 DCHECK(value.IsConstant()) << value;
3896 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01003897 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003898 }
3899 }
3900 break;
3901 }
3902 default:
3903 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003904 }
Calin Juravled0d48522014-11-04 16:40:20 +00003905}
3906
Calin Juravle9aec02f2014-11-18 23:06:35 +00003907void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3908 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3909
3910 LocationSummary* locations =
3911 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3912
3913 switch (op->GetResultType()) {
3914 case Primitive::kPrimInt:
3915 case Primitive::kPrimLong: {
3916 locations->SetInAt(0, Location::RequiresRegister());
3917 // The shift count needs to be in CL.
3918 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3919 locations->SetOut(Location::SameAsFirstInput());
3920 break;
3921 }
3922 default:
3923 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3924 }
3925}
3926
3927void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3928 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3929
3930 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003931 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003932 Location second = locations->InAt(1);
3933
3934 switch (op->GetResultType()) {
3935 case Primitive::kPrimInt: {
3936 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003937 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003938 if (op->IsShl()) {
3939 __ shll(first_reg, second_reg);
3940 } else if (op->IsShr()) {
3941 __ sarl(first_reg, second_reg);
3942 } else {
3943 __ shrl(first_reg, second_reg);
3944 }
3945 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003946 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003947 if (op->IsShl()) {
3948 __ shll(first_reg, imm);
3949 } else if (op->IsShr()) {
3950 __ sarl(first_reg, imm);
3951 } else {
3952 __ shrl(first_reg, imm);
3953 }
3954 }
3955 break;
3956 }
3957 case Primitive::kPrimLong: {
3958 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003959 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003960 if (op->IsShl()) {
3961 __ shlq(first_reg, second_reg);
3962 } else if (op->IsShr()) {
3963 __ sarq(first_reg, second_reg);
3964 } else {
3965 __ shrq(first_reg, second_reg);
3966 }
3967 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003968 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003969 if (op->IsShl()) {
3970 __ shlq(first_reg, imm);
3971 } else if (op->IsShr()) {
3972 __ sarq(first_reg, imm);
3973 } else {
3974 __ shrq(first_reg, imm);
3975 }
3976 }
3977 break;
3978 }
3979 default:
3980 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
Vladimir Marko351dddf2015-12-11 16:34:46 +00003981 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003982 }
3983}
3984
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003985void LocationsBuilderX86_64::VisitRor(HRor* ror) {
3986 LocationSummary* locations =
3987 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3988
3989 switch (ror->GetResultType()) {
3990 case Primitive::kPrimInt:
3991 case Primitive::kPrimLong: {
3992 locations->SetInAt(0, Location::RequiresRegister());
3993 // The shift count needs to be in CL (unless it is a constant).
3994 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, ror->InputAt(1)));
3995 locations->SetOut(Location::SameAsFirstInput());
3996 break;
3997 }
3998 default:
3999 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4000 UNREACHABLE();
4001 }
4002}
4003
4004void InstructionCodeGeneratorX86_64::VisitRor(HRor* ror) {
4005 LocationSummary* locations = ror->GetLocations();
4006 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
4007 Location second = locations->InAt(1);
4008
4009 switch (ror->GetResultType()) {
4010 case Primitive::kPrimInt:
4011 if (second.IsRegister()) {
4012 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4013 __ rorl(first_reg, second_reg);
4014 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004015 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004016 __ rorl(first_reg, imm);
4017 }
4018 break;
4019 case Primitive::kPrimLong:
4020 if (second.IsRegister()) {
4021 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4022 __ rorq(first_reg, second_reg);
4023 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004024 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004025 __ rorq(first_reg, imm);
4026 }
4027 break;
4028 default:
4029 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4030 UNREACHABLE();
4031 }
4032}
4033
Calin Juravle9aec02f2014-11-18 23:06:35 +00004034void LocationsBuilderX86_64::VisitShl(HShl* shl) {
4035 HandleShift(shl);
4036}
4037
4038void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
4039 HandleShift(shl);
4040}
4041
4042void LocationsBuilderX86_64::VisitShr(HShr* shr) {
4043 HandleShift(shr);
4044}
4045
4046void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
4047 HandleShift(shr);
4048}
4049
4050void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
4051 HandleShift(ushr);
4052}
4053
4054void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
4055 HandleShift(ushr);
4056}
4057
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004058void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004059 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004060 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004061 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00004062 if (instruction->IsStringAlloc()) {
4063 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4064 } else {
4065 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00004066 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004067 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004068}
4069
4070void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004071 // Note: if heap poisoning is enabled, the entry point takes cares
4072 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00004073 if (instruction->IsStringAlloc()) {
4074 // String is allocated through StringFactory. Call NewEmptyString entry point.
4075 CpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Andreas Gampe542451c2016-07-26 09:02:02 -07004076 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64PointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00004077 __ gs()->movq(temp, Address::Absolute(QUICK_ENTRY_POINT(pNewEmptyString), /* no_rip */ true));
4078 __ call(Address(temp, code_offset.SizeValue()));
4079 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4080 } else {
Serban Constantinescuba45db02016-07-12 22:53:02 +01004081 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00004082 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00004083 DCHECK(!codegen_->IsLeafMethod());
4084 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004085}
4086
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004087void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
4088 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004089 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004090 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004091 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004092 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4093 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004094}
4095
4096void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004097 // Note: if heap poisoning is enabled, the entry point takes cares
4098 // of poisoning the reference.
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004099 codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
4100 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004101 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004102}
4103
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004104void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004105 LocationSummary* locations =
4106 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004107 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4108 if (location.IsStackSlot()) {
4109 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4110 } else if (location.IsDoubleStackSlot()) {
4111 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4112 }
4113 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004114}
4115
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004116void InstructionCodeGeneratorX86_64::VisitParameterValue(
4117 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004118 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004119}
4120
4121void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
4122 LocationSummary* locations =
4123 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4124 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4125}
4126
4127void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
4128 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4129 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004130}
4131
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004132void LocationsBuilderX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4133 LocationSummary* locations =
4134 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4135 locations->SetInAt(0, Location::RequiresRegister());
4136 locations->SetOut(Location::RequiresRegister());
4137}
4138
4139void InstructionCodeGeneratorX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4140 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00004141 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004142 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004143 instruction->GetIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004144 __ movq(locations->Out().AsRegister<CpuRegister>(),
4145 Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004146 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004147 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00004148 instruction->GetIndex(), kX86_64PointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00004149 __ movq(locations->Out().AsRegister<CpuRegister>(),
4150 Address(locations->InAt(0).AsRegister<CpuRegister>(),
4151 mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004152 __ movq(locations->Out().AsRegister<CpuRegister>(),
4153 Address(locations->Out().AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004154 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004155}
4156
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004157void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004158 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004159 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004160 locations->SetInAt(0, Location::RequiresRegister());
4161 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004162}
4163
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004164void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
4165 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004166 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4167 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004168 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004169 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004170 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004171 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004172 break;
4173
4174 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004175 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004176 break;
4177
4178 default:
4179 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4180 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004181}
4182
David Brazdil66d126e2015-04-03 16:02:44 +01004183void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
4184 LocationSummary* locations =
4185 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4186 locations->SetInAt(0, Location::RequiresRegister());
4187 locations->SetOut(Location::SameAsFirstInput());
4188}
4189
4190void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004191 LocationSummary* locations = bool_not->GetLocations();
4192 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4193 locations->Out().AsRegister<CpuRegister>().AsRegister());
4194 Location out = locations->Out();
4195 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
4196}
4197
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004198void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004199 LocationSummary* locations =
4200 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01004201 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004202 locations->SetInAt(i, Location::Any());
4203 }
4204 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004205}
4206
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004207void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004208 LOG(FATAL) << "Unimplemented";
4209}
4210
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004211void CodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
Calin Juravle52c48962014-12-16 17:02:57 +00004212 /*
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004213 * According to the JSR-133 Cookbook, for x86-64 only StoreLoad/AnyAny barriers need memory fence.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004214 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86-64 memory model.
Calin Juravle52c48962014-12-16 17:02:57 +00004215 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
4216 */
4217 switch (kind) {
4218 case MemBarrierKind::kAnyAny: {
Mark P Mendell17077d82015-12-16 19:15:59 +00004219 MemoryFence();
Calin Juravle52c48962014-12-16 17:02:57 +00004220 break;
4221 }
4222 case MemBarrierKind::kAnyStore:
4223 case MemBarrierKind::kLoadAny:
4224 case MemBarrierKind::kStoreStore: {
4225 // nop
4226 break;
4227 }
Mark Mendell7aa04a12016-01-27 22:39:07 -05004228 case MemBarrierKind::kNTStoreStore:
4229 // Non-Temporal Store/Store needs an explicit fence.
4230 MemoryFence(/* non-temporal */ true);
4231 break;
Calin Juravle52c48962014-12-16 17:02:57 +00004232 }
4233}
4234
4235void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
4236 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4237
Roland Levillain0d5a2812015-11-13 10:07:31 +00004238 bool object_field_get_with_read_barrier =
4239 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004240 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004241 new (GetGraph()->GetArena()) LocationSummary(instruction,
4242 object_field_get_with_read_barrier ?
4243 LocationSummary::kCallOnSlowPath :
4244 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004245 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004246 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004247 }
Calin Juravle52c48962014-12-16 17:02:57 +00004248 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004249 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4250 locations->SetOut(Location::RequiresFpuRegister());
4251 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004252 // The output overlaps for an object field get when read barriers
4253 // are enabled: we do not want the move to overwrite the object's
4254 // location, as we need it to emit the read barrier.
4255 locations->SetOut(
4256 Location::RequiresRegister(),
4257 object_field_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004258 }
Calin Juravle52c48962014-12-16 17:02:57 +00004259}
4260
4261void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
4262 const FieldInfo& field_info) {
4263 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4264
4265 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004266 Location base_loc = locations->InAt(0);
4267 CpuRegister base = base_loc.AsRegister<CpuRegister>();
Calin Juravle52c48962014-12-16 17:02:57 +00004268 Location out = locations->Out();
4269 bool is_volatile = field_info.IsVolatile();
4270 Primitive::Type field_type = field_info.GetFieldType();
4271 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4272
4273 switch (field_type) {
4274 case Primitive::kPrimBoolean: {
4275 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4276 break;
4277 }
4278
4279 case Primitive::kPrimByte: {
4280 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4281 break;
4282 }
4283
4284 case Primitive::kPrimShort: {
4285 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
4286 break;
4287 }
4288
4289 case Primitive::kPrimChar: {
4290 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
4291 break;
4292 }
4293
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004294 case Primitive::kPrimInt: {
Calin Juravle52c48962014-12-16 17:02:57 +00004295 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4296 break;
4297 }
4298
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004299 case Primitive::kPrimNot: {
4300 // /* HeapReference<Object> */ out = *(base + offset)
4301 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004302 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01004303 // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004304 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00004305 instruction, out, base, offset, /* needs_null_check */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004306 if (is_volatile) {
4307 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4308 }
4309 } else {
4310 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4311 codegen_->MaybeRecordImplicitNullCheck(instruction);
4312 if (is_volatile) {
4313 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4314 }
4315 // If read barriers are enabled, emit read barriers other than
4316 // Baker's using a slow path (and also unpoison the loaded
4317 // reference, if heap poisoning is enabled).
4318 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4319 }
4320 break;
4321 }
4322
Calin Juravle52c48962014-12-16 17:02:57 +00004323 case Primitive::kPrimLong: {
4324 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
4325 break;
4326 }
4327
4328 case Primitive::kPrimFloat: {
4329 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4330 break;
4331 }
4332
4333 case Primitive::kPrimDouble: {
4334 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4335 break;
4336 }
4337
4338 case Primitive::kPrimVoid:
4339 LOG(FATAL) << "Unreachable type " << field_type;
4340 UNREACHABLE();
4341 }
4342
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004343 if (field_type == Primitive::kPrimNot) {
4344 // Potential implicit null checks, in the case of reference
4345 // fields, are handled in the previous switch statement.
4346 } else {
4347 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004348 }
Roland Levillain4d027112015-07-01 15:41:14 +01004349
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004350 if (is_volatile) {
4351 if (field_type == Primitive::kPrimNot) {
4352 // Memory barriers, in the case of references, are also handled
4353 // in the previous switch statement.
4354 } else {
4355 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4356 }
Roland Levillain4d027112015-07-01 15:41:14 +01004357 }
Calin Juravle52c48962014-12-16 17:02:57 +00004358}
4359
4360void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
4361 const FieldInfo& field_info) {
4362 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4363
4364 LocationSummary* locations =
4365 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01004366 Primitive::Type field_type = field_info.GetFieldType();
Mark Mendellea5af682015-10-22 17:35:49 -04004367 bool is_volatile = field_info.IsVolatile();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004368 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01004369 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004370
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004371 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004372 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
Mark Mendellea5af682015-10-22 17:35:49 -04004373 if (is_volatile) {
4374 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4375 locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
4376 } else {
4377 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
4378 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004379 } else {
Mark Mendellea5af682015-10-22 17:35:49 -04004380 if (is_volatile) {
4381 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4382 locations->SetInAt(1, Location::RegisterOrInt32Constant(instruction->InputAt(1)));
4383 } else {
4384 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4385 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004386 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004387 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004388 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01004389 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004390 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01004391 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4392 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004393 locations->AddTemp(Location::RequiresRegister());
4394 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004395}
4396
Calin Juravle52c48962014-12-16 17:02:57 +00004397void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004398 const FieldInfo& field_info,
4399 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004400 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4401
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004402 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004403 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
4404 Location value = locations->InAt(1);
4405 bool is_volatile = field_info.IsVolatile();
4406 Primitive::Type field_type = field_info.GetFieldType();
4407 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4408
4409 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004410 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00004411 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004412
Mark Mendellea5af682015-10-22 17:35:49 -04004413 bool maybe_record_implicit_null_check_done = false;
4414
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004415 switch (field_type) {
4416 case Primitive::kPrimBoolean:
4417 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04004418 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004419 int8_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004420 __ movb(Address(base, offset), Immediate(v));
4421 } else {
4422 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
4423 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004424 break;
4425 }
4426
4427 case Primitive::kPrimShort:
4428 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04004429 if (value.IsConstant()) {
Mark Mendellea5af682015-10-22 17:35:49 -04004430 int16_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Mark Mendell40741f32015-04-20 22:10:34 -04004431 __ movw(Address(base, offset), Immediate(v));
4432 } else {
4433 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
4434 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004435 break;
4436 }
4437
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004438 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004439 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04004440 if (value.IsConstant()) {
4441 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004442 // `field_type == Primitive::kPrimNot` implies `v == 0`.
4443 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
4444 // Note: if heap poisoning is enabled, no need to poison
4445 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01004446 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04004447 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01004448 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4449 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4450 __ movl(temp, value.AsRegister<CpuRegister>());
4451 __ PoisonHeapReference(temp);
4452 __ movl(Address(base, offset), temp);
4453 } else {
4454 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
4455 }
Mark Mendell40741f32015-04-20 22:10:34 -04004456 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004457 break;
4458 }
4459
4460 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04004461 if (value.IsConstant()) {
4462 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004463 codegen_->MoveInt64ToAddress(Address(base, offset),
4464 Address(base, offset + sizeof(int32_t)),
4465 v,
4466 instruction);
4467 maybe_record_implicit_null_check_done = true;
Mark Mendell40741f32015-04-20 22:10:34 -04004468 } else {
4469 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
4470 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004471 break;
4472 }
4473
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004474 case Primitive::kPrimFloat: {
Mark Mendellea5af682015-10-22 17:35:49 -04004475 if (value.IsConstant()) {
4476 int32_t v =
4477 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4478 __ movl(Address(base, offset), Immediate(v));
4479 } else {
4480 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4481 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004482 break;
4483 }
4484
4485 case Primitive::kPrimDouble: {
Mark Mendellea5af682015-10-22 17:35:49 -04004486 if (value.IsConstant()) {
4487 int64_t v =
4488 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4489 codegen_->MoveInt64ToAddress(Address(base, offset),
4490 Address(base, offset + sizeof(int32_t)),
4491 v,
4492 instruction);
4493 maybe_record_implicit_null_check_done = true;
4494 } else {
4495 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4496 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004497 break;
4498 }
4499
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004500 case Primitive::kPrimVoid:
4501 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004502 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004503 }
Calin Juravle52c48962014-12-16 17:02:57 +00004504
Mark Mendellea5af682015-10-22 17:35:49 -04004505 if (!maybe_record_implicit_null_check_done) {
4506 codegen_->MaybeRecordImplicitNullCheck(instruction);
4507 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004508
4509 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4510 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4511 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004512 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004513 }
4514
Calin Juravle52c48962014-12-16 17:02:57 +00004515 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004516 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00004517 }
4518}
4519
4520void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4521 HandleFieldSet(instruction, instruction->GetFieldInfo());
4522}
4523
4524void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004525 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004526}
4527
4528void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004529 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004530}
4531
4532void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004533 HandleFieldGet(instruction, instruction->GetFieldInfo());
4534}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004535
Calin Juravle52c48962014-12-16 17:02:57 +00004536void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4537 HandleFieldGet(instruction);
4538}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004539
Calin Juravle52c48962014-12-16 17:02:57 +00004540void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4541 HandleFieldGet(instruction, instruction->GetFieldInfo());
4542}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004543
Calin Juravle52c48962014-12-16 17:02:57 +00004544void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4545 HandleFieldSet(instruction, instruction->GetFieldInfo());
4546}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004547
Calin Juravle52c48962014-12-16 17:02:57 +00004548void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004549 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004550}
4551
Calin Juravlee460d1d2015-09-29 04:52:17 +01004552void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
4553 HUnresolvedInstanceFieldGet* instruction) {
4554 FieldAccessCallingConventionX86_64 calling_convention;
4555 codegen_->CreateUnresolvedFieldLocationSummary(
4556 instruction, instruction->GetFieldType(), calling_convention);
4557}
4558
4559void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
4560 HUnresolvedInstanceFieldGet* instruction) {
4561 FieldAccessCallingConventionX86_64 calling_convention;
4562 codegen_->GenerateUnresolvedFieldAccess(instruction,
4563 instruction->GetFieldType(),
4564 instruction->GetFieldIndex(),
4565 instruction->GetDexPc(),
4566 calling_convention);
4567}
4568
4569void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
4570 HUnresolvedInstanceFieldSet* instruction) {
4571 FieldAccessCallingConventionX86_64 calling_convention;
4572 codegen_->CreateUnresolvedFieldLocationSummary(
4573 instruction, instruction->GetFieldType(), calling_convention);
4574}
4575
4576void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
4577 HUnresolvedInstanceFieldSet* instruction) {
4578 FieldAccessCallingConventionX86_64 calling_convention;
4579 codegen_->GenerateUnresolvedFieldAccess(instruction,
4580 instruction->GetFieldType(),
4581 instruction->GetFieldIndex(),
4582 instruction->GetDexPc(),
4583 calling_convention);
4584}
4585
4586void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
4587 HUnresolvedStaticFieldGet* instruction) {
4588 FieldAccessCallingConventionX86_64 calling_convention;
4589 codegen_->CreateUnresolvedFieldLocationSummary(
4590 instruction, instruction->GetFieldType(), calling_convention);
4591}
4592
4593void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
4594 HUnresolvedStaticFieldGet* instruction) {
4595 FieldAccessCallingConventionX86_64 calling_convention;
4596 codegen_->GenerateUnresolvedFieldAccess(instruction,
4597 instruction->GetFieldType(),
4598 instruction->GetFieldIndex(),
4599 instruction->GetDexPc(),
4600 calling_convention);
4601}
4602
4603void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
4604 HUnresolvedStaticFieldSet* instruction) {
4605 FieldAccessCallingConventionX86_64 calling_convention;
4606 codegen_->CreateUnresolvedFieldLocationSummary(
4607 instruction, instruction->GetFieldType(), calling_convention);
4608}
4609
4610void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
4611 HUnresolvedStaticFieldSet* instruction) {
4612 FieldAccessCallingConventionX86_64 calling_convention;
4613 codegen_->GenerateUnresolvedFieldAccess(instruction,
4614 instruction->GetFieldType(),
4615 instruction->GetFieldIndex(),
4616 instruction->GetDexPc(),
4617 calling_convention);
4618}
4619
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004620void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004621 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4622 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
4623 ? Location::RequiresRegister()
4624 : Location::Any();
4625 locations->SetInAt(0, loc);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004626}
4627
Calin Juravle2ae48182016-03-16 14:05:09 +00004628void CodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
4629 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004630 return;
4631 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004632 LocationSummary* locations = instruction->GetLocations();
4633 Location obj = locations->InAt(0);
4634
4635 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
Calin Juravle2ae48182016-03-16 14:05:09 +00004636 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004637}
4638
Calin Juravle2ae48182016-03-16 14:05:09 +00004639void CodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004640 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004641 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004642
4643 LocationSummary* locations = instruction->GetLocations();
4644 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004645
4646 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004647 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004648 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004649 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004650 } else {
4651 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004652 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004653 __ jmp(slow_path->GetEntryLabel());
4654 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004655 }
4656 __ j(kEqual, slow_path->GetEntryLabel());
4657}
4658
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004659void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004660 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004661}
4662
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004663void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004664 bool object_array_get_with_read_barrier =
4665 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004666 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004667 new (GetGraph()->GetArena()) LocationSummary(instruction,
4668 object_array_get_with_read_barrier ?
4669 LocationSummary::kCallOnSlowPath :
4670 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004671 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004672 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004673 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004674 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004675 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004676 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4677 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4678 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004679 // The output overlaps for an object array get when read barriers
4680 // are enabled: we do not want the move to overwrite the array's
4681 // location, as we need it to emit the read barrier.
4682 locations->SetOut(
4683 Location::RequiresRegister(),
4684 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004685 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004686}
4687
4688void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4689 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004690 Location obj_loc = locations->InAt(0);
4691 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004692 Location index = locations->InAt(1);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004693 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004694 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004695
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004696 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004697 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004698 case Primitive::kPrimBoolean: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004699 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004700 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004701 break;
4702 }
4703
4704 case Primitive::kPrimByte: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004705 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004706 __ movsxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004707 break;
4708 }
4709
4710 case Primitive::kPrimShort: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004711 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004712 __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004713 break;
4714 }
4715
4716 case Primitive::kPrimChar: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004717 CpuRegister out = out_loc.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07004718 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
4719 // Branch cases into compressed and uncompressed for each index's type.
4720 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
4721 NearLabel done, not_compressed;
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004722 __ testl(Address(obj, count_offset), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07004723 codegen_->MaybeRecordImplicitNullCheck(instruction);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004724 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4725 "Expecting 0=compressed, 1=uncompressed");
4726 __ j(kNotZero, &not_compressed);
jessicahandojo4877b792016-09-08 19:49:13 -07004727 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
4728 __ jmp(&done);
4729 __ Bind(&not_compressed);
4730 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
4731 __ Bind(&done);
4732 } else {
4733 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
4734 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004735 break;
4736 }
4737
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004738 case Primitive::kPrimInt: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004739 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004740 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004741 break;
4742 }
4743
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004744 case Primitive::kPrimNot: {
4745 static_assert(
4746 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4747 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004748 // /* HeapReference<Object> */ out =
4749 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4750 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004751 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01004752 // CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004753 codegen_->GenerateArrayLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00004754 instruction, out_loc, obj, data_offset, index, /* needs_null_check */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004755 } else {
4756 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004757 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
4758 codegen_->MaybeRecordImplicitNullCheck(instruction);
4759 // If read barriers are enabled, emit read barriers other than
4760 // Baker's using a slow path (and also unpoison the loaded
4761 // reference, if heap poisoning is enabled).
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004762 if (index.IsConstant()) {
4763 uint32_t offset =
4764 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004765 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4766 } else {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004767 codegen_->MaybeGenerateReadBarrierSlow(
4768 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4769 }
4770 }
4771 break;
4772 }
4773
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004774 case Primitive::kPrimLong: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004775 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004776 __ movq(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004777 break;
4778 }
4779
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004780 case Primitive::kPrimFloat: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004781 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004782 __ movss(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004783 break;
4784 }
4785
4786 case Primitive::kPrimDouble: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004787 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004788 __ movsd(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004789 break;
4790 }
4791
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004792 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004793 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004794 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004795 }
Roland Levillain4d027112015-07-01 15:41:14 +01004796
4797 if (type == Primitive::kPrimNot) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004798 // Potential implicit null checks, in the case of reference
4799 // arrays, are handled in the previous switch statement.
4800 } else {
4801 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004802 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004803}
4804
4805void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004806 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004807
4808 bool needs_write_barrier =
4809 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004810 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004811
Nicolas Geoffray39468442014-09-02 15:17:15 +01004812 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004813 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01004814 may_need_runtime_call_for_type_check ?
Roland Levillain0d5a2812015-11-13 10:07:31 +00004815 LocationSummary::kCallOnSlowPath :
4816 LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004817
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004818 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04004819 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4820 if (Primitive::IsFloatingPointType(value_type)) {
4821 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004822 } else {
4823 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4824 }
4825
4826 if (needs_write_barrier) {
4827 // Temporary registers for the write barrier.
Roland Levillain16d9f942016-08-25 17:27:56 +01004828 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004829 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004830 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004831}
4832
4833void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4834 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004835 Location array_loc = locations->InAt(0);
4836 CpuRegister array = array_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004837 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004838 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004839 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004840 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004841 bool needs_write_barrier =
4842 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004843 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4844 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4845 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004846
4847 switch (value_type) {
4848 case Primitive::kPrimBoolean:
4849 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004850 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004851 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_1, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004852 if (value.IsRegister()) {
4853 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004854 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004855 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004856 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004857 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004858 break;
4859 }
4860
4861 case Primitive::kPrimShort:
4862 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004863 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004864 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_2, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004865 if (value.IsRegister()) {
4866 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004867 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004868 DCHECK(value.IsConstant()) << value;
4869 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004870 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004871 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004872 break;
4873 }
4874
4875 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004876 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004877 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00004878
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004879 if (!value.IsRegister()) {
4880 // Just setting null.
4881 DCHECK(instruction->InputAt(2)->IsNullConstant());
4882 DCHECK(value.IsConstant()) << value;
4883 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004884 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004885 DCHECK(!needs_write_barrier);
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004886 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004887 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004888 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004889
4890 DCHECK(needs_write_barrier);
4891 CpuRegister register_value = value.AsRegister<CpuRegister>();
Roland Levillain16d9f942016-08-25 17:27:56 +01004892 // We cannot use a NearLabel for `done`, as its range may be too
4893 // short when Baker read barriers are enabled.
4894 Label done;
4895 NearLabel not_null, do_put;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004896 SlowPathCode* slow_path = nullptr;
Roland Levillain16d9f942016-08-25 17:27:56 +01004897 Location temp_loc = locations->GetTemp(0);
4898 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004899 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004900 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4901 codegen_->AddSlowPath(slow_path);
4902 if (instruction->GetValueCanBeNull()) {
4903 __ testl(register_value, register_value);
4904 __ j(kNotEqual, &not_null);
4905 __ movl(address, Immediate(0));
4906 codegen_->MaybeRecordImplicitNullCheck(instruction);
4907 __ jmp(&done);
4908 __ Bind(&not_null);
4909 }
4910
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004911 // Note that when Baker read barriers are enabled, the type
4912 // checks are performed without read barriers. This is fine,
4913 // even in the case where a class object is in the from-space
4914 // after the flip, as a comparison involving such a type would
4915 // not produce a false positive; it may of course produce a
4916 // false negative, in which case we would take the ArraySet
4917 // slow path.
Roland Levillain16d9f942016-08-25 17:27:56 +01004918
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004919 // /* HeapReference<Class> */ temp = array->klass_
4920 __ movl(temp, Address(array, class_offset));
4921 codegen_->MaybeRecordImplicitNullCheck(instruction);
4922 __ MaybeUnpoisonHeapReference(temp);
Roland Levillain16d9f942016-08-25 17:27:56 +01004923
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004924 // /* HeapReference<Class> */ temp = temp->component_type_
4925 __ movl(temp, Address(temp, component_offset));
4926 // If heap poisoning is enabled, no need to unpoison `temp`
4927 // nor the object reference in `register_value->klass`, as
4928 // we are comparing two poisoned references.
4929 __ cmpl(temp, Address(register_value, class_offset));
Roland Levillain16d9f942016-08-25 17:27:56 +01004930
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004931 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4932 __ j(kEqual, &do_put);
4933 // If heap poisoning is enabled, the `temp` reference has
4934 // not been unpoisoned yet; unpoison it now.
Roland Levillain0d5a2812015-11-13 10:07:31 +00004935 __ MaybeUnpoisonHeapReference(temp);
4936
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004937 // If heap poisoning is enabled, no need to unpoison the
4938 // heap reference loaded below, as it is only used for a
4939 // comparison with null.
4940 __ cmpl(Address(temp, super_offset), Immediate(0));
4941 __ j(kNotEqual, slow_path->GetEntryLabel());
4942 __ Bind(&do_put);
4943 } else {
4944 __ j(kNotEqual, slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004945 }
4946 }
4947
4948 if (kPoisonHeapReferences) {
4949 __ movl(temp, register_value);
4950 __ PoisonHeapReference(temp);
4951 __ movl(address, temp);
4952 } else {
4953 __ movl(address, register_value);
4954 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004955 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004956 codegen_->MaybeRecordImplicitNullCheck(instruction);
4957 }
4958
4959 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4960 codegen_->MarkGCCard(
4961 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4962 __ Bind(&done);
4963
4964 if (slow_path != nullptr) {
4965 __ Bind(slow_path->GetExitLabel());
4966 }
4967
4968 break;
4969 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00004970
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004971 case Primitive::kPrimInt: {
4972 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004973 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004974 if (value.IsRegister()) {
4975 __ movl(address, value.AsRegister<CpuRegister>());
4976 } else {
4977 DCHECK(value.IsConstant()) << value;
4978 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4979 __ movl(address, Immediate(v));
4980 }
4981 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004982 break;
4983 }
4984
4985 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004986 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004987 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004988 if (value.IsRegister()) {
4989 __ movq(address, value.AsRegister<CpuRegister>());
Mark Mendellea5af682015-10-22 17:35:49 -04004990 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004991 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004992 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004993 Address address_high =
4994 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04004995 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004996 }
4997 break;
4998 }
4999
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005000 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005001 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005002 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005003 if (value.IsFpuRegister()) {
5004 __ movss(address, value.AsFpuRegister<XmmRegister>());
5005 } else {
5006 DCHECK(value.IsConstant());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005007 int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
Mark Mendellea5af682015-10-22 17:35:49 -04005008 __ movl(address, Immediate(v));
5009 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005010 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005011 break;
5012 }
5013
5014 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005015 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005016 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005017 if (value.IsFpuRegister()) {
5018 __ movsd(address, value.AsFpuRegister<XmmRegister>());
5019 codegen_->MaybeRecordImplicitNullCheck(instruction);
5020 } else {
5021 int64_t v =
5022 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005023 Address address_high =
5024 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04005025 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
5026 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005027 break;
5028 }
5029
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005030 case Primitive::kPrimVoid:
5031 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07005032 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005033 }
5034}
5035
5036void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005037 LocationSummary* locations =
5038 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005039 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellee8d9712016-07-12 11:13:15 -04005040 if (!instruction->IsEmittedAtUseSite()) {
5041 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5042 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005043}
5044
5045void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
Mark Mendellee8d9712016-07-12 11:13:15 -04005046 if (instruction->IsEmittedAtUseSite()) {
5047 return;
5048 }
5049
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005050 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01005051 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005052 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
5053 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005054 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00005055 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo4877b792016-09-08 19:49:13 -07005056 // Mask out most significant bit in case the array is String's array of char.
5057 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005058 __ shrl(out, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005059 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005060}
5061
5062void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005063 RegisterSet caller_saves = RegisterSet::Empty();
5064 InvokeRuntimeCallingConvention calling_convention;
5065 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5066 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5067 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Mark Mendellf60c90b2015-03-04 15:12:59 -05005068 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendellee8d9712016-07-12 11:13:15 -04005069 HInstruction* length = instruction->InputAt(1);
5070 if (!length->IsEmittedAtUseSite()) {
5071 locations->SetInAt(1, Location::RegisterOrConstant(length));
5072 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005073}
5074
5075void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
5076 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05005077 Location index_loc = locations->InAt(0);
5078 Location length_loc = locations->InAt(1);
Mark Mendellee8d9712016-07-12 11:13:15 -04005079 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005080
Mark Mendell99dbd682015-04-22 16:18:52 -04005081 if (length_loc.IsConstant()) {
5082 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
5083 if (index_loc.IsConstant()) {
5084 // BCE will remove the bounds check if we are guarenteed to pass.
5085 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5086 if (index < 0 || index >= length) {
5087 codegen_->AddSlowPath(slow_path);
5088 __ jmp(slow_path->GetEntryLabel());
5089 } else {
5090 // Some optimization after BCE may have generated this, and we should not
5091 // generate a bounds check if it is a valid range.
5092 }
5093 return;
5094 }
5095
5096 // We have to reverse the jump condition because the length is the constant.
5097 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
5098 __ cmpl(index_reg, Immediate(length));
5099 codegen_->AddSlowPath(slow_path);
5100 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005101 } else {
Mark Mendellee8d9712016-07-12 11:13:15 -04005102 HInstruction* array_length = instruction->InputAt(1);
5103 if (array_length->IsEmittedAtUseSite()) {
5104 // Address the length field in the array.
5105 DCHECK(array_length->IsArrayLength());
5106 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
5107 Location array_loc = array_length->GetLocations()->InAt(0);
5108 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
jessicahandojo4877b792016-09-08 19:49:13 -07005109 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005110 // TODO: if index_loc.IsConstant(), compare twice the index (to compensate for
5111 // the string compression flag) with the in-memory length and avoid the temporary.
jessicahandojo4877b792016-09-08 19:49:13 -07005112 CpuRegister length_reg = CpuRegister(TMP);
5113 __ movl(length_reg, array_len);
5114 codegen_->MaybeRecordImplicitNullCheck(array_length);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005115 __ shrl(length_reg, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005116 codegen_->GenerateIntCompare(length_reg, index_loc);
Mark Mendellee8d9712016-07-12 11:13:15 -04005117 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07005118 // Checking the bound for general case:
5119 // Array of char or String's array when the compression feature off.
5120 if (index_loc.IsConstant()) {
5121 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5122 __ cmpl(array_len, Immediate(value));
5123 } else {
5124 __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
5125 }
5126 codegen_->MaybeRecordImplicitNullCheck(array_length);
Mark Mendellee8d9712016-07-12 11:13:15 -04005127 }
Mark Mendell99dbd682015-04-22 16:18:52 -04005128 } else {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005129 codegen_->GenerateIntCompare(length_loc, index_loc);
Mark Mendell99dbd682015-04-22 16:18:52 -04005130 }
5131 codegen_->AddSlowPath(slow_path);
5132 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005133 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005134}
5135
5136void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
5137 CpuRegister card,
5138 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005139 CpuRegister value,
5140 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04005141 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005142 if (value_can_be_null) {
5143 __ testl(value, value);
5144 __ j(kEqual, &is_null);
5145 }
Andreas Gampe542451c2016-07-26 09:02:02 -07005146 __ gs()->movq(card, Address::Absolute(Thread::CardTableOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005147 /* no_rip */ true));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005148 __ movq(temp, object);
5149 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01005150 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005151 if (value_can_be_null) {
5152 __ Bind(&is_null);
5153 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005154}
5155
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005156void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005157 LOG(FATAL) << "Unimplemented";
5158}
5159
5160void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005161 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5162}
5163
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005164void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01005165 LocationSummary* locations =
5166 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01005167 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005168}
5169
5170void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005171 HBasicBlock* block = instruction->GetBlock();
5172 if (block->GetLoopInformation() != nullptr) {
5173 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5174 // The back edge will generate the suspend check.
5175 return;
5176 }
5177 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5178 // The goto will generate the suspend check.
5179 return;
5180 }
5181 GenerateSuspendCheck(instruction, nullptr);
5182}
5183
5184void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
5185 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005186 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005187 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
5188 if (slow_path == nullptr) {
5189 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
5190 instruction->SetSlowPath(slow_path);
5191 codegen_->AddSlowPath(slow_path);
5192 if (successor != nullptr) {
5193 DCHECK(successor->IsLoopHeader());
5194 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5195 }
5196 } else {
5197 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5198 }
5199
Andreas Gampe542451c2016-07-26 09:02:02 -07005200 __ gs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005201 /* no_rip */ true),
5202 Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005203 if (successor == nullptr) {
5204 __ j(kNotEqual, slow_path->GetEntryLabel());
5205 __ Bind(slow_path->GetReturnLabel());
5206 } else {
5207 __ j(kEqual, codegen_->GetLabelOf(successor));
5208 __ jmp(slow_path->GetEntryLabel());
5209 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005210}
5211
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005212X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
5213 return codegen_->GetAssembler();
5214}
5215
5216void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005217 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005218 Location source = move->GetSource();
5219 Location destination = move->GetDestination();
5220
5221 if (source.IsRegister()) {
5222 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005223 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005224 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005225 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005226 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005227 } else {
5228 DCHECK(destination.IsDoubleStackSlot());
5229 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005230 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005231 }
5232 } else if (source.IsStackSlot()) {
5233 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005234 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005235 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005236 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005237 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005238 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005239 } else {
5240 DCHECK(destination.IsStackSlot());
5241 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5242 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5243 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005244 } else if (source.IsDoubleStackSlot()) {
5245 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005246 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005247 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005248 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005249 __ movsd(destination.AsFpuRegister<XmmRegister>(),
5250 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005251 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01005252 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005253 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5254 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5255 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005256 } else if (source.IsConstant()) {
5257 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005258 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5259 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005260 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005261 if (value == 0) {
5262 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
5263 } else {
5264 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
5265 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005266 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005267 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005268 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005269 }
5270 } else if (constant->IsLongConstant()) {
5271 int64_t value = constant->AsLongConstant()->GetValue();
5272 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04005273 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005274 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005275 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005276 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005277 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005278 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005279 float fp_value = constant->AsFloatConstant()->GetValue();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005280 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005281 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005282 codegen_->Load32BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005283 } else {
5284 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005285 Immediate imm(bit_cast<int32_t, float>(fp_value));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005286 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
5287 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005288 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005289 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005290 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00005291 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005292 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005293 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005294 codegen_->Load64BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005295 } else {
5296 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005297 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005298 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005299 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005300 } else if (source.IsFpuRegister()) {
5301 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005302 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005303 } else if (destination.IsStackSlot()) {
5304 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005305 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005306 } else {
Nicolas Geoffray31596742014-11-24 15:28:45 +00005307 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005308 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005309 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005310 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005311 }
5312}
5313
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005314void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005315 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005316 __ movl(Address(CpuRegister(RSP), mem), reg);
5317 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005318}
5319
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005320void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005321 ScratchRegisterScope ensure_scratch(
5322 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5323
5324 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5325 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5326 __ movl(CpuRegister(ensure_scratch.GetRegister()),
5327 Address(CpuRegister(RSP), mem2 + stack_offset));
5328 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5329 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
5330 CpuRegister(ensure_scratch.GetRegister()));
5331}
5332
Mark Mendell8a1c7282015-06-29 15:41:28 -04005333void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg1, CpuRegister reg2) {
5334 __ movq(CpuRegister(TMP), reg1);
5335 __ movq(reg1, reg2);
5336 __ movq(reg2, CpuRegister(TMP));
5337}
5338
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005339void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
5340 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5341 __ movq(Address(CpuRegister(RSP), mem), reg);
5342 __ movq(reg, CpuRegister(TMP));
5343}
5344
5345void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
5346 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005347 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005348
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005349 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5350 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5351 __ movq(CpuRegister(ensure_scratch.GetRegister()),
5352 Address(CpuRegister(RSP), mem2 + stack_offset));
5353 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5354 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
5355 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005356}
5357
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005358void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
5359 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5360 __ movss(Address(CpuRegister(RSP), mem), reg);
5361 __ movd(reg, CpuRegister(TMP));
5362}
5363
5364void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
5365 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5366 __ movsd(Address(CpuRegister(RSP), mem), reg);
5367 __ movd(reg, CpuRegister(TMP));
5368}
5369
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005370void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005371 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005372 Location source = move->GetSource();
5373 Location destination = move->GetDestination();
5374
5375 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell8a1c7282015-06-29 15:41:28 -04005376 Exchange64(source.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005377 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005378 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005379 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005380 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005381 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005382 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
5383 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005384 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005385 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005386 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005387 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5388 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005389 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005390 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
5391 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5392 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005393 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005394 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005395 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005396 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005397 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005398 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005399 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005400 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005401 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005402 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005403 }
5404}
5405
5406
5407void ParallelMoveResolverX86_64::SpillScratch(int reg) {
5408 __ pushq(CpuRegister(reg));
5409}
5410
5411
5412void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
5413 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005414}
5415
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005416void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005417 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005418 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5419 Immediate(mirror::Class::kStatusInitialized));
5420 __ j(kLess, slow_path->GetEntryLabel());
5421 __ Bind(slow_path->GetExitLabel());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005422 // No need for memory fence, thanks to the x86-64 memory model.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005423}
5424
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005425HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
5426 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005427 switch (desired_class_load_kind) {
5428 case HLoadClass::LoadKind::kReferrersClass:
5429 break;
5430 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5431 DCHECK(!GetCompilerOptions().GetCompilePic());
5432 // We prefer the always-available RIP-relative address for the x86-64 boot image.
5433 return HLoadClass::LoadKind::kBootImageLinkTimePcRelative;
5434 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5435 DCHECK(GetCompilerOptions().GetCompilePic());
5436 break;
5437 case HLoadClass::LoadKind::kBootImageAddress:
5438 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005439 case HLoadClass::LoadKind::kBssEntry:
5440 DCHECK(!Runtime::Current()->UseJitCompilation());
5441 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005442 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005443 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005444 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005445 case HLoadClass::LoadKind::kDexCacheViaMethod:
5446 break;
5447 }
5448 return desired_class_load_kind;
5449}
5450
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005451void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005452 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5453 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005454 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00005455 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005456 cls,
5457 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00005458 Location::RegisterLocation(RAX));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005459 return;
5460 }
Vladimir Marko41559982017-01-06 14:04:23 +00005461 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005462
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005463 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5464 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005465 ? LocationSummary::kCallOnSlowPath
5466 : LocationSummary::kNoCall;
5467 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005468 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005469 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005470 }
5471
Vladimir Marko41559982017-01-06 14:04:23 +00005472 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005473 locations->SetInAt(0, Location::RequiresRegister());
5474 }
5475 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005476}
5477
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005478Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
5479 dex::TypeIndex dex_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005480 Handle<mirror::Class> handle) {
5481 jit_class_roots_.Overwrite(
5482 TypeReference(&dex_file, dex_index), reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005483 // Add a patch entry and return the label.
5484 jit_class_patches_.emplace_back(dex_file, dex_index.index_);
5485 PatchInfo<Label>* info = &jit_class_patches_.back();
5486 return &info->label;
5487}
5488
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005489// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5490// move.
5491void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00005492 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5493 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5494 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01005495 return;
5496 }
Vladimir Marko41559982017-01-06 14:04:23 +00005497 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01005498
Vladimir Marko41559982017-01-06 14:04:23 +00005499 LocationSummary* locations = cls->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005500 Location out_loc = locations->Out();
5501 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005502
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005503 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
5504 ? kWithoutReadBarrier
5505 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005506 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00005507 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005508 case HLoadClass::LoadKind::kReferrersClass: {
5509 DCHECK(!cls->CanCallRuntime());
5510 DCHECK(!cls->MustGenerateClinitCheck());
5511 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5512 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
5513 GenerateGcRootFieldLoad(
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005514 cls,
5515 out_loc,
5516 Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
Roland Levillain00468f32016-10-27 18:02:48 +01005517 /* fixup_label */ nullptr,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005518 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005519 break;
5520 }
5521 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005522 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005523 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005524 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
Vladimir Marko1998cd02017-01-13 13:02:58 +00005525 codegen_->RecordBootTypePatch(cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005526 break;
5527 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005528 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005529 uint32_t address = dchecked_integral_cast<uint32_t>(
5530 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5531 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005532 __ movl(out, Immediate(address)); // Zero-extended.
5533 codegen_->RecordSimplePatch();
5534 break;
5535 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005536 case HLoadClass::LoadKind::kBssEntry: {
5537 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5538 /* no_rip */ false);
5539 Label* fixup_label = codegen_->NewTypeBssEntryPatch(cls);
5540 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
5541 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
5542 generate_null_check = true;
5543 break;
5544 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005545 case HLoadClass::LoadKind::kJitTableAddress: {
5546 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5547 /* no_rip */ true);
5548 Label* fixup_label =
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005549 codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005550 // /* GcRoot<mirror::Class> */ out = *address
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005551 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, kCompilerReadBarrierOption);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005552 break;
5553 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005554 default:
5555 LOG(FATAL) << "Unexpected load kind: " << cls->GetLoadKind();
5556 UNREACHABLE();
5557 }
5558
5559 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5560 DCHECK(cls->CanCallRuntime());
5561 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
5562 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5563 codegen_->AddSlowPath(slow_path);
5564 if (generate_null_check) {
5565 __ testl(out, out);
5566 __ j(kEqual, slow_path->GetEntryLabel());
5567 }
5568 if (cls->MustGenerateClinitCheck()) {
5569 GenerateClassInitializationCheck(slow_path, out);
5570 } else {
5571 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005572 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005573 }
5574}
5575
5576void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
5577 LocationSummary* locations =
5578 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5579 locations->SetInAt(0, Location::RequiresRegister());
5580 if (check->HasUses()) {
5581 locations->SetOut(Location::SameAsFirstInput());
5582 }
5583}
5584
5585void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005586 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005587 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005588 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005589 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005590 GenerateClassInitializationCheck(slow_path,
5591 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005592}
5593
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005594HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
5595 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005596 switch (desired_string_load_kind) {
5597 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5598 DCHECK(!GetCompilerOptions().GetCompilePic());
5599 // We prefer the always-available RIP-relative address for the x86-64 boot image.
5600 return HLoadString::LoadKind::kBootImageLinkTimePcRelative;
5601 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5602 DCHECK(GetCompilerOptions().GetCompilePic());
5603 break;
5604 case HLoadString::LoadKind::kBootImageAddress:
5605 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00005606 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01005607 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005608 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005609 case HLoadString::LoadKind::kJitTableAddress:
5610 DCHECK(Runtime::Current()->UseJitCompilation());
5611 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005612 case HLoadString::LoadKind::kDexCacheViaMethod:
5613 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005614 }
5615 return desired_string_load_kind;
5616}
5617
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005618void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005619 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005620 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005621 if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthabb341b2016-08-31 16:29:44 -07005622 locations->SetOut(Location::RegisterLocation(RAX));
5623 } else {
5624 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005625 if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) {
5626 if (!kUseReadBarrier || kUseBakerReadBarrier) {
5627 // Rely on the pResolveString and/or marking to save everything.
5628 // Custom calling convention: RAX serves as both input and output.
5629 RegisterSet caller_saves = RegisterSet::Empty();
5630 caller_saves.Add(Location::RegisterLocation(RAX));
5631 locations->SetCustomSlowPathCallerSaves(caller_saves);
5632 } else {
5633 // For non-Baker read barrier we have a temp-clobbering call.
5634 }
5635 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005636 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005637}
5638
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005639Label* CodeGeneratorX86_64::NewJitRootStringPatch(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005640 dex::StringIndex dex_index,
5641 Handle<mirror::String> handle) {
5642 jit_string_roots_.Overwrite(
5643 StringReference(&dex_file, dex_index), reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005644 // Add a patch entry and return the label.
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005645 jit_string_patches_.emplace_back(dex_file, dex_index.index_);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005646 PatchInfo<Label>* info = &jit_string_patches_.back();
5647 return &info->label;
5648}
5649
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005650// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5651// move.
5652void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005653 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005654 Location out_loc = locations->Out();
5655 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005656
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005657 switch (load->GetLoadKind()) {
5658 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005659 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005660 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
Vladimir Markoaad75c62016-10-03 08:46:48 +00005661 codegen_->RecordBootStringPatch(load);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005662 return; // No dex cache slow path.
5663 }
5664 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005665 uint32_t address = dchecked_integral_cast<uint32_t>(
5666 reinterpret_cast<uintptr_t>(load->GetString().Get()));
5667 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005668 __ movl(out, Immediate(address)); // Zero-extended.
5669 codegen_->RecordSimplePatch();
5670 return; // No dex cache slow path.
5671 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00005672 case HLoadString::LoadKind::kBssEntry: {
5673 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5674 /* no_rip */ false);
5675 Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
5676 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005677 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005678 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
5679 codegen_->AddSlowPath(slow_path);
5680 __ testl(out, out);
5681 __ j(kEqual, slow_path->GetEntryLabel());
5682 __ Bind(slow_path->GetExitLabel());
5683 return;
5684 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005685 case HLoadString::LoadKind::kJitTableAddress: {
5686 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5687 /* no_rip */ true);
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005688 Label* fixup_label = codegen_->NewJitRootStringPatch(
5689 load->GetDexFile(), load->GetStringIndex(), load->GetString());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005690 // /* GcRoot<mirror::String> */ out = *address
5691 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
5692 return;
5693 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005694 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005695 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005696 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005697
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005698 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005699 // Custom calling convention: RAX serves as both input and output.
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005700 __ movl(CpuRegister(RAX), Immediate(load->GetStringIndex().index_));
Christina Wadsworthabb341b2016-08-31 16:29:44 -07005701 codegen_->InvokeRuntime(kQuickResolveString,
5702 load,
5703 load->GetDexPc());
5704 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005705}
5706
David Brazdilcb1c0552015-08-04 16:22:25 +01005707static Address GetExceptionTlsAddress() {
Andreas Gampe542451c2016-07-26 09:02:02 -07005708 return Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005709 /* no_rip */ true);
David Brazdilcb1c0552015-08-04 16:22:25 +01005710}
5711
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005712void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
5713 LocationSummary* locations =
5714 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5715 locations->SetOut(Location::RequiresRegister());
5716}
5717
5718void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005719 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
5720}
5721
5722void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
5723 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5724}
5725
5726void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5727 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005728}
5729
5730void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
5731 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005732 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005733 InvokeRuntimeCallingConvention calling_convention;
5734 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5735}
5736
5737void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01005738 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00005739 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005740}
5741
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005742static bool CheckCastTypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5743 if (type_check_kind == TypeCheckKind::kInterfaceCheck && !kPoisonHeapReferences) {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07005744 // We need a temporary for holding the iftable length.
5745 return true;
5746 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005747 return kEmitCompilerReadBarrier &&
Vladimir Marko953437b2016-08-24 08:30:46 +00005748 !kUseBakerReadBarrier &&
5749 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005750 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5751 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5752}
5753
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005754static bool InstanceOfTypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5755 return kEmitCompilerReadBarrier &&
5756 !kUseBakerReadBarrier &&
5757 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5758 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5759 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5760}
5761
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005762void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005763 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005764 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01005765 bool baker_read_barrier_slow_path = false;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005766 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005767 case TypeCheckKind::kExactCheck:
5768 case TypeCheckKind::kAbstractClassCheck:
5769 case TypeCheckKind::kClassHierarchyCheck:
5770 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005771 call_kind =
5772 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01005773 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005774 break;
5775 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005776 case TypeCheckKind::kUnresolvedCheck:
5777 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005778 call_kind = LocationSummary::kCallOnSlowPath;
5779 break;
5780 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005781
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005782 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01005783 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005784 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005785 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005786 locations->SetInAt(0, Location::RequiresRegister());
5787 locations->SetInAt(1, Location::Any());
5788 // Note that TypeCheckSlowPathX86_64 uses this "out" register too.
5789 locations->SetOut(Location::RequiresRegister());
5790 // When read barriers are enabled, we need a temporary register for
5791 // some cases.
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005792 if (InstanceOfTypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005793 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005794 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005795}
5796
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005797void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005798 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005799 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005800 Location obj_loc = locations->InAt(0);
5801 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005802 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005803 Location out_loc = locations->Out();
5804 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005805 Location maybe_temp_loc = InstanceOfTypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005806 locations->GetTemp(0) :
5807 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005808 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005809 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5810 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5811 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005812 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005813 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005814
5815 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005816 // Avoid null check if we know obj is not null.
5817 if (instruction->MustDoNullCheck()) {
5818 __ testl(obj, obj);
5819 __ j(kEqual, &zero);
5820 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005821
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005822 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005823 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005824 // /* HeapReference<Class> */ out = obj->klass_
5825 GenerateReferenceLoadTwoRegisters(instruction,
5826 out_loc,
5827 obj_loc,
5828 class_offset,
5829 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005830 if (cls.IsRegister()) {
5831 __ cmpl(out, cls.AsRegister<CpuRegister>());
5832 } else {
5833 DCHECK(cls.IsStackSlot()) << cls;
5834 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5835 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005836 if (zero.IsLinked()) {
5837 // Classes must be equal for the instanceof to succeed.
5838 __ j(kNotEqual, &zero);
5839 __ movl(out, Immediate(1));
5840 __ jmp(&done);
5841 } else {
5842 __ setcc(kEqual, out);
5843 // setcc only sets the low byte.
5844 __ andl(out, Immediate(1));
5845 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005846 break;
5847 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005848
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005849 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005850 // /* HeapReference<Class> */ out = obj->klass_
5851 GenerateReferenceLoadTwoRegisters(instruction,
5852 out_loc,
5853 obj_loc,
5854 class_offset,
5855 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005856 // If the class is abstract, we eagerly fetch the super class of the
5857 // object to avoid doing a comparison we know will fail.
5858 NearLabel loop, success;
5859 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005860 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005861 GenerateReferenceLoadOneRegister(instruction,
5862 out_loc,
5863 super_offset,
5864 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005865 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005866 __ testl(out, out);
5867 // If `out` is null, we use it for the result, and jump to `done`.
5868 __ j(kEqual, &done);
5869 if (cls.IsRegister()) {
5870 __ cmpl(out, cls.AsRegister<CpuRegister>());
5871 } else {
5872 DCHECK(cls.IsStackSlot()) << cls;
5873 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5874 }
5875 __ j(kNotEqual, &loop);
5876 __ movl(out, Immediate(1));
5877 if (zero.IsLinked()) {
5878 __ jmp(&done);
5879 }
5880 break;
5881 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005882
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005883 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005884 // /* HeapReference<Class> */ out = obj->klass_
5885 GenerateReferenceLoadTwoRegisters(instruction,
5886 out_loc,
5887 obj_loc,
5888 class_offset,
5889 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005890 // Walk over the class hierarchy to find a match.
5891 NearLabel loop, success;
5892 __ Bind(&loop);
5893 if (cls.IsRegister()) {
5894 __ cmpl(out, cls.AsRegister<CpuRegister>());
5895 } else {
5896 DCHECK(cls.IsStackSlot()) << cls;
5897 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5898 }
5899 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005900 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005901 GenerateReferenceLoadOneRegister(instruction,
5902 out_loc,
5903 super_offset,
5904 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005905 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005906 __ testl(out, out);
5907 __ j(kNotEqual, &loop);
5908 // If `out` is null, we use it for the result, and jump to `done`.
5909 __ jmp(&done);
5910 __ Bind(&success);
5911 __ movl(out, Immediate(1));
5912 if (zero.IsLinked()) {
5913 __ jmp(&done);
5914 }
5915 break;
5916 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005917
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005918 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005919 // /* HeapReference<Class> */ out = obj->klass_
5920 GenerateReferenceLoadTwoRegisters(instruction,
5921 out_loc,
5922 obj_loc,
5923 class_offset,
5924 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005925 // Do an exact check.
5926 NearLabel exact_check;
5927 if (cls.IsRegister()) {
5928 __ cmpl(out, cls.AsRegister<CpuRegister>());
5929 } else {
5930 DCHECK(cls.IsStackSlot()) << cls;
5931 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5932 }
5933 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005934 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005935 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005936 GenerateReferenceLoadOneRegister(instruction,
5937 out_loc,
5938 component_offset,
5939 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005940 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005941 __ testl(out, out);
5942 // If `out` is null, we use it for the result, and jump to `done`.
5943 __ j(kEqual, &done);
5944 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5945 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005946 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005947 __ movl(out, Immediate(1));
5948 __ jmp(&done);
5949 break;
5950 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005951
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005952 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005953 // No read barrier since the slow path will retry upon failure.
5954 // /* HeapReference<Class> */ out = obj->klass_
5955 GenerateReferenceLoadTwoRegisters(instruction,
5956 out_loc,
5957 obj_loc,
5958 class_offset,
5959 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005960 if (cls.IsRegister()) {
5961 __ cmpl(out, cls.AsRegister<CpuRegister>());
5962 } else {
5963 DCHECK(cls.IsStackSlot()) << cls;
5964 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5965 }
5966 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005967 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
5968 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005969 codegen_->AddSlowPath(slow_path);
5970 __ j(kNotEqual, slow_path->GetEntryLabel());
5971 __ movl(out, Immediate(1));
5972 if (zero.IsLinked()) {
5973 __ jmp(&done);
5974 }
5975 break;
5976 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005977
Calin Juravle98893e12015-10-02 21:05:03 +01005978 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005979 case TypeCheckKind::kInterfaceCheck: {
5980 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005981 // into the slow path for the unresolved and interface check
Roland Levillain0d5a2812015-11-13 10:07:31 +00005982 // cases.
5983 //
5984 // We cannot directly call the InstanceofNonTrivial runtime
5985 // entry point without resorting to a type checking slow path
5986 // here (i.e. by calling InvokeRuntime directly), as it would
5987 // require to assign fixed registers for the inputs of this
5988 // HInstanceOf instruction (following the runtime calling
5989 // convention), which might be cluttered by the potential first
5990 // read barrier emission at the beginning of this method.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005991 //
5992 // TODO: Introduce a new runtime entry point taking the object
5993 // to test (instead of its class) as argument, and let it deal
5994 // with the read barrier issues. This will let us refactor this
5995 // case of the `switch` code as it was previously (with a direct
5996 // call to the runtime not using a type checking slow path).
5997 // This should also be beneficial for the other cases above.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005998 DCHECK(locations->OnlyCallsOnSlowPath());
5999 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
6000 /* is_fatal */ false);
6001 codegen_->AddSlowPath(slow_path);
6002 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006003 if (zero.IsLinked()) {
6004 __ jmp(&done);
6005 }
6006 break;
6007 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006008 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006009
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006010 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006011 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006012 __ xorl(out, out);
6013 }
6014
6015 if (done.IsLinked()) {
6016 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006017 }
6018
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006019 if (slow_path != nullptr) {
6020 __ Bind(slow_path->GetExitLabel());
6021 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006022}
6023
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006024static bool IsTypeCheckSlowPathFatal(TypeCheckKind type_check_kind, bool throws_into_catch) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006025 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006026 case TypeCheckKind::kExactCheck:
6027 case TypeCheckKind::kAbstractClassCheck:
6028 case TypeCheckKind::kClassHierarchyCheck:
6029 case TypeCheckKind::kArrayObjectCheck:
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006030 return !throws_into_catch && !kEmitCompilerReadBarrier;
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006031 case TypeCheckKind::kInterfaceCheck:
6032 return !throws_into_catch && !kEmitCompilerReadBarrier && !kPoisonHeapReferences;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006033 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00006034 case TypeCheckKind::kUnresolvedCheck:
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006035 return false;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006036 }
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006037 LOG(FATAL) << "Unreachable";
6038 UNREACHABLE();
6039}
6040
6041void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
6042 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
6043 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6044 bool is_fatal_slow_path = IsTypeCheckSlowPathFatal(type_check_kind, throws_into_catch);
6045 LocationSummary::CallKind call_kind = is_fatal_slow_path
6046 ? LocationSummary::kNoCall
6047 : LocationSummary::kCallOnSlowPath;
Roland Levillain0d5a2812015-11-13 10:07:31 +00006048 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6049 locations->SetInAt(0, Location::RequiresRegister());
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006050 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6051 // Require a register for the interface check since there is a loop that compares the class to
6052 // a memory address.
6053 locations->SetInAt(1, Location::RequiresRegister());
6054 } else {
6055 locations->SetInAt(1, Location::Any());
6056 }
6057
Roland Levillain0d5a2812015-11-13 10:07:31 +00006058 // Note that TypeCheckSlowPathX86_64 uses this "temp" register too.
6059 locations->AddTemp(Location::RequiresRegister());
6060 // When read barriers are enabled, we need an additional temporary
6061 // register for some cases.
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006062 if (CheckCastTypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006063 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006064 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006065}
6066
6067void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006068 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006069 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006070 Location obj_loc = locations->InAt(0);
6071 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006072 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006073 Location temp_loc = locations->GetTemp(0);
6074 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006075 Location maybe_temp2_loc = CheckCastTypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006076 locations->GetTemp(1) :
6077 Location::NoLocation();
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006078 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6079 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6080 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6081 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6082 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6083 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006084 const uint32_t object_array_data_offset =
6085 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006086
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006087 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
6088 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
6089 // read barriers is done for performance and code size reasons.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006090 bool is_type_check_slow_path_fatal =
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006091 IsTypeCheckSlowPathFatal(type_check_kind, instruction->CanThrowIntoCatchBlock());
Roland Levillain0d5a2812015-11-13 10:07:31 +00006092 SlowPathCode* type_check_slow_path =
6093 new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
6094 is_type_check_slow_path_fatal);
6095 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006096
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006097
6098 NearLabel done;
6099 // Avoid null check if we know obj is not null.
6100 if (instruction->MustDoNullCheck()) {
6101 __ testl(obj, obj);
6102 __ j(kEqual, &done);
6103 }
6104
Roland Levillain0d5a2812015-11-13 10:07:31 +00006105 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006106 case TypeCheckKind::kExactCheck:
6107 case TypeCheckKind::kArrayCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006108 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006109 GenerateReferenceLoadTwoRegisters(instruction,
6110 temp_loc,
6111 obj_loc,
6112 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006113 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006114 if (cls.IsRegister()) {
6115 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6116 } else {
6117 DCHECK(cls.IsStackSlot()) << cls;
6118 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6119 }
6120 // Jump to slow path for throwing the exception or doing a
6121 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006122 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006123 break;
6124 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006125
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006126 case TypeCheckKind::kAbstractClassCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006127 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006128 GenerateReferenceLoadTwoRegisters(instruction,
6129 temp_loc,
6130 obj_loc,
6131 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006132 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006133 // If the class is abstract, we eagerly fetch the super class of the
6134 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006135 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006136 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006137 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006138 GenerateReferenceLoadOneRegister(instruction,
6139 temp_loc,
6140 super_offset,
6141 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006142 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006143
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006144 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6145 // exception.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006146 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006147 // Otherwise, compare the classes.
6148 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006149 if (cls.IsRegister()) {
6150 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6151 } else {
6152 DCHECK(cls.IsStackSlot()) << cls;
6153 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6154 }
6155 __ j(kNotEqual, &loop);
6156 break;
6157 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006158
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006159 case TypeCheckKind::kClassHierarchyCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006160 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006161 GenerateReferenceLoadTwoRegisters(instruction,
6162 temp_loc,
6163 obj_loc,
6164 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006165 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006166 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006167 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006168 __ Bind(&loop);
6169 if (cls.IsRegister()) {
6170 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6171 } else {
6172 DCHECK(cls.IsStackSlot()) << cls;
6173 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6174 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006175 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006176
Roland Levillain0d5a2812015-11-13 10:07:31 +00006177 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006178 GenerateReferenceLoadOneRegister(instruction,
6179 temp_loc,
6180 super_offset,
6181 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006182 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006183
6184 // If the class reference currently in `temp` is not null, jump
6185 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006186 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006187 __ j(kNotZero, &loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006188 // Otherwise, jump to the slow path to throw the exception.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006189 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006190 break;
6191 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006192
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006193 case TypeCheckKind::kArrayObjectCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006194 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006195 GenerateReferenceLoadTwoRegisters(instruction,
6196 temp_loc,
6197 obj_loc,
6198 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006199 kWithoutReadBarrier);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006200 // Do an exact check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006201 NearLabel check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006202 if (cls.IsRegister()) {
6203 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6204 } else {
6205 DCHECK(cls.IsStackSlot()) << cls;
6206 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6207 }
6208 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006209
6210 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006211 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006212 GenerateReferenceLoadOneRegister(instruction,
6213 temp_loc,
6214 component_offset,
6215 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006216 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006217
6218 // If the component type is not null (i.e. the object is indeed
6219 // an array), jump to label `check_non_primitive_component_type`
6220 // to further check that this component type is not a primitive
6221 // type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006222 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006223 // Otherwise, jump to the slow path to throw the exception.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006224 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006225 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006226 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006227 break;
6228 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006229
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006230 case TypeCheckKind::kUnresolvedCheck: {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006231 // We always go into the type check slow path for the unresolved case.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006232 //
6233 // We cannot directly call the CheckCast runtime entry point
6234 // without resorting to a type checking slow path here (i.e. by
6235 // calling InvokeRuntime directly), as it would require to
6236 // assign fixed registers for the inputs of this HInstanceOf
6237 // instruction (following the runtime calling convention), which
6238 // might be cluttered by the potential first read barrier
6239 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006240 __ jmp(type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006241 break;
6242 }
6243
6244 case TypeCheckKind::kInterfaceCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006245 // Fast path for the interface check. We always go slow path for heap poisoning since
6246 // unpoisoning cls would require an extra temp.
6247 if (!kPoisonHeapReferences) {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006248 // Try to avoid read barriers to improve the fast path. We can not get false positives by
6249 // doing this.
6250 // /* HeapReference<Class> */ temp = obj->klass_
6251 GenerateReferenceLoadTwoRegisters(instruction,
6252 temp_loc,
6253 obj_loc,
6254 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006255 kWithoutReadBarrier);
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006256
6257 // /* HeapReference<Class> */ temp = temp->iftable_
6258 GenerateReferenceLoadTwoRegisters(instruction,
6259 temp_loc,
6260 temp_loc,
6261 iftable_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006262 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006263 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006264 __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006265 // Loop through the iftable and check if any class matches.
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006266 NearLabel start_loop;
6267 __ Bind(&start_loop);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006268 // Need to subtract first to handle the empty array case.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006269 __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006270 __ j(kNegative, type_check_slow_path->GetEntryLabel());
6271 // Go to next interface if the classes do not match.
6272 __ cmpl(cls.AsRegister<CpuRegister>(),
6273 CodeGeneratorX86_64::ArrayAddress(temp,
6274 maybe_temp2_loc,
6275 TIMES_4,
6276 object_array_data_offset));
6277 __ j(kNotEqual, &start_loop); // Return if same class.
6278 } else {
6279 __ jmp(type_check_slow_path->GetEntryLabel());
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006280 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006281 break;
6282 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006283
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006284 if (done.IsLinked()) {
6285 __ Bind(&done);
6286 }
6287
Roland Levillain0d5a2812015-11-13 10:07:31 +00006288 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006289}
6290
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006291void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
6292 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006293 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006294 InvokeRuntimeCallingConvention calling_convention;
6295 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6296}
6297
6298void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01006299 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
Alexandre Rames8158f282015-08-07 10:26:17 +01006300 instruction,
Serban Constantinescuba45db02016-07-12 22:53:02 +01006301 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006302 if (instruction->IsEnter()) {
6303 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6304 } else {
6305 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6306 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006307}
6308
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006309void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
6310void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
6311void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
6312
6313void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6314 LocationSummary* locations =
6315 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6316 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6317 || instruction->GetResultType() == Primitive::kPrimLong);
6318 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04006319 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006320 locations->SetOut(Location::SameAsFirstInput());
6321}
6322
6323void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
6324 HandleBitwiseOperation(instruction);
6325}
6326
6327void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
6328 HandleBitwiseOperation(instruction);
6329}
6330
6331void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
6332 HandleBitwiseOperation(instruction);
6333}
6334
6335void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6336 LocationSummary* locations = instruction->GetLocations();
6337 Location first = locations->InAt(0);
6338 Location second = locations->InAt(1);
6339 DCHECK(first.Equals(locations->Out()));
6340
6341 if (instruction->GetResultType() == Primitive::kPrimInt) {
6342 if (second.IsRegister()) {
6343 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006344 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006345 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006346 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006347 } else {
6348 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006349 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006350 }
6351 } else if (second.IsConstant()) {
6352 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
6353 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006354 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006355 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006356 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006357 } else {
6358 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006359 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006360 }
6361 } else {
6362 Address address(CpuRegister(RSP), second.GetStackIndex());
6363 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006364 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006365 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006366 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006367 } else {
6368 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006369 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006370 }
6371 }
6372 } else {
6373 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006374 CpuRegister first_reg = first.AsRegister<CpuRegister>();
6375 bool second_is_constant = false;
6376 int64_t value = 0;
6377 if (second.IsConstant()) {
6378 second_is_constant = true;
6379 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006380 }
Mark Mendell40741f32015-04-20 22:10:34 -04006381 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006382
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006383 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006384 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006385 if (is_int32_value) {
6386 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
6387 } else {
6388 __ andq(first_reg, codegen_->LiteralInt64Address(value));
6389 }
6390 } else if (second.IsDoubleStackSlot()) {
6391 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006392 } else {
6393 __ andq(first_reg, second.AsRegister<CpuRegister>());
6394 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006395 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006396 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006397 if (is_int32_value) {
6398 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
6399 } else {
6400 __ orq(first_reg, codegen_->LiteralInt64Address(value));
6401 }
6402 } else if (second.IsDoubleStackSlot()) {
6403 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006404 } else {
6405 __ orq(first_reg, second.AsRegister<CpuRegister>());
6406 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006407 } else {
6408 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006409 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006410 if (is_int32_value) {
6411 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
6412 } else {
6413 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
6414 }
6415 } else if (second.IsDoubleStackSlot()) {
6416 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006417 } else {
6418 __ xorq(first_reg, second.AsRegister<CpuRegister>());
6419 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006420 }
6421 }
6422}
6423
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006424void InstructionCodeGeneratorX86_64::GenerateReferenceLoadOneRegister(
6425 HInstruction* instruction,
6426 Location out,
6427 uint32_t offset,
6428 Location maybe_temp,
6429 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006430 CpuRegister out_reg = out.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006431 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006432 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006433 if (kUseBakerReadBarrier) {
6434 // Load with fast path based Baker's read barrier.
6435 // /* HeapReference<Object> */ out = *(out + offset)
6436 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00006437 instruction, out, out_reg, offset, /* needs_null_check */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006438 } else {
6439 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006440 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006441 // in the following move operation, as we will need it for the
6442 // read barrier below.
Vladimir Marko953437b2016-08-24 08:30:46 +00006443 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006444 __ movl(maybe_temp.AsRegister<CpuRegister>(), out_reg);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006445 // /* HeapReference<Object> */ out = *(out + offset)
6446 __ movl(out_reg, Address(out_reg, offset));
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006447 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006448 }
6449 } else {
6450 // Plain load with no read barrier.
6451 // /* HeapReference<Object> */ out = *(out + offset)
6452 __ movl(out_reg, Address(out_reg, offset));
6453 __ MaybeUnpoisonHeapReference(out_reg);
6454 }
6455}
6456
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006457void InstructionCodeGeneratorX86_64::GenerateReferenceLoadTwoRegisters(
6458 HInstruction* instruction,
6459 Location out,
6460 Location obj,
6461 uint32_t offset,
6462 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006463 CpuRegister out_reg = out.AsRegister<CpuRegister>();
6464 CpuRegister obj_reg = obj.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006465 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006466 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006467 if (kUseBakerReadBarrier) {
6468 // Load with fast path based Baker's read barrier.
6469 // /* HeapReference<Object> */ out = *(obj + offset)
6470 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00006471 instruction, out, obj_reg, offset, /* needs_null_check */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006472 } else {
6473 // Load with slow path based read barrier.
6474 // /* HeapReference<Object> */ out = *(obj + offset)
6475 __ movl(out_reg, Address(obj_reg, offset));
6476 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6477 }
6478 } else {
6479 // Plain load with no read barrier.
6480 // /* HeapReference<Object> */ out = *(obj + offset)
6481 __ movl(out_reg, Address(obj_reg, offset));
6482 __ MaybeUnpoisonHeapReference(out_reg);
6483 }
6484}
6485
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006486void InstructionCodeGeneratorX86_64::GenerateGcRootFieldLoad(
6487 HInstruction* instruction,
6488 Location root,
6489 const Address& address,
6490 Label* fixup_label,
6491 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006492 CpuRegister root_reg = root.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006493 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006494 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006495 if (kUseBakerReadBarrier) {
6496 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6497 // Baker's read barrier are used:
6498 //
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006499 // root = *address;
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006500 // if (Thread::Current()->GetIsGcMarking()) {
6501 // root = ReadBarrier::Mark(root)
6502 // }
6503
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006504 // /* GcRoot<mirror::Object> */ root = *address
6505 __ movl(root_reg, address);
6506 if (fixup_label != nullptr) {
6507 __ Bind(fixup_label);
6508 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006509 static_assert(
6510 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6511 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6512 "have different sizes.");
6513 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6514 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6515 "have different sizes.");
6516
Vladimir Marko953437b2016-08-24 08:30:46 +00006517 // Slow path marking the GC root `root`.
6518 SlowPathCode* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006519 instruction, root, /* unpoison_ref_before_marking */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006520 codegen_->AddSlowPath(slow_path);
6521
Andreas Gampe542451c2016-07-26 09:02:02 -07006522 __ gs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006523 /* no_rip */ true),
6524 Immediate(0));
6525 __ j(kNotEqual, slow_path->GetEntryLabel());
6526 __ Bind(slow_path->GetExitLabel());
6527 } else {
6528 // GC root loaded through a slow path for read barriers other
6529 // than Baker's.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006530 // /* GcRoot<mirror::Object>* */ root = address
6531 __ leaq(root_reg, address);
6532 if (fixup_label != nullptr) {
6533 __ Bind(fixup_label);
6534 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006535 // /* mirror::Object* */ root = root->Read()
6536 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6537 }
6538 } else {
6539 // Plain GC root load with no read barrier.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006540 // /* GcRoot<mirror::Object> */ root = *address
6541 __ movl(root_reg, address);
6542 if (fixup_label != nullptr) {
6543 __ Bind(fixup_label);
6544 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006545 // Note that GC roots are not affected by heap poisoning, thus we
6546 // do not have to unpoison `root_reg` here.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006547 }
6548}
6549
6550void CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6551 Location ref,
6552 CpuRegister obj,
6553 uint32_t offset,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006554 bool needs_null_check) {
6555 DCHECK(kEmitCompilerReadBarrier);
6556 DCHECK(kUseBakerReadBarrier);
6557
6558 // /* HeapReference<Object> */ ref = *(obj + offset)
6559 Address src(obj, offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00006560 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006561}
6562
6563void CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6564 Location ref,
6565 CpuRegister obj,
6566 uint32_t data_offset,
6567 Location index,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006568 bool needs_null_check) {
6569 DCHECK(kEmitCompilerReadBarrier);
6570 DCHECK(kUseBakerReadBarrier);
6571
Roland Levillain3d312422016-06-23 13:53:42 +01006572 static_assert(
6573 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6574 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006575 // /* HeapReference<Object> */ ref =
6576 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006577 Address src = CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00006578 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006579}
6580
6581void CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6582 Location ref,
6583 CpuRegister obj,
6584 const Address& src,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006585 bool needs_null_check,
6586 bool always_update_field,
6587 CpuRegister* temp1,
6588 CpuRegister* temp2) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006589 DCHECK(kEmitCompilerReadBarrier);
6590 DCHECK(kUseBakerReadBarrier);
6591
6592 // In slow path based read barriers, the read barrier call is
6593 // inserted after the original load. However, in fast path based
6594 // Baker's read barriers, we need to perform the load of
6595 // mirror::Object::monitor_ *before* the original reference load.
6596 // This load-load ordering is required by the read barrier.
6597 // The fast path/slow path (for Baker's algorithm) should look like:
6598 //
6599 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6600 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6601 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006602 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006603 // if (is_gray) {
6604 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6605 // }
6606 //
6607 // Note: the original implementation in ReadBarrier::Barrier is
6608 // slightly more complex as:
6609 // - it implements the load-load fence using a data dependency on
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006610 // the high-bits of rb_state, which are expected to be all zeroes
6611 // (we use CodeGeneratorX86_64::GenerateMemoryBarrier instead
6612 // here, which is a no-op thanks to the x86-64 memory model);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006613 // - it performs additional checks that we do not do here for
6614 // performance reasons.
6615
6616 CpuRegister ref_reg = ref.AsRegister<CpuRegister>();
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006617 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6618
Vladimir Marko953437b2016-08-24 08:30:46 +00006619 // Given the numeric representation, it's enough to check the low bit of the rb_state.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006620 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
6621 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko953437b2016-08-24 08:30:46 +00006622 constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
6623 constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
6624 constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
6625
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006626 // if (rb_state == ReadBarrier::GrayState())
Vladimir Marko953437b2016-08-24 08:30:46 +00006627 // ref = ReadBarrier::Mark(ref);
6628 // At this point, just do the "if" and make sure that flags are preserved until the branch.
6629 __ testb(Address(obj, monitor_offset + gray_byte_position), Immediate(test_value));
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006630 if (needs_null_check) {
6631 MaybeRecordImplicitNullCheck(instruction);
6632 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006633
6634 // Load fence to prevent load-load reordering.
6635 // Note that this is a no-op, thanks to the x86-64 memory model.
6636 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6637
6638 // The actual reference load.
6639 // /* HeapReference<Object> */ ref = *src
Vladimir Marko953437b2016-08-24 08:30:46 +00006640 __ movl(ref_reg, src); // Flags are unaffected.
6641
6642 // Note: Reference unpoisoning modifies the flags, so we need to delay it after the branch.
6643 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006644 SlowPathCode* slow_path;
6645 if (always_update_field) {
6646 DCHECK(temp1 != nullptr);
6647 DCHECK(temp2 != nullptr);
6648 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkAndUpdateFieldSlowPathX86_64(
6649 instruction, ref, obj, src, /* unpoison_ref_before_marking */ true, *temp1, *temp2);
6650 } else {
6651 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(
6652 instruction, ref, /* unpoison_ref_before_marking */ true);
6653 }
Vladimir Marko953437b2016-08-24 08:30:46 +00006654 AddSlowPath(slow_path);
6655
6656 // We have done the "if" of the gray bit check above, now branch based on the flags.
6657 __ j(kNotZero, slow_path->GetEntryLabel());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006658
6659 // Object* ref = ref_addr->AsMirrorPtr()
6660 __ MaybeUnpoisonHeapReference(ref_reg);
6661
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006662 __ Bind(slow_path->GetExitLabel());
6663}
6664
6665void CodeGeneratorX86_64::GenerateReadBarrierSlow(HInstruction* instruction,
6666 Location out,
6667 Location ref,
6668 Location obj,
6669 uint32_t offset,
6670 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006671 DCHECK(kEmitCompilerReadBarrier);
6672
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006673 // Insert a slow path based read barrier *after* the reference load.
6674 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00006675 // If heap poisoning is enabled, the unpoisoning of the loaded
6676 // reference will be carried out by the runtime within the slow
6677 // path.
6678 //
6679 // Note that `ref` currently does not get unpoisoned (when heap
6680 // poisoning is enabled), which is alright as the `ref` argument is
6681 // not used by the artReadBarrierSlow entry point.
6682 //
6683 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6684 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6685 ReadBarrierForHeapReferenceSlowPathX86_64(instruction, out, ref, obj, offset, index);
6686 AddSlowPath(slow_path);
6687
Roland Levillain0d5a2812015-11-13 10:07:31 +00006688 __ jmp(slow_path->GetEntryLabel());
6689 __ Bind(slow_path->GetExitLabel());
6690}
6691
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006692void CodeGeneratorX86_64::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6693 Location out,
6694 Location ref,
6695 Location obj,
6696 uint32_t offset,
6697 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006698 if (kEmitCompilerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006699 // Baker's read barriers shall be handled by the fast path
6700 // (CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier).
6701 DCHECK(!kUseBakerReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006702 // If heap poisoning is enabled, unpoisoning will be taken care of
6703 // by the runtime within the slow path.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006704 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006705 } else if (kPoisonHeapReferences) {
6706 __ UnpoisonHeapReference(out.AsRegister<CpuRegister>());
6707 }
6708}
6709
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006710void CodeGeneratorX86_64::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6711 Location out,
6712 Location root) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006713 DCHECK(kEmitCompilerReadBarrier);
6714
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006715 // Insert a slow path based read barrier *after* the GC root load.
6716 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00006717 // Note that GC roots are not affected by heap poisoning, so we do
6718 // not need to do anything special for this here.
6719 SlowPathCode* slow_path =
6720 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathX86_64(instruction, out, root);
6721 AddSlowPath(slow_path);
6722
Roland Levillain0d5a2812015-11-13 10:07:31 +00006723 __ jmp(slow_path->GetEntryLabel());
6724 __ Bind(slow_path->GetExitLabel());
6725}
6726
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006727void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006728 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006729 LOG(FATAL) << "Unreachable";
6730}
6731
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006732void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006733 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006734 LOG(FATAL) << "Unreachable";
6735}
6736
Mark Mendellfe57faa2015-09-18 09:26:15 -04006737// Simple implementation of packed switch - generate cascaded compare/jumps.
6738void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6739 LocationSummary* locations =
6740 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6741 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04006742 locations->AddTemp(Location::RequiresRegister());
6743 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04006744}
6745
6746void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6747 int32_t lower_bound = switch_instr->GetStartValue();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006748 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006749 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04006750 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
6751 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
6752 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006753 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6754
6755 // Should we generate smaller inline compare/jumps?
6756 if (num_entries <= kPackedSwitchJumpTableThreshold) {
6757 // Figure out the correct compare values and jump conditions.
6758 // Handle the first compare/branch as a special case because it might
6759 // jump to the default case.
6760 DCHECK_GT(num_entries, 2u);
6761 Condition first_condition;
6762 uint32_t index;
6763 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6764 if (lower_bound != 0) {
6765 first_condition = kLess;
6766 __ cmpl(value_reg_in, Immediate(lower_bound));
6767 __ j(first_condition, codegen_->GetLabelOf(default_block));
6768 __ j(kEqual, codegen_->GetLabelOf(successors[0]));
6769
6770 index = 1;
6771 } else {
6772 // Handle all the compare/jumps below.
6773 first_condition = kBelow;
6774 index = 0;
6775 }
6776
6777 // Handle the rest of the compare/jumps.
6778 for (; index + 1 < num_entries; index += 2) {
6779 int32_t compare_to_value = lower_bound + index + 1;
6780 __ cmpl(value_reg_in, Immediate(compare_to_value));
6781 // Jump to successors[index] if value < case_value[index].
6782 __ j(first_condition, codegen_->GetLabelOf(successors[index]));
6783 // Jump to successors[index + 1] if value == case_value[index + 1].
6784 __ j(kEqual, codegen_->GetLabelOf(successors[index + 1]));
6785 }
6786
6787 if (index != num_entries) {
6788 // There are an odd number of entries. Handle the last one.
6789 DCHECK_EQ(index + 1, num_entries);
Nicolas Geoffray6ce01732015-12-30 14:10:13 +00006790 __ cmpl(value_reg_in, Immediate(static_cast<int32_t>(lower_bound + index)));
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006791 __ j(kEqual, codegen_->GetLabelOf(successors[index]));
6792 }
6793
6794 // And the default for any other value.
6795 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6796 __ jmp(codegen_->GetLabelOf(default_block));
6797 }
6798 return;
6799 }
Mark Mendell9c86b482015-09-18 13:36:07 -04006800
6801 // Remove the bias, if needed.
6802 Register value_reg_out = value_reg_in.AsRegister();
6803 if (lower_bound != 0) {
6804 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
6805 value_reg_out = temp_reg.AsRegister();
6806 }
6807 CpuRegister value_reg(value_reg_out);
6808
6809 // Is the value in range?
Mark Mendell9c86b482015-09-18 13:36:07 -04006810 __ cmpl(value_reg, Immediate(num_entries - 1));
6811 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006812
Mark Mendell9c86b482015-09-18 13:36:07 -04006813 // We are in the range of the table.
6814 // Load the address of the jump table in the constant area.
6815 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006816
Mark Mendell9c86b482015-09-18 13:36:07 -04006817 // Load the (signed) offset from the jump table.
6818 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
6819
6820 // Add the offset to the address of the table base.
6821 __ addq(temp_reg, base_reg);
6822
6823 // And jump.
6824 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006825}
6826
Aart Bikc5d47542016-01-27 17:00:35 -08006827void CodeGeneratorX86_64::Load32BitValue(CpuRegister dest, int32_t value) {
6828 if (value == 0) {
6829 __ xorl(dest, dest);
6830 } else {
6831 __ movl(dest, Immediate(value));
6832 }
6833}
6834
Mark Mendell92e83bf2015-05-07 11:25:03 -04006835void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
6836 if (value == 0) {
Aart Bikc5d47542016-01-27 17:00:35 -08006837 // Clears upper bits too.
Mark Mendell92e83bf2015-05-07 11:25:03 -04006838 __ xorl(dest, dest);
Vladimir Markoed009782016-02-22 16:54:39 +00006839 } else if (IsUint<32>(value)) {
6840 // We can use a 32 bit move, as it will zero-extend and is shorter.
Mark Mendell92e83bf2015-05-07 11:25:03 -04006841 __ movl(dest, Immediate(static_cast<int32_t>(value)));
6842 } else {
6843 __ movq(dest, Immediate(value));
6844 }
6845}
6846
Mark Mendell7c0b44f2016-02-01 10:08:35 -05006847void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, int32_t value) {
6848 if (value == 0) {
6849 __ xorps(dest, dest);
6850 } else {
6851 __ movss(dest, LiteralInt32Address(value));
6852 }
6853}
6854
6855void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, int64_t value) {
6856 if (value == 0) {
6857 __ xorpd(dest, dest);
6858 } else {
6859 __ movsd(dest, LiteralInt64Address(value));
6860 }
6861}
6862
6863void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, float value) {
6864 Load32BitValue(dest, bit_cast<int32_t, float>(value));
6865}
6866
6867void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, double value) {
6868 Load64BitValue(dest, bit_cast<int64_t, double>(value));
6869}
6870
Aart Bika19616e2016-02-01 18:57:58 -08006871void CodeGeneratorX86_64::Compare32BitValue(CpuRegister dest, int32_t value) {
6872 if (value == 0) {
6873 __ testl(dest, dest);
6874 } else {
6875 __ cmpl(dest, Immediate(value));
6876 }
6877}
6878
6879void CodeGeneratorX86_64::Compare64BitValue(CpuRegister dest, int64_t value) {
6880 if (IsInt<32>(value)) {
6881 if (value == 0) {
6882 __ testq(dest, dest);
6883 } else {
6884 __ cmpq(dest, Immediate(static_cast<int32_t>(value)));
6885 }
6886 } else {
6887 // Value won't fit in an int.
6888 __ cmpq(dest, LiteralInt64Address(value));
6889 }
6890}
6891
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006892void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
6893 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07006894 GenerateIntCompare(lhs_reg, rhs);
6895}
6896
6897void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006898 if (rhs.IsConstant()) {
6899 int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
jessicahandojo4877b792016-09-08 19:49:13 -07006900 Compare32BitValue(lhs, value);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006901 } else if (rhs.IsStackSlot()) {
jessicahandojo4877b792016-09-08 19:49:13 -07006902 __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006903 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07006904 __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006905 }
6906}
6907
6908void CodeGeneratorX86_64::GenerateLongCompare(Location lhs, Location rhs) {
6909 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
6910 if (rhs.IsConstant()) {
6911 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
6912 Compare64BitValue(lhs_reg, value);
6913 } else if (rhs.IsDoubleStackSlot()) {
6914 __ cmpq(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
6915 } else {
6916 __ cmpq(lhs_reg, rhs.AsRegister<CpuRegister>());
6917 }
6918}
6919
6920Address CodeGeneratorX86_64::ArrayAddress(CpuRegister obj,
6921 Location index,
6922 ScaleFactor scale,
6923 uint32_t data_offset) {
6924 return index.IsConstant() ?
6925 Address(obj, (index.GetConstant()->AsIntConstant()->GetValue() << scale) + data_offset) :
6926 Address(obj, index.AsRegister<CpuRegister>(), scale, data_offset);
6927}
6928
Mark Mendellcfa410b2015-05-25 16:02:44 -04006929void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
6930 DCHECK(dest.IsDoubleStackSlot());
6931 if (IsInt<32>(value)) {
6932 // Can move directly as an int32 constant.
6933 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
6934 Immediate(static_cast<int32_t>(value)));
6935 } else {
6936 Load64BitValue(CpuRegister(TMP), value);
6937 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
6938 }
6939}
6940
Mark Mendell9c86b482015-09-18 13:36:07 -04006941/**
6942 * Class to handle late fixup of offsets into constant area.
6943 */
6944class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
6945 public:
6946 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
6947 : codegen_(&codegen), offset_into_constant_area_(offset) {}
6948
6949 protected:
6950 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
6951
6952 CodeGeneratorX86_64* codegen_;
6953
6954 private:
6955 void Process(const MemoryRegion& region, int pos) OVERRIDE {
6956 // Patch the correct offset for the instruction. We use the address of the
6957 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
6958 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
6959 int32_t relative_position = constant_offset - pos;
6960
6961 // Patch in the right value.
6962 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
6963 }
6964
6965 // Location in constant area that the fixup refers to.
6966 size_t offset_into_constant_area_;
6967};
6968
6969/**
6970 t * Class to handle late fixup of offsets to a jump table that will be created in the
6971 * constant area.
6972 */
6973class JumpTableRIPFixup : public RIPFixup {
6974 public:
6975 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
6976 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
6977
6978 void CreateJumpTable() {
6979 X86_64Assembler* assembler = codegen_->GetAssembler();
6980
6981 // Ensure that the reference to the jump table has the correct offset.
6982 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
6983 SetOffset(offset_in_constant_table);
6984
6985 // Compute the offset from the start of the function to this jump table.
6986 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
6987
6988 // Populate the jump table with the correct values for the jump table.
6989 int32_t num_entries = switch_instr_->GetNumEntries();
6990 HBasicBlock* block = switch_instr_->GetBlock();
6991 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
6992 // The value that we want is the target offset - the position of the table.
6993 for (int32_t i = 0; i < num_entries; i++) {
6994 HBasicBlock* b = successors[i];
6995 Label* l = codegen_->GetLabelOf(b);
6996 DCHECK(l->IsBound());
6997 int32_t offset_to_block = l->Position() - current_table_offset;
6998 assembler->AppendInt32(offset_to_block);
6999 }
7000 }
7001
7002 private:
7003 const HPackedSwitch* switch_instr_;
7004};
7005
Mark Mendellf55c3e02015-03-26 21:07:46 -04007006void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
7007 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04007008 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04007009 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
7010 // 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 -04007011 assembler->Align(4, 0);
7012 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04007013
7014 // Populate any jump tables.
7015 for (auto jump_table : fixups_to_jump_tables_) {
7016 jump_table->CreateJumpTable();
7017 }
7018
7019 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04007020 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04007021 }
7022
7023 // And finish up.
7024 CodeGenerator::Finalize(allocator);
7025}
7026
Mark Mendellf55c3e02015-03-26 21:07:46 -04007027Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
7028 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
7029 return Address::RIP(fixup);
7030}
7031
7032Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
7033 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
7034 return Address::RIP(fixup);
7035}
7036
7037Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
7038 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
7039 return Address::RIP(fixup);
7040}
7041
7042Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
7043 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
7044 return Address::RIP(fixup);
7045}
7046
Andreas Gampe85b62f22015-09-09 13:15:38 -07007047// TODO: trg as memory.
7048void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7049 if (!trg.IsValid()) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007050 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007051 return;
7052 }
7053
7054 DCHECK_NE(type, Primitive::kPrimVoid);
7055
7056 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
7057 if (trg.Equals(return_loc)) {
7058 return;
7059 }
7060
7061 // Let the parallel move resolver take care of all of this.
7062 HParallelMove parallel_move(GetGraph()->GetArena());
7063 parallel_move.AddMove(return_loc, trg, type, nullptr);
7064 GetMoveResolver()->EmitNativeCode(&parallel_move);
7065}
7066
Mark Mendell9c86b482015-09-18 13:36:07 -04007067Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
7068 // Create a fixup to be used to create and address the jump table.
7069 JumpTableRIPFixup* table_fixup =
7070 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
7071
7072 // We have to populate the jump tables.
7073 fixups_to_jump_tables_.push_back(table_fixup);
7074 return Address::RIP(table_fixup);
7075}
7076
Mark Mendellea5af682015-10-22 17:35:49 -04007077void CodeGeneratorX86_64::MoveInt64ToAddress(const Address& addr_low,
7078 const Address& addr_high,
7079 int64_t v,
7080 HInstruction* instruction) {
7081 if (IsInt<32>(v)) {
7082 int32_t v_32 = v;
7083 __ movq(addr_low, Immediate(v_32));
7084 MaybeRecordImplicitNullCheck(instruction);
7085 } else {
7086 // Didn't fit in a register. Do it in pieces.
7087 int32_t low_v = Low32Bits(v);
7088 int32_t high_v = High32Bits(v);
7089 __ movl(addr_low, Immediate(low_v));
7090 MaybeRecordImplicitNullCheck(instruction);
7091 __ movl(addr_high, Immediate(high_v));
7092 }
7093}
7094
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007095void CodeGeneratorX86_64::PatchJitRootUse(uint8_t* code,
7096 const uint8_t* roots_data,
7097 const PatchInfo<Label>& info,
7098 uint64_t index_in_table) const {
7099 uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
7100 uintptr_t address =
7101 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
7102 typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
7103 reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
7104 dchecked_integral_cast<uint32_t>(address);
7105}
7106
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007107void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7108 for (const PatchInfo<Label>& info : jit_string_patches_) {
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007109 const auto& it = jit_string_roots_.find(
7110 StringReference(&info.dex_file, dex::StringIndex(info.index)));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007111 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007112 PatchJitRootUse(code, roots_data, info, it->second);
7113 }
7114
7115 for (const PatchInfo<Label>& info : jit_class_patches_) {
7116 const auto& it = jit_class_roots_.find(
7117 TypeReference(&info.dex_file, dex::TypeIndex(info.index)));
7118 DCHECK(it != jit_class_roots_.end());
7119 PatchJitRootUse(code, roots_data, info, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007120 }
7121}
7122
Roland Levillain4d027112015-07-01 15:41:14 +01007123#undef __
7124
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01007125} // namespace x86_64
7126} // namespace art