blob: 8c4374d71e68b47f898207c412ceabe4dc8fbd3a [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"
Vladimir Marko94ec2db2017-09-06 17:21:03 +010020#include "class_table.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010021#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000022#include "compiled_method.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010023#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010024#include "gc/accounting/card_table.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080025#include "intrinsics.h"
26#include "intrinsics_x86_64.h"
Andreas Gamped4901292017-05-30 18:41:34 -070027#include "lock_word.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070028#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070029#include "mirror/class-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "mirror/object_reference.h"
31#include "thread.h"
32#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010033#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010034#include "utils/x86_64/assembler_x86_64.h"
35#include "utils/x86_64/managed_register_x86_64.h"
36
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010037namespace art {
38
Roland Levillain0d5a2812015-11-13 10:07:31 +000039template<class MirrorType>
40class GcRoot;
41
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010042namespace x86_64 {
43
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010044static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010045static constexpr Register kMethodRegisterArgument = RDI;
Vladimir Markof3e0ee22015-12-17 15:23:13 +000046// The compare/jump sequence will generate about (1.5 * num_entries) instructions. A jump
47// table version generates 7 instructions and num_entries literals. Compare/jump sequence will
48// generates less code/data with a small num_entries.
49static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010050
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000051static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000052static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010053
Mark Mendell24f2dfa2015-01-14 19:51:45 -050054static constexpr int kC2ConditionMask = 0x400;
55
Roland Levillain7cbd27f2016-08-11 23:53:33 +010056// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
57#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070058#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64PointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059
Andreas Gampe85b62f22015-09-09 13:15:38 -070060class NullCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000062 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063
Alexandre Rames2ed20af2015-03-06 13:55:35 +000064 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +000065 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000067 if (instruction_->CanThrowIntoCatchBlock()) {
68 // Live registers will be restored in the catch block if caught.
69 SaveLiveRegisters(codegen, instruction_->GetLocations());
70 }
Serban Constantinescuba45db02016-07-12 22:53:02 +010071 x86_64_codegen->InvokeRuntime(kQuickThrowNullPointer,
Roland Levillain0d5a2812015-11-13 10:07:31 +000072 instruction_,
73 instruction_->GetDexPc(),
74 this);
Roland Levillain888d0672015-11-23 18:53:50 +000075 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 }
77
Alexandre Rames8158f282015-08-07 10:26:17 +010078 bool IsFatal() const OVERRIDE { return true; }
79
Alexandre Rames9931f312015-06-19 14:47:01 +010080 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
81
Nicolas Geoffraye5038322014-07-04 09:41:32 +010082 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010083 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
84};
85
Andreas Gampe85b62f22015-09-09 13:15:38 -070086class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000087 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000088 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +000089
Alexandre Rames2ed20af2015-03-06 13:55:35 +000090 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +000091 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000092 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +010093 x86_64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000094 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +000095 }
96
Alexandre Rames8158f282015-08-07 10:26:17 +010097 bool IsFatal() const OVERRIDE { return true; }
98
Alexandre Rames9931f312015-06-19 14:47:01 +010099 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
100
Calin Juravled0d48522014-11-04 16:40:20 +0000101 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000102 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
103};
104
Andreas Gampe85b62f22015-09-09 13:15:38 -0700105class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000106 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000107 DivRemMinusOneSlowPathX86_64(HInstruction* at, Register reg, Primitive::Type type, bool is_div)
108 : SlowPathCode(at), cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000109
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000110 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000111 __ Bind(GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000112 if (type_ == Primitive::kPrimInt) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000113 if (is_div_) {
114 __ negl(cpu_reg_);
115 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400116 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000117 }
118
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000119 } else {
120 DCHECK_EQ(Primitive::kPrimLong, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000121 if (is_div_) {
122 __ negq(cpu_reg_);
123 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400124 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000126 }
Calin Juravled0d48522014-11-04 16:40:20 +0000127 __ jmp(GetExitLabel());
128 }
129
Alexandre Rames9931f312015-06-19 14:47:01 +0100130 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
131
Calin Juravled0d48522014-11-04 16:40:20 +0000132 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000133 const CpuRegister cpu_reg_;
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000134 const Primitive::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000135 const bool is_div_;
136 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000137};
138
Andreas Gampe85b62f22015-09-09 13:15:38 -0700139class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100141 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000142 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000144 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bikb13c65b2017-03-21 20:14:07 -0700145 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000146 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000147 __ Bind(GetEntryLabel());
Aart Bik24b905f2017-04-06 09:59:06 -0700148 SaveLiveRegisters(codegen, locations); // Only saves full width XMM for SIMD.
Serban Constantinescuba45db02016-07-12 22:53:02 +0100149 x86_64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000150 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Aart Bik24b905f2017-04-06 09:59:06 -0700151 RestoreLiveRegisters(codegen, locations); // Only restores full width XMM for SIMD.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100152 if (successor_ == nullptr) {
153 __ jmp(GetReturnLabel());
154 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000155 __ jmp(x86_64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100156 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000157 }
158
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100159 Label* GetReturnLabel() {
160 DCHECK(successor_ == nullptr);
161 return &return_label_;
162 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000163
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100164 HBasicBlock* GetSuccessor() const {
165 return successor_;
166 }
167
Alexandre Rames9931f312015-06-19 14:47:01 +0100168 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
169
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000170 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100171 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000172 Label return_label_;
173
174 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
175};
176
Andreas Gampe85b62f22015-09-09 13:15:38 -0700177class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100178 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100179 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000180 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100181
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000182 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100183 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000184 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000186 if (instruction_->CanThrowIntoCatchBlock()) {
187 // Live registers will be restored in the catch block if caught.
188 SaveLiveRegisters(codegen, instruction_->GetLocations());
189 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400190 // Are we using an array length from memory?
191 HInstruction* array_length = instruction_->InputAt(1);
192 Location length_loc = locations->InAt(1);
193 InvokeRuntimeCallingConvention calling_convention;
194 if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
195 // Load the array length into our temporary.
196 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
197 Location array_loc = array_length->GetLocations()->InAt(0);
198 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
199 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
200 // Check for conflicts with index.
201 if (length_loc.Equals(locations->InAt(0))) {
202 // We know we aren't using parameter 2.
203 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
204 }
205 __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
jessicahandojo4877b792016-09-08 19:49:13 -0700206 if (mirror::kUseStringCompression) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +0100207 __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -0700208 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400209 }
210
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000211 // We're moving two locations to locations that could overlap, so we need a parallel
212 // move resolver.
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000213 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100214 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000215 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100216 Primitive::kPrimInt,
Mark Mendellee8d9712016-07-12 11:13:15 -0400217 length_loc,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100218 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
219 Primitive::kPrimInt);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100220 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
221 ? kQuickThrowStringBounds
222 : kQuickThrowArrayBounds;
223 x86_64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100224 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000225 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100226 }
227
Alexandre Rames8158f282015-08-07 10:26:17 +0100228 bool IsFatal() const OVERRIDE { return true; }
229
Alexandre Rames9931f312015-06-19 14:47:01 +0100230 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
231
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100232 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100233 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
234};
235
Andreas Gampe85b62f22015-09-09 13:15:38 -0700236class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100237 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000238 LoadClassSlowPathX86_64(HLoadClass* cls,
239 HInstruction* at,
240 uint32_t dex_pc,
241 bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000242 : SlowPathCode(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000243 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
244 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100245
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000246 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000247 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000248 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100249 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100250
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000251 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000252
Vladimir Markoea4c1262017-02-06 19:59:33 +0000253 // Custom calling convention: RAX serves as both input and output.
254 __ movl(CpuRegister(RAX), Immediate(cls_->GetTypeIndex().index_));
Serban Constantinescuba45db02016-07-12 22:53:02 +0100255 x86_64_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage : kQuickInitializeType,
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000256 instruction_,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000257 dex_pc_,
258 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000259 if (do_clinit_) {
260 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
261 } else {
262 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
263 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100264
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000265 Location out = locations->Out();
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000266 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000267 if (out.IsValid()) {
268 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000269 x86_64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000270 }
271
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000272 RestoreLiveRegisters(codegen, locations);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000273 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
274 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
275 if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
276 DCHECK(out.IsValid());
277 __ movl(Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false),
278 locations->Out().AsRegister<CpuRegister>());
279 Label* fixup_label = x86_64_codegen->NewTypeBssEntryPatch(cls_);
280 __ Bind(fixup_label);
281 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100282 __ jmp(GetExitLabel());
283 }
284
Alexandre Rames9931f312015-06-19 14:47:01 +0100285 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
286
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100287 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000288 // The class this slow path will load.
289 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100290
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000291 // The dex PC of `at_`.
292 const uint32_t dex_pc_;
293
294 // Whether to initialize the class.
295 const bool do_clinit_;
296
297 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100298};
299
Vladimir Markoaad75c62016-10-03 08:46:48 +0000300class LoadStringSlowPathX86_64 : public SlowPathCode {
301 public:
302 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : SlowPathCode(instruction) {}
303
304 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
305 LocationSummary* locations = instruction_->GetLocations();
306 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
307
308 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
309 __ Bind(GetEntryLabel());
310 SaveLiveRegisters(codegen, locations);
311
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000312 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100313 // Custom calling convention: RAX serves as both input and output.
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000314 __ movl(CpuRegister(RAX), Immediate(string_index.index_));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000315 x86_64_codegen->InvokeRuntime(kQuickResolveString,
316 instruction_,
317 instruction_->GetDexPc(),
318 this);
319 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
320 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
321 RestoreLiveRegisters(codegen, locations);
322
323 // Store the resolved String to the BSS entry.
324 __ movl(Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false),
325 locations->Out().AsRegister<CpuRegister>());
326 Label* fixup_label = x86_64_codegen->NewStringBssEntryPatch(instruction_->AsLoadString());
327 __ Bind(fixup_label);
328
329 __ jmp(GetExitLabel());
330 }
331
332 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
333
334 private:
335 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
336};
337
Andreas Gampe85b62f22015-09-09 13:15:38 -0700338class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000339 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000340 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000341 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000342
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000343 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000344 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100345 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000346 DCHECK(instruction_->IsCheckCast()
347 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000348
Roland Levillain0d5a2812015-11-13 10:07:31 +0000349 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000350 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000351
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000352 if (!is_fatal_) {
353 SaveLiveRegisters(codegen, locations);
354 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000355
356 // We're moving two locations to locations that could overlap, so we need a parallel
357 // move resolver.
358 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800359 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800360 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
361 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800362 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800363 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
364 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000365 if (instruction_->IsInstanceOf()) {
Serban Constantinescuba45db02016-07-12 22:53:02 +0100366 x86_64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800367 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000368 } else {
369 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800370 x86_64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
371 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000372 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000373
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000374 if (!is_fatal_) {
375 if (instruction_->IsInstanceOf()) {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000376 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000377 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000378
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000379 RestoreLiveRegisters(codegen, locations);
380 __ jmp(GetExitLabel());
381 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000382 }
383
Alexandre Rames9931f312015-06-19 14:47:01 +0100384 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
385
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000386 bool IsFatal() const OVERRIDE { return is_fatal_; }
387
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000388 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000389 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000390
391 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
392};
393
Andreas Gampe85b62f22015-09-09 13:15:38 -0700394class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700395 public:
Aart Bik42249c32016-01-07 15:33:50 -0800396 explicit DeoptimizationSlowPathX86_64(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000397 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700398
399 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000400 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700401 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100402 LocationSummary* locations = instruction_->GetLocations();
403 SaveLiveRegisters(codegen, locations);
404 InvokeRuntimeCallingConvention calling_convention;
405 x86_64_codegen->Load32BitValue(
406 CpuRegister(calling_convention.GetRegisterAt(0)),
407 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescuba45db02016-07-12 22:53:02 +0100408 x86_64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100409 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700410 }
411
Alexandre Rames9931f312015-06-19 14:47:01 +0100412 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
413
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700414 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700415 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
416};
417
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100418class ArraySetSlowPathX86_64 : public SlowPathCode {
419 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000420 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100421
422 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
423 LocationSummary* locations = instruction_->GetLocations();
424 __ Bind(GetEntryLabel());
425 SaveLiveRegisters(codegen, locations);
426
427 InvokeRuntimeCallingConvention calling_convention;
428 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
429 parallel_move.AddMove(
430 locations->InAt(0),
431 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
432 Primitive::kPrimNot,
433 nullptr);
434 parallel_move.AddMove(
435 locations->InAt(1),
436 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
437 Primitive::kPrimInt,
438 nullptr);
439 parallel_move.AddMove(
440 locations->InAt(2),
441 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
442 Primitive::kPrimNot,
443 nullptr);
444 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
445
Roland Levillain0d5a2812015-11-13 10:07:31 +0000446 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100447 x86_64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000448 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100449 RestoreLiveRegisters(codegen, locations);
450 __ jmp(GetExitLabel());
451 }
452
453 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86_64"; }
454
455 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100456 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
457};
458
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100459// Slow path marking an object reference `ref` during a read
460// barrier. The field `obj.field` in the object `obj` holding this
461// reference does not get updated by this slow path after marking (see
462// ReadBarrierMarkAndUpdateFieldSlowPathX86_64 below for that).
463//
464// This means that after the execution of this slow path, `ref` will
465// always be up-to-date, but `obj.field` may not; i.e., after the
466// flip, `ref` will be a to-space reference, but `obj.field` will
467// probably still be a from-space reference (unless it gets updated by
468// another thread, or if another thread installed another object
469// reference (different from `ref`) in `obj.field`).
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000470class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode {
471 public:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100472 ReadBarrierMarkSlowPathX86_64(HInstruction* instruction,
473 Location ref,
474 bool unpoison_ref_before_marking)
475 : SlowPathCode(instruction),
476 ref_(ref),
477 unpoison_ref_before_marking_(unpoison_ref_before_marking) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000478 DCHECK(kEmitCompilerReadBarrier);
479 }
480
481 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathX86_64"; }
482
483 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
484 LocationSummary* locations = instruction_->GetLocations();
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100485 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
486 Register ref_reg = ref_cpu_reg.AsRegister();
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000487 DCHECK(locations->CanCall());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100488 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000489 DCHECK(instruction_->IsInstanceFieldGet() ||
490 instruction_->IsStaticFieldGet() ||
491 instruction_->IsArrayGet() ||
Roland Levillain16d9f942016-08-25 17:27:56 +0100492 instruction_->IsArraySet() ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000493 instruction_->IsLoadClass() ||
494 instruction_->IsLoadString() ||
495 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100496 instruction_->IsCheckCast() ||
Roland Levillain0b671c02016-08-19 12:02:34 +0100497 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
498 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000499 << "Unexpected instruction in read barrier marking slow path: "
500 << instruction_->DebugName();
501
502 __ Bind(GetEntryLabel());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100503 if (unpoison_ref_before_marking_) {
Vladimir Marko953437b2016-08-24 08:30:46 +0000504 // Object* ref = ref_addr->AsMirrorPtr()
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100505 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
Vladimir Marko953437b2016-08-24 08:30:46 +0000506 }
Roland Levillain4359e612016-07-20 11:32:19 +0100507 // No need to save live registers; it's taken care of by the
508 // entrypoint. Also, there is no need to update the stack mask,
509 // as this runtime call will not trigger a garbage collection.
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000510 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100511 DCHECK_NE(ref_reg, RSP);
512 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
Roland Levillain02b75802016-07-13 11:54:35 +0100513 // "Compact" slow path, saving two moves.
514 //
515 // Instead of using the standard runtime calling convention (input
516 // and output in R0):
517 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100518 // RDI <- ref
Roland Levillain02b75802016-07-13 11:54:35 +0100519 // RAX <- ReadBarrierMark(RDI)
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100520 // ref <- RAX
Roland Levillain02b75802016-07-13 11:54:35 +0100521 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100522 // we just use rX (the register containing `ref`) as input and output
Roland Levillain02b75802016-07-13 11:54:35 +0100523 // of a dedicated entrypoint:
524 //
525 // rX <- ReadBarrierMarkRegX(rX)
526 //
527 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100528 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
Roland Levillaindec8f632016-07-22 17:10:06 +0100529 // This runtime call does not require a stack map.
530 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000531 __ jmp(GetExitLabel());
532 }
533
534 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100535 // The location (register) of the marked object reference.
536 const Location ref_;
537 // Should the reference in `ref_` be unpoisoned prior to marking it?
538 const bool unpoison_ref_before_marking_;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000539
540 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86_64);
541};
542
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100543// Slow path marking an object reference `ref` during a read barrier,
544// and if needed, atomically updating the field `obj.field` in the
545// object `obj` holding this reference after marking (contrary to
546// ReadBarrierMarkSlowPathX86_64 above, which never tries to update
547// `obj.field`).
548//
549// This means that after the execution of this slow path, both `ref`
550// and `obj.field` will be up-to-date; i.e., after the flip, both will
551// hold the same to-space reference (unless another thread installed
552// another object reference (different from `ref`) in `obj.field`).
553class ReadBarrierMarkAndUpdateFieldSlowPathX86_64 : public SlowPathCode {
554 public:
555 ReadBarrierMarkAndUpdateFieldSlowPathX86_64(HInstruction* instruction,
556 Location ref,
557 CpuRegister obj,
558 const Address& field_addr,
559 bool unpoison_ref_before_marking,
560 CpuRegister temp1,
561 CpuRegister temp2)
562 : SlowPathCode(instruction),
563 ref_(ref),
564 obj_(obj),
565 field_addr_(field_addr),
566 unpoison_ref_before_marking_(unpoison_ref_before_marking),
567 temp1_(temp1),
568 temp2_(temp2) {
569 DCHECK(kEmitCompilerReadBarrier);
570 }
571
572 const char* GetDescription() const OVERRIDE {
573 return "ReadBarrierMarkAndUpdateFieldSlowPathX86_64";
574 }
575
576 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
577 LocationSummary* locations = instruction_->GetLocations();
578 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
579 Register ref_reg = ref_cpu_reg.AsRegister();
580 DCHECK(locations->CanCall());
581 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
582 // This slow path is only used by the UnsafeCASObject intrinsic.
583 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
584 << "Unexpected instruction in read barrier marking and field updating slow path: "
585 << instruction_->DebugName();
586 DCHECK(instruction_->GetLocations()->Intrinsified());
587 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
588
589 __ Bind(GetEntryLabel());
590 if (unpoison_ref_before_marking_) {
591 // Object* ref = ref_addr->AsMirrorPtr()
592 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
593 }
594
595 // Save the old (unpoisoned) reference.
596 __ movl(temp1_, ref_cpu_reg);
597
598 // No need to save live registers; it's taken care of by the
599 // entrypoint. Also, there is no need to update the stack mask,
600 // as this runtime call will not trigger a garbage collection.
601 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
602 DCHECK_NE(ref_reg, RSP);
603 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
604 // "Compact" slow path, saving two moves.
605 //
606 // Instead of using the standard runtime calling convention (input
607 // and output in R0):
608 //
609 // RDI <- ref
610 // RAX <- ReadBarrierMark(RDI)
611 // ref <- RAX
612 //
613 // we just use rX (the register containing `ref`) as input and output
614 // of a dedicated entrypoint:
615 //
616 // rX <- ReadBarrierMarkRegX(rX)
617 //
618 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100619 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100620 // This runtime call does not require a stack map.
621 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
622
623 // If the new reference is different from the old reference,
624 // update the field in the holder (`*field_addr`).
625 //
626 // Note that this field could also hold a different object, if
627 // another thread had concurrently changed it. In that case, the
628 // LOCK CMPXCHGL instruction in the compare-and-set (CAS)
629 // operation below would abort the CAS, leaving the field as-is.
630 NearLabel done;
631 __ cmpl(temp1_, ref_cpu_reg);
632 __ j(kEqual, &done);
633
634 // Update the the holder's field atomically. This may fail if
635 // mutator updates before us, but it's OK. This is achived
636 // using a strong compare-and-set (CAS) operation with relaxed
637 // memory synchronization ordering, where the expected value is
638 // the old reference and the desired value is the new reference.
639 // This operation is implemented with a 32-bit LOCK CMPXLCHG
640 // instruction, which requires the expected value (the old
641 // reference) to be in EAX. Save RAX beforehand, and move the
642 // expected value (stored in `temp1_`) into EAX.
643 __ movq(temp2_, CpuRegister(RAX));
644 __ movl(CpuRegister(RAX), temp1_);
645
646 // Convenience aliases.
647 CpuRegister base = obj_;
648 CpuRegister expected = CpuRegister(RAX);
649 CpuRegister value = ref_cpu_reg;
650
651 bool base_equals_value = (base.AsRegister() == value.AsRegister());
652 Register value_reg = ref_reg;
653 if (kPoisonHeapReferences) {
654 if (base_equals_value) {
655 // If `base` and `value` are the same register location, move
656 // `value_reg` to a temporary register. This way, poisoning
657 // `value_reg` won't invalidate `base`.
658 value_reg = temp1_.AsRegister();
659 __ movl(CpuRegister(value_reg), base);
660 }
661
662 // Check that the register allocator did not assign the location
663 // of `expected` (RAX) to `value` nor to `base`, so that heap
664 // poisoning (when enabled) works as intended below.
665 // - If `value` were equal to `expected`, both references would
666 // be poisoned twice, meaning they would not be poisoned at
667 // all, as heap poisoning uses address negation.
668 // - If `base` were equal to `expected`, poisoning `expected`
669 // would invalidate `base`.
670 DCHECK_NE(value_reg, expected.AsRegister());
671 DCHECK_NE(base.AsRegister(), expected.AsRegister());
672
673 __ PoisonHeapReference(expected);
674 __ PoisonHeapReference(CpuRegister(value_reg));
675 }
676
677 __ LockCmpxchgl(field_addr_, CpuRegister(value_reg));
678
679 // If heap poisoning is enabled, we need to unpoison the values
680 // that were poisoned earlier.
681 if (kPoisonHeapReferences) {
682 if (base_equals_value) {
683 // `value_reg` has been moved to a temporary register, no need
684 // to unpoison it.
685 } else {
686 __ UnpoisonHeapReference(CpuRegister(value_reg));
687 }
688 // No need to unpoison `expected` (RAX), as it is be overwritten below.
689 }
690
691 // Restore RAX.
692 __ movq(CpuRegister(RAX), temp2_);
693
694 __ Bind(&done);
695 __ jmp(GetExitLabel());
696 }
697
698 private:
699 // The location (register) of the marked object reference.
700 const Location ref_;
701 // The register containing the object holding the marked object reference field.
702 const CpuRegister obj_;
703 // The address of the marked reference field. The base of this address must be `obj_`.
704 const Address field_addr_;
705
706 // Should the reference in `ref_` be unpoisoned prior to marking it?
707 const bool unpoison_ref_before_marking_;
708
709 const CpuRegister temp1_;
710 const CpuRegister temp2_;
711
712 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathX86_64);
713};
714
Roland Levillain0d5a2812015-11-13 10:07:31 +0000715// Slow path generating a read barrier for a heap reference.
716class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
717 public:
718 ReadBarrierForHeapReferenceSlowPathX86_64(HInstruction* instruction,
719 Location out,
720 Location ref,
721 Location obj,
722 uint32_t offset,
723 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000724 : SlowPathCode(instruction),
Roland Levillain0d5a2812015-11-13 10:07:31 +0000725 out_(out),
726 ref_(ref),
727 obj_(obj),
728 offset_(offset),
729 index_(index) {
730 DCHECK(kEmitCompilerReadBarrier);
731 // If `obj` is equal to `out` or `ref`, it means the initial
732 // object has been overwritten by (or after) the heap object
733 // reference load to be instrumented, e.g.:
734 //
735 // __ movl(out, Address(out, offset));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000736 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000737 //
738 // In that case, we have lost the information about the original
739 // object, and the emitted read barrier cannot work properly.
740 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
741 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
742}
743
744 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
745 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
746 LocationSummary* locations = instruction_->GetLocations();
747 CpuRegister reg_out = out_.AsRegister<CpuRegister>();
748 DCHECK(locations->CanCall());
749 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_;
Roland Levillain3d312422016-06-23 13:53:42 +0100750 DCHECK(instruction_->IsInstanceFieldGet() ||
751 instruction_->IsStaticFieldGet() ||
752 instruction_->IsArrayGet() ||
753 instruction_->IsInstanceOf() ||
754 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -0700755 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000756 << "Unexpected instruction in read barrier for heap reference slow path: "
757 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000758
759 __ Bind(GetEntryLabel());
760 SaveLiveRegisters(codegen, locations);
761
762 // We may have to change the index's value, but as `index_` is a
763 // constant member (like other "inputs" of this slow path),
764 // introduce a copy of it, `index`.
765 Location index = index_;
766 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100767 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain0d5a2812015-11-13 10:07:31 +0000768 if (instruction_->IsArrayGet()) {
769 // Compute real offset and store it in index_.
770 Register index_reg = index_.AsRegister<CpuRegister>().AsRegister();
771 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
772 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
773 // We are about to change the value of `index_reg` (see the
774 // calls to art::x86_64::X86_64Assembler::shll and
775 // art::x86_64::X86_64Assembler::AddImmediate below), but it
776 // has not been saved by the previous call to
777 // art::SlowPathCode::SaveLiveRegisters, as it is a
778 // callee-save register --
779 // art::SlowPathCode::SaveLiveRegisters does not consider
780 // callee-save registers, as it has been designed with the
781 // assumption that callee-save registers are supposed to be
782 // handled by the called function. So, as a callee-save
783 // register, `index_reg` _would_ eventually be saved onto
784 // the stack, but it would be too late: we would have
785 // changed its value earlier. Therefore, we manually save
786 // it here into another freely available register,
787 // `free_reg`, chosen of course among the caller-save
788 // registers (as a callee-save `free_reg` register would
789 // exhibit the same problem).
790 //
791 // Note we could have requested a temporary register from
792 // the register allocator instead; but we prefer not to, as
793 // this is a slow path, and we know we can find a
794 // caller-save register that is available.
795 Register free_reg = FindAvailableCallerSaveRegister(codegen).AsRegister();
796 __ movl(CpuRegister(free_reg), CpuRegister(index_reg));
797 index_reg = free_reg;
798 index = Location::RegisterLocation(index_reg);
799 } else {
800 // The initial register stored in `index_` has already been
801 // saved in the call to art::SlowPathCode::SaveLiveRegisters
802 // (as it is not a callee-save register), so we can freely
803 // use it.
804 }
805 // Shifting the index value contained in `index_reg` by the
806 // scale factor (2) cannot overflow in practice, as the
807 // runtime is unable to allocate object arrays with a size
808 // larger than 2^26 - 1 (that is, 2^28 - 4 bytes).
809 __ shll(CpuRegister(index_reg), Immediate(TIMES_4));
810 static_assert(
811 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
812 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
813 __ AddImmediate(CpuRegister(index_reg), Immediate(offset_));
814 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100815 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
816 // intrinsics, `index_` is not shifted by a scale factor of 2
817 // (as in the case of ArrayGet), as it is actually an offset
818 // to an object field within an object.
819 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000820 DCHECK(instruction_->GetLocations()->Intrinsified());
821 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
822 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
823 << instruction_->AsInvoke()->GetIntrinsic();
824 DCHECK_EQ(offset_, 0U);
825 DCHECK(index_.IsRegister());
826 }
827 }
828
829 // We're moving two or three locations to locations that could
830 // overlap, so we need a parallel move resolver.
831 InvokeRuntimeCallingConvention calling_convention;
832 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
833 parallel_move.AddMove(ref_,
834 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
835 Primitive::kPrimNot,
836 nullptr);
837 parallel_move.AddMove(obj_,
838 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
839 Primitive::kPrimNot,
840 nullptr);
841 if (index.IsValid()) {
842 parallel_move.AddMove(index,
843 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
844 Primitive::kPrimInt,
845 nullptr);
846 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
847 } else {
848 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
849 __ movl(CpuRegister(calling_convention.GetRegisterAt(2)), Immediate(offset_));
850 }
Serban Constantinescuba45db02016-07-12 22:53:02 +0100851 x86_64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000852 instruction_,
853 instruction_->GetDexPc(),
854 this);
855 CheckEntrypointTypes<
856 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
857 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
858
859 RestoreLiveRegisters(codegen, locations);
860 __ jmp(GetExitLabel());
861 }
862
863 const char* GetDescription() const OVERRIDE {
864 return "ReadBarrierForHeapReferenceSlowPathX86_64";
865 }
866
867 private:
868 CpuRegister FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
869 size_t ref = static_cast<int>(ref_.AsRegister<CpuRegister>().AsRegister());
870 size_t obj = static_cast<int>(obj_.AsRegister<CpuRegister>().AsRegister());
871 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
872 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
873 return static_cast<CpuRegister>(i);
874 }
875 }
876 // We shall never fail to find a free caller-save register, as
877 // there are more than two core caller-save registers on x86-64
878 // (meaning it is possible to find one which is different from
879 // `ref` and `obj`).
880 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
881 LOG(FATAL) << "Could not find a free caller-save register";
882 UNREACHABLE();
883 }
884
Roland Levillain0d5a2812015-11-13 10:07:31 +0000885 const Location out_;
886 const Location ref_;
887 const Location obj_;
888 const uint32_t offset_;
889 // An additional location containing an index to an array.
890 // Only used for HArrayGet and the UnsafeGetObject &
891 // UnsafeGetObjectVolatile intrinsics.
892 const Location index_;
893
894 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86_64);
895};
896
897// Slow path generating a read barrier for a GC root.
898class ReadBarrierForRootSlowPathX86_64 : public SlowPathCode {
899 public:
900 ReadBarrierForRootSlowPathX86_64(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000901 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000902 DCHECK(kEmitCompilerReadBarrier);
903 }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000904
905 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
906 LocationSummary* locations = instruction_->GetLocations();
907 DCHECK(locations->CanCall());
908 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000909 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
910 << "Unexpected instruction in read barrier for GC root slow path: "
911 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000912
913 __ Bind(GetEntryLabel());
914 SaveLiveRegisters(codegen, locations);
915
916 InvokeRuntimeCallingConvention calling_convention;
917 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
918 x86_64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100919 x86_64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000920 instruction_,
921 instruction_->GetDexPc(),
922 this);
923 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
924 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
925
926 RestoreLiveRegisters(codegen, locations);
927 __ jmp(GetExitLabel());
928 }
929
930 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathX86_64"; }
931
932 private:
Roland Levillain0d5a2812015-11-13 10:07:31 +0000933 const Location out_;
934 const Location root_;
935
936 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86_64);
937};
938
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100939#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100940// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
941#define __ down_cast<X86_64Assembler*>(GetAssembler())-> // NOLINT
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100942
Roland Levillain4fa13f62015-07-06 18:11:54 +0100943inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700944 switch (cond) {
945 case kCondEQ: return kEqual;
946 case kCondNE: return kNotEqual;
947 case kCondLT: return kLess;
948 case kCondLE: return kLessEqual;
949 case kCondGT: return kGreater;
950 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700951 case kCondB: return kBelow;
952 case kCondBE: return kBelowEqual;
953 case kCondA: return kAbove;
954 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700955 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100956 LOG(FATAL) << "Unreachable";
957 UNREACHABLE();
958}
959
Aart Bike9f37602015-10-09 11:15:55 -0700960// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100961inline Condition X86_64FPCondition(IfCondition cond) {
962 switch (cond) {
963 case kCondEQ: return kEqual;
964 case kCondNE: return kNotEqual;
965 case kCondLT: return kBelow;
966 case kCondLE: return kBelowEqual;
967 case kCondGT: return kAbove;
968 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700969 default: break; // should not happen
Roland Levillain4fa13f62015-07-06 18:11:54 +0100970 };
971 LOG(FATAL) << "Unreachable";
972 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700973}
974
Vladimir Markodc151b22015-10-15 18:02:30 +0100975HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
976 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100977 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +0000978 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +0100979}
980
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100981void CodeGeneratorX86_64::GenerateStaticOrDirectCall(
982 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800983 // All registers are assumed to be correctly set up.
Vladimir Marko4ee8e292017-06-02 15:39:30 +0000984
Vladimir Marko58155012015-08-19 12:49:41 +0000985 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
986 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100987 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Vladimir Marko58155012015-08-19 12:49:41 +0000988 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100989 uint32_t offset =
990 GetThreadOffset<kX86_64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
991 __ gs()->movq(temp.AsRegister<CpuRegister>(), Address::Absolute(offset, /* no_rip */ true));
Vladimir Marko58155012015-08-19 12:49:41 +0000992 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100993 }
Vladimir Marko58155012015-08-19 12:49:41 +0000994 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +0000995 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +0000996 break;
Vladimir Marko65979462017-05-19 17:25:12 +0100997 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative:
998 DCHECK(GetCompilerOptions().IsBootImage());
999 __ leal(temp.AsRegister<CpuRegister>(),
1000 Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
1001 RecordBootMethodPatch(invoke);
1002 break;
Vladimir Marko58155012015-08-19 12:49:41 +00001003 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
Vladimir Marko2d73f332017-03-16 15:55:49 +00001004 Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress());
Vladimir Marko58155012015-08-19 12:49:41 +00001005 break;
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001006 case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
Vladimir Marko58155012015-08-19 12:49:41 +00001007 __ movq(temp.AsRegister<CpuRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00001008 Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001009 // Bind a new fixup label at the end of the "movl" insn.
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001010 __ Bind(NewMethodBssEntryPatch(
1011 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())));
Vladimir Marko58155012015-08-19 12:49:41 +00001012 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001013 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001014 case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
1015 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
1016 return; // No code pointer retrieval; the runtime performs the call directly.
Vladimir Marko9b688a02015-05-06 14:12:42 +01001017 }
Vladimir Marko58155012015-08-19 12:49:41 +00001018 }
1019
1020 switch (invoke->GetCodePtrLocation()) {
1021 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
1022 __ call(&frame_entry_label_);
1023 break;
Vladimir Marko58155012015-08-19 12:49:41 +00001024 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
1025 // (callee_method + offset_of_quick_compiled_code)()
1026 __ call(Address(callee_method.AsRegister<CpuRegister>(),
1027 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001028 kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +00001029 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001030 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001031 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001032
1033 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001034}
1035
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001036void CodeGeneratorX86_64::GenerateVirtualCall(
1037 HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001038 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
1039 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1040 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001041
1042 // Use the calling convention instead of the location of the receiver, as
1043 // intrinsics may have put the receiver in a different register. In the intrinsics
1044 // slow path, the arguments have been moved to the right place, so here we are
1045 // guaranteed that the receiver is the first register of the calling convention.
1046 InvokeDexCallingConvention calling_convention;
1047 Register receiver = calling_convention.GetRegisterAt(0);
1048
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001049 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
Roland Levillain0d5a2812015-11-13 10:07:31 +00001050 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001051 __ movl(temp, Address(CpuRegister(receiver), class_offset));
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001052 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00001053 // Instead of simply (possibly) unpoisoning `temp` here, we should
1054 // emit a read barrier for the previous class reference load.
1055 // However this is not required in practice, as this is an
1056 // intermediate/temporary reference and because the current
1057 // concurrent copying collector keeps the from-space memory
1058 // intact/accessible until the end of the marking phase (the
1059 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001060 __ MaybeUnpoisonHeapReference(temp);
1061 // temp = temp->GetMethodAt(method_offset);
1062 __ movq(temp, Address(temp, method_offset));
1063 // call temp->GetEntryPoint();
1064 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001065 kX86_64PointerSize).SizeValue()));
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001066 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001067}
1068
Vladimir Marko65979462017-05-19 17:25:12 +01001069void CodeGeneratorX86_64::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) {
1070 boot_image_method_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
1071 invoke->GetTargetMethod().dex_method_index);
1072 __ Bind(&boot_image_method_patches_.back().label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001073}
1074
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001075Label* CodeGeneratorX86_64::NewMethodBssEntryPatch(MethodReference target_method) {
1076 // Add a patch entry and return the label.
1077 method_bss_entry_patches_.emplace_back(*target_method.dex_file, target_method.dex_method_index);
1078 return &method_bss_entry_patches_.back().label;
1079}
1080
Vladimir Marko1998cd02017-01-13 13:02:58 +00001081void CodeGeneratorX86_64::RecordBootTypePatch(HLoadClass* load_class) {
1082 boot_image_type_patches_.emplace_back(load_class->GetDexFile(),
1083 load_class->GetTypeIndex().index_);
1084 __ Bind(&boot_image_type_patches_.back().label);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001085}
1086
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001087Label* CodeGeneratorX86_64::NewTypeBssEntryPatch(HLoadClass* load_class) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001088 type_bss_entry_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
1089 return &type_bss_entry_patches_.back().label;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001090}
1091
Vladimir Marko65979462017-05-19 17:25:12 +01001092void CodeGeneratorX86_64::RecordBootStringPatch(HLoadString* load_string) {
Vladimir Marko65979462017-05-19 17:25:12 +01001093 string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex().index_);
1094 __ Bind(&string_patches_.back().label);
1095}
1096
Vladimir Markoaad75c62016-10-03 08:46:48 +00001097Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) {
1098 DCHECK(!GetCompilerOptions().IsBootImage());
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001099 string_bss_entry_patches_.emplace_back(
1100 load_string->GetDexFile(), load_string->GetStringIndex().index_);
1101 return &string_bss_entry_patches_.back().label;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001102}
1103
Vladimir Markoaad75c62016-10-03 08:46:48 +00001104// The label points to the end of the "movl" or another instruction but the literal offset
1105// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
1106constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
1107
1108template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1109inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
1110 const ArenaDeque<PatchInfo<Label>>& infos,
1111 ArenaVector<LinkerPatch>* linker_patches) {
1112 for (const PatchInfo<Label>& info : infos) {
1113 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
1114 linker_patches->push_back(
1115 Factory(literal_offset, &info.dex_file, info.label.Position(), info.index));
1116 }
1117}
1118
Vladimir Marko58155012015-08-19 12:49:41 +00001119void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
1120 DCHECK(linker_patches->empty());
1121 size_t size =
Vladimir Marko65979462017-05-19 17:25:12 +01001122 boot_image_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001123 method_bss_entry_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00001124 boot_image_type_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01001125 type_bss_entry_patches_.size() +
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001126 string_patches_.size() +
1127 string_bss_entry_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00001128 linker_patches->reserve(size);
Vladimir Marko764d4542017-05-16 10:31:41 +01001129 if (GetCompilerOptions().IsBootImage()) {
Vladimir Marko65979462017-05-19 17:25:12 +01001130 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_,
1131 linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001132 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(boot_image_type_patches_,
1133 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001134 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
Vladimir Marko764d4542017-05-16 10:31:41 +01001135 } else {
Vladimir Marko65979462017-05-19 17:25:12 +01001136 DCHECK(boot_image_method_patches_.empty());
Vladimir Marko94ec2db2017-09-06 17:21:03 +01001137 EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_,
1138 linker_patches);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001139 EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_,
1140 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001141 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001142 EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
1143 linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001144 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
1145 linker_patches);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001146 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_bss_entry_patches_,
1147 linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001148 DCHECK_EQ(size, linker_patches->size());
Vladimir Marko58155012015-08-19 12:49:41 +00001149}
1150
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001151void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001152 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001153}
1154
1155void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001156 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001157}
1158
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001159size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1160 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
1161 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001162}
1163
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001164size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1165 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1166 return kX86_64WordSize;
1167}
1168
1169size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001170 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001171 __ movups(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
Aart Bikb13c65b2017-03-21 20:14:07 -07001172 } else {
1173 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
1174 }
1175 return GetFloatingPointSpillSlotSize();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001176}
1177
1178size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001179 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001180 __ movups(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
Aart Bikb13c65b2017-03-21 20:14:07 -07001181 } else {
1182 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1183 }
1184 return GetFloatingPointSpillSlotSize();
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001185}
1186
Calin Juravle175dc732015-08-25 15:42:32 +01001187void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
1188 HInstruction* instruction,
1189 uint32_t dex_pc,
1190 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001191 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001192 GenerateInvokeRuntime(GetThreadOffset<kX86_64PointerSize>(entrypoint).Int32Value());
1193 if (EntrypointRequiresStackMap(entrypoint)) {
1194 RecordPcInfo(instruction, dex_pc, slow_path);
1195 }
Alexandre Rames8158f282015-08-07 10:26:17 +01001196}
1197
Roland Levillaindec8f632016-07-22 17:10:06 +01001198void CodeGeneratorX86_64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1199 HInstruction* instruction,
1200 SlowPathCode* slow_path) {
1201 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001202 GenerateInvokeRuntime(entry_point_offset);
1203}
1204
1205void CodeGeneratorX86_64::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01001206 __ gs()->call(Address::Absolute(entry_point_offset, /* no_rip */ true));
1207}
1208
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001209static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001210// Use a fake return address register to mimic Quick.
1211static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -04001212CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +00001213 const X86_64InstructionSetFeatures& isa_features,
1214 const CompilerOptions& compiler_options,
1215 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +00001216 : CodeGenerator(graph,
1217 kNumberOfCpuRegisters,
1218 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001219 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001220 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1221 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001222 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001223 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1224 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001225 compiler_options,
1226 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001227 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001228 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001229 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -04001230 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01001231 assembler_(graph->GetArena()),
Mark Mendellf55c3e02015-03-26 21:07:46 -04001232 isa_features_(isa_features),
Vladimir Marko58155012015-08-19 12:49:41 +00001233 constant_area_start_(0),
Vladimir Marko65979462017-05-19 17:25:12 +01001234 boot_image_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001235 method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00001236 boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1237 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko65979462017-05-19 17:25:12 +01001238 string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001239 string_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00001240 jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko65979462017-05-19 17:25:12 +01001241 jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1242 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001243 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
1244}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001245
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001246InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
1247 CodeGeneratorX86_64* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001248 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001249 assembler_(codegen->GetAssembler()),
1250 codegen_(codegen) {}
1251
David Brazdil58282f42016-01-14 12:45:10 +00001252void CodeGeneratorX86_64::SetupBlockedRegisters() const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001253 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001254 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001255
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001256 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001257 blocked_core_registers_[TMP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001258}
1259
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001260static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001261 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001262}
David Srbecky9d8606d2015-04-12 09:35:32 +01001263
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001264static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001265 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001266}
1267
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001268void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001269 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001270 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001271 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -07001272 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001273 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001274
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001275 if (!skip_overflow_check) {
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001276 __ testq(CpuRegister(RAX), Address(
1277 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001278 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001279 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +00001280
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001281 if (HasEmptyFrame()) {
1282 return;
1283 }
1284
Nicolas Geoffray98893962015-01-21 12:32:32 +00001285 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001286 Register reg = kCoreCalleeSaves[i];
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001287 if (allocated_registers_.ContainsCoreRegister(reg)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001288 __ pushq(CpuRegister(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001289 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1290 __ cfi().RelOffset(DWARFReg(reg), 0);
Nicolas Geoffray98893962015-01-21 12:32:32 +00001291 }
1292 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001293
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001294 int adjust = GetFrameSize() - GetCoreSpillSize();
1295 __ subq(CpuRegister(RSP), Immediate(adjust));
1296 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001297 uint32_t xmm_spill_location = GetFpuSpillStart();
1298 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001299
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001300 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1301 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001302 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1303 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
1304 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001305 }
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001306 }
1307
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01001308 // Save the current method if we need it. Note that we do not
1309 // do this in HCurrentMethod, as the instruction might have been removed
1310 // in the SSA graph.
1311 if (RequiresCurrentMethod()) {
1312 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
1313 CpuRegister(kMethodRegisterArgument));
1314 }
Nicolas Geoffrayf7893532017-06-15 12:34:36 +01001315
1316 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1317 // Initialize should_deoptimize flag to 0.
1318 __ movl(Address(CpuRegister(RSP), GetStackOffsetOfShouldDeoptimizeFlag()), Immediate(0));
1319 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001320}
1321
1322void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001323 __ cfi().RememberState();
1324 if (!HasEmptyFrame()) {
1325 uint32_t xmm_spill_location = GetFpuSpillStart();
1326 size_t xmm_spill_slot_size = GetFloatingPointSpillSlotSize();
1327 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1328 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1329 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1330 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
1331 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
1332 }
1333 }
1334
1335 int adjust = GetFrameSize() - GetCoreSpillSize();
1336 __ addq(CpuRegister(RSP), Immediate(adjust));
1337 __ cfi().AdjustCFAOffset(-adjust);
1338
1339 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1340 Register reg = kCoreCalleeSaves[i];
1341 if (allocated_registers_.ContainsCoreRegister(reg)) {
1342 __ popq(CpuRegister(reg));
1343 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1344 __ cfi().Restore(DWARFReg(reg));
1345 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001346 }
1347 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001348 __ ret();
1349 __ cfi().RestoreState();
1350 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001351}
1352
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001353void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
1354 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001355}
1356
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001357void CodeGeneratorX86_64::Move(Location destination, Location source) {
1358 if (source.Equals(destination)) {
1359 return;
1360 }
1361 if (destination.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001362 CpuRegister dest = destination.AsRegister<CpuRegister>();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001363 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001364 __ movq(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001365 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001366 __ movd(dest, source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001367 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001368 __ movl(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
1369 } else if (source.IsConstant()) {
1370 HConstant* constant = source.GetConstant();
1371 if (constant->IsLongConstant()) {
1372 Load64BitValue(dest, constant->AsLongConstant()->GetValue());
1373 } else {
1374 Load32BitValue(dest, GetInt32ValueOf(constant));
1375 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001376 } else {
1377 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001378 __ movq(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001379 }
1380 } else if (destination.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001381 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001382 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001383 __ movd(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001384 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001385 __ movaps(dest, source.AsFpuRegister<XmmRegister>());
1386 } else if (source.IsConstant()) {
1387 HConstant* constant = source.GetConstant();
1388 int64_t value = CodeGenerator::GetInt64ValueOf(constant);
1389 if (constant->IsFloatConstant()) {
1390 Load32BitValue(dest, static_cast<int32_t>(value));
1391 } else {
1392 Load64BitValue(dest, value);
1393 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001394 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001395 __ movss(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001396 } else {
1397 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001398 __ movsd(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001399 }
1400 } else if (destination.IsStackSlot()) {
1401 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001402 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001403 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001404 } else if (source.IsFpuRegister()) {
1405 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001406 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001407 } else if (source.IsConstant()) {
1408 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001409 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001410 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001411 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001412 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001413 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1414 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001415 }
1416 } else {
1417 DCHECK(destination.IsDoubleStackSlot());
1418 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001419 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001420 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001421 } else if (source.IsFpuRegister()) {
1422 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001423 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001424 } else if (source.IsConstant()) {
1425 HConstant* constant = source.GetConstant();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001426 DCHECK(constant->IsLongConstant() || constant->IsDoubleConstant());
1427 int64_t value = GetInt64ValueOf(constant);
Mark Mendellcfa410b2015-05-25 16:02:44 -04001428 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001429 } else {
1430 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001431 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1432 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001433 }
1434 }
1435}
1436
Calin Juravle175dc732015-08-25 15:42:32 +01001437void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
1438 DCHECK(location.IsRegister());
1439 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
1440}
1441
Calin Juravlee460d1d2015-09-29 04:52:17 +01001442void CodeGeneratorX86_64::MoveLocation(
1443 Location dst, Location src, Primitive::Type dst_type ATTRIBUTE_UNUSED) {
1444 Move(dst, src);
1445}
1446
1447void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1448 if (location.IsRegister()) {
1449 locations->AddTemp(location);
1450 } else {
1451 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1452 }
1453}
1454
David Brazdilfc6a86a2015-06-26 10:33:45 +00001455void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001456 DCHECK(!successor->IsExitBlock());
1457
1458 HBasicBlock* block = got->GetBlock();
1459 HInstruction* previous = got->GetPrevious();
1460
1461 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001462 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001463 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1464 return;
1465 }
1466
1467 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1468 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1469 }
1470 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001471 __ jmp(codegen_->GetLabelOf(successor));
1472 }
1473}
1474
David Brazdilfc6a86a2015-06-26 10:33:45 +00001475void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1476 got->SetLocations(nullptr);
1477}
1478
1479void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1480 HandleGoto(got, got->GetSuccessor());
1481}
1482
1483void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1484 try_boundary->SetLocations(nullptr);
1485}
1486
1487void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1488 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1489 if (!successor->IsExitBlock()) {
1490 HandleGoto(try_boundary, successor);
1491 }
1492}
1493
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001494void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1495 exit->SetLocations(nullptr);
1496}
1497
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001498void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001499}
1500
Mark Mendell152408f2015-12-31 12:28:50 -05001501template<class LabelType>
Mark Mendellc4701932015-04-10 13:18:51 -04001502void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
Mark Mendell152408f2015-12-31 12:28:50 -05001503 LabelType* true_label,
1504 LabelType* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001505 if (cond->IsFPConditionTrueIfNaN()) {
1506 __ j(kUnordered, true_label);
1507 } else if (cond->IsFPConditionFalseIfNaN()) {
1508 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001509 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001510 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001511}
1512
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001513void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition) {
Mark Mendellc4701932015-04-10 13:18:51 -04001514 LocationSummary* locations = condition->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001515
Mark Mendellc4701932015-04-10 13:18:51 -04001516 Location left = locations->InAt(0);
1517 Location right = locations->InAt(1);
Mark Mendellc4701932015-04-10 13:18:51 -04001518 Primitive::Type type = condition->InputAt(0)->GetType();
1519 switch (type) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001520 case Primitive::kPrimBoolean:
1521 case Primitive::kPrimByte:
1522 case Primitive::kPrimChar:
1523 case Primitive::kPrimShort:
1524 case Primitive::kPrimInt:
1525 case Primitive::kPrimNot: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001526 codegen_->GenerateIntCompare(left, right);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001527 break;
1528 }
Mark Mendellc4701932015-04-10 13:18:51 -04001529 case Primitive::kPrimLong: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001530 codegen_->GenerateLongCompare(left, right);
Mark Mendellc4701932015-04-10 13:18:51 -04001531 break;
1532 }
1533 case Primitive::kPrimFloat: {
1534 if (right.IsFpuRegister()) {
1535 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1536 } else if (right.IsConstant()) {
1537 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1538 codegen_->LiteralFloatAddress(
1539 right.GetConstant()->AsFloatConstant()->GetValue()));
1540 } else {
1541 DCHECK(right.IsStackSlot());
1542 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1543 Address(CpuRegister(RSP), right.GetStackIndex()));
1544 }
Mark Mendellc4701932015-04-10 13:18:51 -04001545 break;
1546 }
1547 case Primitive::kPrimDouble: {
1548 if (right.IsFpuRegister()) {
1549 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1550 } else if (right.IsConstant()) {
1551 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1552 codegen_->LiteralDoubleAddress(
1553 right.GetConstant()->AsDoubleConstant()->GetValue()));
1554 } else {
1555 DCHECK(right.IsDoubleStackSlot());
1556 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1557 Address(CpuRegister(RSP), right.GetStackIndex()));
1558 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001559 break;
1560 }
1561 default:
1562 LOG(FATAL) << "Unexpected condition type " << type;
1563 }
1564}
1565
1566template<class LabelType>
1567void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
1568 LabelType* true_target_in,
1569 LabelType* false_target_in) {
1570 // Generated branching requires both targets to be explicit. If either of the
1571 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1572 LabelType fallthrough_target;
1573 LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1574 LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1575
1576 // Generate the comparison to set the CC.
1577 GenerateCompareTest(condition);
1578
1579 // Now generate the correct jump(s).
1580 Primitive::Type type = condition->InputAt(0)->GetType();
1581 switch (type) {
1582 case Primitive::kPrimLong: {
1583 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
1584 break;
1585 }
1586 case Primitive::kPrimFloat: {
1587 GenerateFPJumps(condition, true_target, false_target);
1588 break;
1589 }
1590 case Primitive::kPrimDouble: {
Mark Mendellc4701932015-04-10 13:18:51 -04001591 GenerateFPJumps(condition, true_target, false_target);
1592 break;
1593 }
1594 default:
1595 LOG(FATAL) << "Unexpected condition type " << type;
1596 }
1597
David Brazdil0debae72015-11-12 18:37:00 +00001598 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001599 __ jmp(false_target);
1600 }
David Brazdil0debae72015-11-12 18:37:00 +00001601
1602 if (fallthrough_target.IsLinked()) {
1603 __ Bind(&fallthrough_target);
1604 }
Mark Mendellc4701932015-04-10 13:18:51 -04001605}
1606
David Brazdil0debae72015-11-12 18:37:00 +00001607static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1608 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1609 // are set only strictly before `branch`. We can't use the eflags on long
1610 // conditions if they are materialized due to the complex branching.
1611 return cond->IsCondition() &&
1612 cond->GetNext() == branch &&
1613 !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType());
1614}
1615
Mark Mendell152408f2015-12-31 12:28:50 -05001616template<class LabelType>
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001617void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001618 size_t condition_input_index,
Mark Mendell152408f2015-12-31 12:28:50 -05001619 LabelType* true_target,
1620 LabelType* false_target) {
David Brazdil0debae72015-11-12 18:37:00 +00001621 HInstruction* cond = instruction->InputAt(condition_input_index);
1622
1623 if (true_target == nullptr && false_target == nullptr) {
1624 // Nothing to do. The code always falls through.
1625 return;
1626 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001627 // Constant condition, statically compared against "true" (integer value 1).
1628 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001629 if (true_target != nullptr) {
1630 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001631 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001632 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001633 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001634 if (false_target != nullptr) {
1635 __ jmp(false_target);
1636 }
1637 }
1638 return;
1639 }
1640
1641 // The following code generates these patterns:
1642 // (1) true_target == nullptr && false_target != nullptr
1643 // - opposite condition true => branch to false_target
1644 // (2) true_target != nullptr && false_target == nullptr
1645 // - condition true => branch to true_target
1646 // (3) true_target != nullptr && false_target != nullptr
1647 // - condition true => branch to true_target
1648 // - branch to false_target
1649 if (IsBooleanValueOrMaterializedCondition(cond)) {
1650 if (AreEflagsSetFrom(cond, instruction)) {
1651 if (true_target == nullptr) {
1652 __ j(X86_64IntegerCondition(cond->AsCondition()->GetOppositeCondition()), false_target);
1653 } else {
1654 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
1655 }
1656 } else {
1657 // Materialized condition, compare against 0.
1658 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
1659 if (lhs.IsRegister()) {
1660 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1661 } else {
1662 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
1663 }
1664 if (true_target == nullptr) {
1665 __ j(kEqual, false_target);
1666 } else {
1667 __ j(kNotEqual, true_target);
1668 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001669 }
1670 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001671 // Condition has not been materialized, use its inputs as the
1672 // comparison and its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001673 HCondition* condition = cond->AsCondition();
Mark Mendellc4701932015-04-10 13:18:51 -04001674
David Brazdil0debae72015-11-12 18:37:00 +00001675 // If this is a long or FP comparison that has been folded into
1676 // the HCondition, generate the comparison directly.
1677 Primitive::Type type = condition->InputAt(0)->GetType();
1678 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1679 GenerateCompareTestAndBranch(condition, true_target, false_target);
1680 return;
1681 }
1682
1683 Location lhs = condition->GetLocations()->InAt(0);
1684 Location rhs = condition->GetLocations()->InAt(1);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001685 codegen_->GenerateIntCompare(lhs, rhs);
David Brazdil0debae72015-11-12 18:37:00 +00001686 if (true_target == nullptr) {
1687 __ j(X86_64IntegerCondition(condition->GetOppositeCondition()), false_target);
1688 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001689 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001690 }
Dave Allison20dfc792014-06-16 20:44:29 -07001691 }
David Brazdil0debae72015-11-12 18:37:00 +00001692
1693 // If neither branch falls through (case 3), the conditional branch to `true_target`
1694 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1695 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001696 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001697 }
1698}
1699
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001700void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001701 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1702 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001703 locations->SetInAt(0, Location::Any());
1704 }
1705}
1706
1707void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001708 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1709 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1710 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1711 nullptr : codegen_->GetLabelOf(true_successor);
1712 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1713 nullptr : codegen_->GetLabelOf(false_successor);
1714 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001715}
1716
1717void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
1718 LocationSummary* locations = new (GetGraph()->GetArena())
1719 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01001720 InvokeRuntimeCallingConvention calling_convention;
1721 RegisterSet caller_saves = RegisterSet::Empty();
1722 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1723 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00001724 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001725 locations->SetInAt(0, Location::Any());
1726 }
1727}
1728
1729void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001730 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathX86_64>(deoptimize);
David Brazdil74eb1b22015-12-14 11:44:01 +00001731 GenerateTestAndBranch<Label>(deoptimize,
1732 /* condition_input_index */ 0,
1733 slow_path->GetEntryLabel(),
1734 /* false_target */ nullptr);
1735}
1736
Mingyao Yang063fc772016-08-02 11:02:54 -07001737void LocationsBuilderX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1738 LocationSummary* locations = new (GetGraph()->GetArena())
1739 LocationSummary(flag, LocationSummary::kNoCall);
1740 locations->SetOut(Location::RequiresRegister());
1741}
1742
1743void InstructionCodeGeneratorX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1744 __ movl(flag->GetLocations()->Out().AsRegister<CpuRegister>(),
1745 Address(CpuRegister(RSP), codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
1746}
1747
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001748static bool SelectCanUseCMOV(HSelect* select) {
1749 // There are no conditional move instructions for XMMs.
1750 if (Primitive::IsFloatingPointType(select->GetType())) {
1751 return false;
1752 }
1753
1754 // A FP condition doesn't generate the single CC that we need.
1755 HInstruction* condition = select->GetCondition();
1756 if (condition->IsCondition() &&
1757 Primitive::IsFloatingPointType(condition->InputAt(0)->GetType())) {
1758 return false;
1759 }
1760
1761 // We can generate a CMOV for this Select.
1762 return true;
1763}
1764
David Brazdil74eb1b22015-12-14 11:44:01 +00001765void LocationsBuilderX86_64::VisitSelect(HSelect* select) {
1766 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1767 if (Primitive::IsFloatingPointType(select->GetType())) {
1768 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001769 locations->SetInAt(1, Location::Any());
David Brazdil74eb1b22015-12-14 11:44:01 +00001770 } else {
1771 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001772 if (SelectCanUseCMOV(select)) {
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001773 if (select->InputAt(1)->IsConstant()) {
1774 locations->SetInAt(1, Location::RequiresRegister());
1775 } else {
1776 locations->SetInAt(1, Location::Any());
1777 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001778 } else {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001779 locations->SetInAt(1, Location::Any());
1780 }
David Brazdil74eb1b22015-12-14 11:44:01 +00001781 }
1782 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1783 locations->SetInAt(2, Location::RequiresRegister());
1784 }
1785 locations->SetOut(Location::SameAsFirstInput());
1786}
1787
1788void InstructionCodeGeneratorX86_64::VisitSelect(HSelect* select) {
1789 LocationSummary* locations = select->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001790 if (SelectCanUseCMOV(select)) {
1791 // If both the condition and the source types are integer, we can generate
1792 // a CMOV to implement Select.
1793 CpuRegister value_false = locations->InAt(0).AsRegister<CpuRegister>();
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001794 Location value_true_loc = locations->InAt(1);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001795 DCHECK(locations->InAt(0).Equals(locations->Out()));
1796
1797 HInstruction* select_condition = select->GetCondition();
1798 Condition cond = kNotEqual;
1799
1800 // Figure out how to test the 'condition'.
1801 if (select_condition->IsCondition()) {
1802 HCondition* condition = select_condition->AsCondition();
1803 if (!condition->IsEmittedAtUseSite()) {
1804 // This was a previously materialized condition.
1805 // Can we use the existing condition code?
1806 if (AreEflagsSetFrom(condition, select)) {
1807 // Materialization was the previous instruction. Condition codes are right.
1808 cond = X86_64IntegerCondition(condition->GetCondition());
1809 } else {
1810 // No, we have to recreate the condition code.
1811 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1812 __ testl(cond_reg, cond_reg);
1813 }
1814 } else {
1815 GenerateCompareTest(condition);
1816 cond = X86_64IntegerCondition(condition->GetCondition());
1817 }
1818 } else {
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001819 // Must be a Boolean condition, which needs to be compared to 0.
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001820 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1821 __ testl(cond_reg, cond_reg);
1822 }
1823
1824 // If the condition is true, overwrite the output, which already contains false.
1825 // Generate the correct sized CMOV.
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001826 bool is_64_bit = Primitive::Is64BitType(select->GetType());
1827 if (value_true_loc.IsRegister()) {
1828 __ cmov(cond, value_false, value_true_loc.AsRegister<CpuRegister>(), is_64_bit);
1829 } else {
1830 __ cmov(cond,
1831 value_false,
1832 Address(CpuRegister(RSP), value_true_loc.GetStackIndex()), is_64_bit);
1833 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001834 } else {
1835 NearLabel false_target;
1836 GenerateTestAndBranch<NearLabel>(select,
1837 /* condition_input_index */ 2,
1838 /* true_target */ nullptr,
1839 &false_target);
1840 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1841 __ Bind(&false_target);
1842 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001843}
1844
David Srbecky0cf44932015-12-09 14:09:59 +00001845void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1846 new (GetGraph()->GetArena()) LocationSummary(info);
1847}
1848
David Srbeckyd28f4a02016-03-14 17:14:24 +00001849void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo*) {
1850 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001851}
1852
1853void CodeGeneratorX86_64::GenerateNop() {
1854 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001855}
1856
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001857void LocationsBuilderX86_64::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001858 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001859 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001860 // Handle the long/FP comparisons made in instruction simplification.
1861 switch (cond->InputAt(0)->GetType()) {
1862 case Primitive::kPrimLong:
1863 locations->SetInAt(0, Location::RequiresRegister());
1864 locations->SetInAt(1, Location::Any());
1865 break;
1866 case Primitive::kPrimFloat:
1867 case Primitive::kPrimDouble:
1868 locations->SetInAt(0, Location::RequiresFpuRegister());
1869 locations->SetInAt(1, Location::Any());
1870 break;
1871 default:
1872 locations->SetInAt(0, Location::RequiresRegister());
1873 locations->SetInAt(1, Location::Any());
1874 break;
1875 }
David Brazdilb3e773e2016-01-26 11:28:37 +00001876 if (!cond->IsEmittedAtUseSite()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001877 locations->SetOut(Location::RequiresRegister());
1878 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001879}
1880
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001881void InstructionCodeGeneratorX86_64::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001882 if (cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04001883 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001884 }
Mark Mendellc4701932015-04-10 13:18:51 -04001885
1886 LocationSummary* locations = cond->GetLocations();
1887 Location lhs = locations->InAt(0);
1888 Location rhs = locations->InAt(1);
1889 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Mark Mendell152408f2015-12-31 12:28:50 -05001890 NearLabel true_label, false_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001891
1892 switch (cond->InputAt(0)->GetType()) {
1893 default:
1894 // Integer case.
1895
1896 // Clear output register: setcc only sets the low byte.
1897 __ xorl(reg, reg);
1898
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001899 codegen_->GenerateIntCompare(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::kPrimLong:
1903 // Clear output register: setcc only sets the low byte.
1904 __ xorl(reg, reg);
1905
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001906 codegen_->GenerateLongCompare(lhs, rhs);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001907 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001908 return;
1909 case Primitive::kPrimFloat: {
1910 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1911 if (rhs.IsConstant()) {
1912 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
1913 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
1914 } else if (rhs.IsStackSlot()) {
1915 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1916 } else {
1917 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1918 }
1919 GenerateFPJumps(cond, &true_label, &false_label);
1920 break;
1921 }
1922 case Primitive::kPrimDouble: {
1923 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
1924 if (rhs.IsConstant()) {
1925 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
1926 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
1927 } else if (rhs.IsDoubleStackSlot()) {
1928 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
1929 } else {
1930 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
1931 }
1932 GenerateFPJumps(cond, &true_label, &false_label);
1933 break;
1934 }
1935 }
1936
1937 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001938 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001939
Roland Levillain4fa13f62015-07-06 18:11:54 +01001940 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001941 __ Bind(&false_label);
1942 __ xorl(reg, reg);
1943 __ jmp(&done_label);
1944
Roland Levillain4fa13f62015-07-06 18:11:54 +01001945 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001946 __ Bind(&true_label);
1947 __ movl(reg, Immediate(1));
1948 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001949}
1950
1951void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001952 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001953}
1954
1955void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001956 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001957}
1958
1959void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001960 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001961}
1962
1963void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001964 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001965}
1966
1967void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001968 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001969}
1970
1971void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001972 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001973}
1974
1975void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001976 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001977}
1978
1979void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001980 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001981}
1982
1983void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001984 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001985}
1986
1987void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001988 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001989}
1990
1991void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001992 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001993}
1994
1995void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001996 HandleCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001997}
1998
Aart Bike9f37602015-10-09 11:15:55 -07001999void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002000 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002001}
2002
2003void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002004 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002005}
2006
2007void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002008 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002009}
2010
2011void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002012 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002013}
2014
2015void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002016 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002017}
2018
2019void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002020 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002021}
2022
2023void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002024 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002025}
2026
2027void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002028 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002029}
2030
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002031void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002032 LocationSummary* locations =
2033 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002034 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002035 case Primitive::kPrimBoolean:
2036 case Primitive::kPrimByte:
2037 case Primitive::kPrimShort:
2038 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002039 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00002040 case Primitive::kPrimLong: {
2041 locations->SetInAt(0, Location::RequiresRegister());
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(), Location::kNoOutputOverlap);
2044 break;
2045 }
2046 case Primitive::kPrimFloat:
2047 case Primitive::kPrimDouble: {
2048 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04002049 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00002050 locations->SetOut(Location::RequiresRegister());
2051 break;
2052 }
2053 default:
2054 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2055 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002056}
2057
2058void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002059 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002060 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002061 Location left = locations->InAt(0);
2062 Location right = locations->InAt(1);
2063
Mark Mendell0c9497d2015-08-21 09:30:05 -04002064 NearLabel less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00002065 Primitive::Type type = compare->InputAt(0)->GetType();
Aart Bika19616e2016-02-01 18:57:58 -08002066 Condition less_cond = kLess;
2067
Calin Juravleddb7df22014-11-25 20:56:51 +00002068 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002069 case Primitive::kPrimBoolean:
2070 case Primitive::kPrimByte:
2071 case Primitive::kPrimShort:
2072 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002073 case Primitive::kPrimInt: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002074 codegen_->GenerateIntCompare(left, right);
Aart Bika19616e2016-02-01 18:57:58 -08002075 break;
2076 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002077 case Primitive::kPrimLong: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002078 codegen_->GenerateLongCompare(left, right);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002079 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00002080 }
2081 case Primitive::kPrimFloat: {
Mark Mendell40741f32015-04-20 22:10:34 -04002082 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2083 if (right.IsConstant()) {
2084 float value = right.GetConstant()->AsFloatConstant()->GetValue();
2085 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
2086 } else if (right.IsStackSlot()) {
2087 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2088 } else {
2089 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
2090 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002091 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002092 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002093 break;
2094 }
2095 case Primitive::kPrimDouble: {
Mark Mendell40741f32015-04-20 22:10:34 -04002096 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2097 if (right.IsConstant()) {
2098 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
2099 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
2100 } else if (right.IsDoubleStackSlot()) {
2101 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2102 } else {
2103 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
2104 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002105 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002106 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002107 break;
2108 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002109 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002110 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002111 }
Aart Bika19616e2016-02-01 18:57:58 -08002112
Calin Juravleddb7df22014-11-25 20:56:51 +00002113 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00002114 __ j(kEqual, &done);
Aart Bika19616e2016-02-01 18:57:58 -08002115 __ j(less_cond, &less);
Calin Juravlefd861242014-11-25 20:56:51 +00002116
Calin Juravle91debbc2014-11-26 19:01:09 +00002117 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00002118 __ movl(out, Immediate(1));
2119 __ jmp(&done);
2120
2121 __ Bind(&less);
2122 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002123
2124 __ Bind(&done);
2125}
2126
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002127void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002128 LocationSummary* locations =
2129 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002130 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002131}
2132
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002133void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002134 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002135}
2136
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002137void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
2138 LocationSummary* locations =
2139 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2140 locations->SetOut(Location::ConstantLocation(constant));
2141}
2142
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002143void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002144 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002145}
2146
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002147void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002148 LocationSummary* locations =
2149 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002150 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002151}
2152
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002153void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002154 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002155}
2156
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002157void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
2158 LocationSummary* locations =
2159 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2160 locations->SetOut(Location::ConstantLocation(constant));
2161}
2162
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002163void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002164 // Will be generated at use site.
2165}
2166
2167void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
2168 LocationSummary* locations =
2169 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2170 locations->SetOut(Location::ConstantLocation(constant));
2171}
2172
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002173void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
2174 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002175 // Will be generated at use site.
2176}
2177
Igor Murashkind01745e2017-04-05 16:40:31 -07002178void LocationsBuilderX86_64::VisitConstructorFence(HConstructorFence* constructor_fence) {
2179 constructor_fence->SetLocations(nullptr);
2180}
2181
2182void InstructionCodeGeneratorX86_64::VisitConstructorFence(
2183 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
2184 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2185}
2186
Calin Juravle27df7582015-04-17 19:12:31 +01002187void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2188 memory_barrier->SetLocations(nullptr);
2189}
2190
2191void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00002192 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01002193}
2194
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002195void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
2196 ret->SetLocations(nullptr);
2197}
2198
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002199void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002200 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002201}
2202
2203void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002204 LocationSummary* locations =
2205 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002206 switch (ret->InputAt(0)->GetType()) {
2207 case Primitive::kPrimBoolean:
2208 case Primitive::kPrimByte:
2209 case Primitive::kPrimChar:
2210 case Primitive::kPrimShort:
2211 case Primitive::kPrimInt:
2212 case Primitive::kPrimNot:
2213 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002214 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002215 break;
2216
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002217 case Primitive::kPrimFloat:
2218 case Primitive::kPrimDouble:
Mark Mendell40741f32015-04-20 22:10:34 -04002219 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002220 break;
2221
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002222 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002223 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002224 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002225}
2226
2227void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
2228 if (kIsDebugBuild) {
2229 switch (ret->InputAt(0)->GetType()) {
2230 case Primitive::kPrimBoolean:
2231 case Primitive::kPrimByte:
2232 case Primitive::kPrimChar:
2233 case Primitive::kPrimShort:
2234 case Primitive::kPrimInt:
2235 case Primitive::kPrimNot:
2236 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002237 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002238 break;
2239
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002240 case Primitive::kPrimFloat:
2241 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002242 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002243 XMM0);
2244 break;
2245
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002246 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002247 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002248 }
2249 }
2250 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002251}
2252
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002253Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
2254 switch (type) {
2255 case Primitive::kPrimBoolean:
2256 case Primitive::kPrimByte:
2257 case Primitive::kPrimChar:
2258 case Primitive::kPrimShort:
2259 case Primitive::kPrimInt:
2260 case Primitive::kPrimNot:
2261 case Primitive::kPrimLong:
2262 return Location::RegisterLocation(RAX);
2263
2264 case Primitive::kPrimVoid:
2265 return Location::NoLocation();
2266
2267 case Primitive::kPrimDouble:
2268 case Primitive::kPrimFloat:
2269 return Location::FpuRegisterLocation(XMM0);
2270 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002271
2272 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002273}
2274
2275Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
2276 return Location::RegisterLocation(kMethodRegisterArgument);
2277}
2278
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002279Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002280 switch (type) {
2281 case Primitive::kPrimBoolean:
2282 case Primitive::kPrimByte:
2283 case Primitive::kPrimChar:
2284 case Primitive::kPrimShort:
2285 case Primitive::kPrimInt:
2286 case Primitive::kPrimNot: {
2287 uint32_t index = gp_index_++;
2288 stack_index_++;
2289 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002290 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002291 } else {
2292 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2293 }
2294 }
2295
2296 case Primitive::kPrimLong: {
2297 uint32_t index = gp_index_;
2298 stack_index_ += 2;
2299 if (index < calling_convention.GetNumberOfRegisters()) {
2300 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002301 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002302 } else {
2303 gp_index_ += 2;
2304 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2305 }
2306 }
2307
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002308 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002309 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002310 stack_index_++;
2311 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002312 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002313 } else {
2314 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2315 }
2316 }
2317
2318 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002319 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002320 stack_index_ += 2;
2321 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002322 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002323 } else {
2324 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2325 }
2326 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002327
2328 case Primitive::kPrimVoid:
2329 LOG(FATAL) << "Unexpected parameter type " << type;
2330 break;
2331 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00002332 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002333}
2334
Calin Juravle175dc732015-08-25 15:42:32 +01002335void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2336 // The trampoline uses the same calling convention as dex calling conventions,
2337 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2338 // the method_idx.
2339 HandleInvoke(invoke);
2340}
2341
2342void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2343 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2344}
2345
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002346void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002347 // Explicit clinit checks triggered by static invokes must have been pruned by
2348 // art::PrepareForRegisterAllocation.
2349 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002350
Mark Mendellfb8d2792015-03-31 22:16:59 -04002351 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002352 if (intrinsic.TryDispatch(invoke)) {
2353 return;
2354 }
2355
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002356 HandleInvoke(invoke);
2357}
2358
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002359static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
2360 if (invoke->GetLocations()->Intrinsified()) {
2361 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
2362 intrinsic.Dispatch(invoke);
2363 return true;
2364 }
2365 return false;
2366}
2367
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002368void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002369 // Explicit clinit checks triggered by static invokes must have been pruned by
2370 // art::PrepareForRegisterAllocation.
2371 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002372
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002373 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2374 return;
2375 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002376
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002377 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002378 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002379 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002380}
2381
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002382void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002383 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002384 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002385}
2386
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002387void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04002388 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002389 if (intrinsic.TryDispatch(invoke)) {
2390 return;
2391 }
2392
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002393 HandleInvoke(invoke);
2394}
2395
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002396void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002397 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2398 return;
2399 }
2400
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002401 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002402 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002403}
2404
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002405void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2406 HandleInvoke(invoke);
2407 // Add the hidden argument.
2408 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
2409}
2410
2411void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2412 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002413 LocationSummary* locations = invoke->GetLocations();
2414 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2415 CpuRegister hidden_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002416 Location receiver = locations->InAt(0);
2417 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
2418
Roland Levillain0d5a2812015-11-13 10:07:31 +00002419 // Set the hidden argument. This is safe to do this here, as RAX
2420 // won't be modified thereafter, before the `call` instruction.
2421 DCHECK_EQ(RAX, hidden_reg.AsRegister());
Mark Mendell92e83bf2015-05-07 11:25:03 -04002422 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002423
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002424 if (receiver.IsStackSlot()) {
2425 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002426 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002427 __ movl(temp, Address(temp, class_offset));
2428 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002429 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002430 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002431 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002432 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002433 // Instead of simply (possibly) unpoisoning `temp` here, we should
2434 // emit a read barrier for the previous class reference load.
2435 // However this is not required in practice, as this is an
2436 // intermediate/temporary reference and because the current
2437 // concurrent copying collector keeps the from-space memory
2438 // intact/accessible until the end of the marking phase (the
2439 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002440 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002441 // temp = temp->GetAddressOfIMT()
2442 __ movq(temp,
2443 Address(temp, mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
2444 // temp = temp->GetImtEntryAt(method_offset);
2445 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00002446 invoke->GetImtIndex(), kX86_64PointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002447 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002448 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002449 // call temp->GetEntryPoint();
Andreas Gampe542451c2016-07-26 09:02:02 -07002450 __ call(Address(
2451 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64PointerSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002452
2453 DCHECK(!codegen_->IsLeafMethod());
2454 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2455}
2456
Orion Hodsonac141392017-01-13 11:53:47 +00002457void LocationsBuilderX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2458 HandleInvoke(invoke);
2459}
2460
2461void InstructionCodeGeneratorX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2462 codegen_->GenerateInvokePolymorphicCall(invoke);
2463}
2464
Roland Levillain88cb1752014-10-20 16:36:47 +01002465void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
2466 LocationSummary* locations =
2467 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2468 switch (neg->GetResultType()) {
2469 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002470 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01002471 locations->SetInAt(0, Location::RequiresRegister());
2472 locations->SetOut(Location::SameAsFirstInput());
2473 break;
2474
Roland Levillain88cb1752014-10-20 16:36:47 +01002475 case Primitive::kPrimFloat:
2476 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002477 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002478 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00002479 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002480 break;
2481
2482 default:
2483 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2484 }
2485}
2486
2487void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
2488 LocationSummary* locations = neg->GetLocations();
2489 Location out = locations->Out();
2490 Location in = locations->InAt(0);
2491 switch (neg->GetResultType()) {
2492 case Primitive::kPrimInt:
2493 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002494 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002495 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002496 break;
2497
2498 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002499 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002500 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002501 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002502 break;
2503
Roland Levillain5368c212014-11-27 15:03:41 +00002504 case Primitive::kPrimFloat: {
2505 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002506 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002507 // Implement float negation with an exclusive or with value
2508 // 0x80000000 (mask for bit 31, representing the sign of a
2509 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002510 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002511 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002512 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002513 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002514
Roland Levillain5368c212014-11-27 15:03:41 +00002515 case Primitive::kPrimDouble: {
2516 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002517 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002518 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00002519 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00002520 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002521 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002522 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002523 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002524 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002525
2526 default:
2527 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2528 }
2529}
2530
Roland Levillaindff1f282014-11-05 14:15:05 +00002531void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2532 LocationSummary* locations =
2533 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2534 Primitive::Type result_type = conversion->GetResultType();
2535 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002536 DCHECK_NE(result_type, input_type);
David Brazdil46e2a392015-03-16 17:31:52 +00002537
David Brazdilb2bd1c52015-03-25 11:17:37 +00002538 // The Java language does not allow treating boolean as an integral type but
2539 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002540
Roland Levillaindff1f282014-11-05 14:15:05 +00002541 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002542 case Primitive::kPrimByte:
2543 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002544 case Primitive::kPrimLong:
2545 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002546 case Primitive::kPrimBoolean:
2547 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002548 case Primitive::kPrimShort:
2549 case Primitive::kPrimInt:
2550 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002551 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002552 locations->SetInAt(0, Location::Any());
2553 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2554 break;
2555
2556 default:
2557 LOG(FATAL) << "Unexpected type conversion from " << input_type
2558 << " to " << result_type;
2559 }
2560 break;
2561
Roland Levillain01a8d712014-11-14 16:27:39 +00002562 case Primitive::kPrimShort:
2563 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002564 case Primitive::kPrimLong:
2565 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002566 case Primitive::kPrimBoolean:
2567 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002568 case Primitive::kPrimByte:
2569 case Primitive::kPrimInt:
2570 case Primitive::kPrimChar:
2571 // Processing a Dex `int-to-short' instruction.
2572 locations->SetInAt(0, Location::Any());
2573 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2574 break;
2575
2576 default:
2577 LOG(FATAL) << "Unexpected type conversion from " << input_type
2578 << " to " << result_type;
2579 }
2580 break;
2581
Roland Levillain946e1432014-11-11 17:35:19 +00002582 case Primitive::kPrimInt:
2583 switch (input_type) {
2584 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002585 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002586 locations->SetInAt(0, Location::Any());
2587 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2588 break;
2589
2590 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002591 // Processing a Dex `float-to-int' instruction.
2592 locations->SetInAt(0, Location::RequiresFpuRegister());
2593 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002594 break;
2595
Roland Levillain946e1432014-11-11 17:35:19 +00002596 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002597 // Processing a Dex `double-to-int' instruction.
2598 locations->SetInAt(0, Location::RequiresFpuRegister());
2599 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002600 break;
2601
2602 default:
2603 LOG(FATAL) << "Unexpected type conversion from " << input_type
2604 << " to " << result_type;
2605 }
2606 break;
2607
Roland Levillaindff1f282014-11-05 14:15:05 +00002608 case Primitive::kPrimLong:
2609 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002610 case Primitive::kPrimBoolean:
2611 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002612 case Primitive::kPrimByte:
2613 case Primitive::kPrimShort:
2614 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002615 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002616 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002617 // TODO: We would benefit from a (to-be-implemented)
2618 // Location::RegisterOrStackSlot requirement for this input.
2619 locations->SetInAt(0, Location::RequiresRegister());
2620 locations->SetOut(Location::RequiresRegister());
2621 break;
2622
2623 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002624 // Processing a Dex `float-to-long' instruction.
2625 locations->SetInAt(0, Location::RequiresFpuRegister());
2626 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002627 break;
2628
Roland Levillaindff1f282014-11-05 14:15:05 +00002629 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002630 // Processing a Dex `double-to-long' instruction.
2631 locations->SetInAt(0, Location::RequiresFpuRegister());
2632 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002633 break;
2634
2635 default:
2636 LOG(FATAL) << "Unexpected type conversion from " << input_type
2637 << " to " << result_type;
2638 }
2639 break;
2640
Roland Levillain981e4542014-11-14 11:47:14 +00002641 case Primitive::kPrimChar:
2642 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002643 case Primitive::kPrimLong:
2644 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002645 case Primitive::kPrimBoolean:
2646 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002647 case Primitive::kPrimByte:
2648 case Primitive::kPrimShort:
2649 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002650 // Processing a Dex `int-to-char' instruction.
2651 locations->SetInAt(0, Location::Any());
2652 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2653 break;
2654
2655 default:
2656 LOG(FATAL) << "Unexpected type conversion from " << input_type
2657 << " to " << result_type;
2658 }
2659 break;
2660
Roland Levillaindff1f282014-11-05 14:15:05 +00002661 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002662 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002663 case Primitive::kPrimBoolean:
2664 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002665 case Primitive::kPrimByte:
2666 case Primitive::kPrimShort:
2667 case Primitive::kPrimInt:
2668 case Primitive::kPrimChar:
2669 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002670 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002671 locations->SetOut(Location::RequiresFpuRegister());
2672 break;
2673
2674 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002675 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002676 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002677 locations->SetOut(Location::RequiresFpuRegister());
2678 break;
2679
Roland Levillaincff13742014-11-17 14:32:17 +00002680 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002681 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002682 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002683 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002684 break;
2685
2686 default:
2687 LOG(FATAL) << "Unexpected type conversion from " << input_type
2688 << " to " << result_type;
2689 };
2690 break;
2691
Roland Levillaindff1f282014-11-05 14:15:05 +00002692 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002693 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002694 case Primitive::kPrimBoolean:
2695 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002696 case Primitive::kPrimByte:
2697 case Primitive::kPrimShort:
2698 case Primitive::kPrimInt:
2699 case Primitive::kPrimChar:
2700 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002701 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002702 locations->SetOut(Location::RequiresFpuRegister());
2703 break;
2704
2705 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002706 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002707 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002708 locations->SetOut(Location::RequiresFpuRegister());
2709 break;
2710
Roland Levillaincff13742014-11-17 14:32:17 +00002711 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002712 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002713 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002714 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002715 break;
2716
2717 default:
2718 LOG(FATAL) << "Unexpected type conversion from " << input_type
2719 << " to " << result_type;
2720 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002721 break;
2722
2723 default:
2724 LOG(FATAL) << "Unexpected type conversion from " << input_type
2725 << " to " << result_type;
2726 }
2727}
2728
2729void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2730 LocationSummary* locations = conversion->GetLocations();
2731 Location out = locations->Out();
2732 Location in = locations->InAt(0);
2733 Primitive::Type result_type = conversion->GetResultType();
2734 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002735 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002736 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002737 case Primitive::kPrimByte:
2738 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002739 case Primitive::kPrimLong:
2740 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002741 case Primitive::kPrimBoolean:
2742 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002743 case Primitive::kPrimShort:
2744 case Primitive::kPrimInt:
2745 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002746 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002747 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002748 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002749 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002750 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002751 Address(CpuRegister(RSP), in.GetStackIndex()));
2752 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002753 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002754 Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain51d3fc42014-11-13 14:11:42 +00002755 }
2756 break;
2757
2758 default:
2759 LOG(FATAL) << "Unexpected type conversion from " << input_type
2760 << " to " << result_type;
2761 }
2762 break;
2763
Roland Levillain01a8d712014-11-14 16:27:39 +00002764 case Primitive::kPrimShort:
2765 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002766 case Primitive::kPrimLong:
2767 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002768 case Primitive::kPrimBoolean:
2769 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002770 case Primitive::kPrimByte:
2771 case Primitive::kPrimInt:
2772 case Primitive::kPrimChar:
2773 // Processing a Dex `int-to-short' instruction.
2774 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002775 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002776 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002777 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002778 Address(CpuRegister(RSP), in.GetStackIndex()));
2779 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002780 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002781 Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain01a8d712014-11-14 16:27:39 +00002782 }
2783 break;
2784
2785 default:
2786 LOG(FATAL) << "Unexpected type conversion from " << input_type
2787 << " to " << result_type;
2788 }
2789 break;
2790
Roland Levillain946e1432014-11-11 17:35:19 +00002791 case Primitive::kPrimInt:
2792 switch (input_type) {
2793 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002794 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002795 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002796 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002797 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002798 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002799 Address(CpuRegister(RSP), in.GetStackIndex()));
2800 } else {
2801 DCHECK(in.IsConstant());
2802 DCHECK(in.GetConstant()->IsLongConstant());
2803 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002804 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002805 }
2806 break;
2807
Roland Levillain3f8f9362014-12-02 17:45:01 +00002808 case Primitive::kPrimFloat: {
2809 // Processing a Dex `float-to-int' instruction.
2810 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2811 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002812 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002813
2814 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002815 // if input >= (float)INT_MAX goto done
2816 __ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002817 __ j(kAboveEqual, &done);
2818 // if input == NaN goto nan
2819 __ j(kUnordered, &nan);
2820 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002821 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002822 __ jmp(&done);
2823 __ Bind(&nan);
2824 // output = 0
2825 __ xorl(output, output);
2826 __ Bind(&done);
2827 break;
2828 }
2829
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002830 case Primitive::kPrimDouble: {
2831 // Processing a Dex `double-to-int' instruction.
2832 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2833 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002834 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002835
2836 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002837 // if input >= (double)INT_MAX goto done
2838 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002839 __ j(kAboveEqual, &done);
2840 // if input == NaN goto nan
2841 __ j(kUnordered, &nan);
2842 // output = double-to-int-truncate(input)
2843 __ cvttsd2si(output, input);
2844 __ jmp(&done);
2845 __ Bind(&nan);
2846 // output = 0
2847 __ xorl(output, output);
2848 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002849 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002850 }
Roland Levillain946e1432014-11-11 17:35:19 +00002851
2852 default:
2853 LOG(FATAL) << "Unexpected type conversion from " << input_type
2854 << " to " << result_type;
2855 }
2856 break;
2857
Roland Levillaindff1f282014-11-05 14:15:05 +00002858 case Primitive::kPrimLong:
2859 switch (input_type) {
2860 DCHECK(out.IsRegister());
David Brazdil46e2a392015-03-16 17:31:52 +00002861 case Primitive::kPrimBoolean:
2862 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002863 case Primitive::kPrimByte:
2864 case Primitive::kPrimShort:
2865 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002866 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002867 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002868 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002869 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002870 break;
2871
Roland Levillain624279f2014-12-04 11:54:28 +00002872 case Primitive::kPrimFloat: {
2873 // Processing a Dex `float-to-long' instruction.
2874 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2875 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002876 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00002877
Mark Mendell92e83bf2015-05-07 11:25:03 -04002878 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002879 // if input >= (float)LONG_MAX goto done
2880 __ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
Roland Levillain624279f2014-12-04 11:54:28 +00002881 __ j(kAboveEqual, &done);
2882 // if input == NaN goto nan
2883 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002884 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002885 __ cvttss2si(output, input, true);
2886 __ jmp(&done);
2887 __ Bind(&nan);
2888 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002889 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00002890 __ Bind(&done);
2891 break;
2892 }
2893
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002894 case Primitive::kPrimDouble: {
2895 // Processing a Dex `double-to-long' instruction.
2896 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2897 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002898 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002899
Mark Mendell92e83bf2015-05-07 11:25:03 -04002900 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04002901 // if input >= (double)LONG_MAX goto done
2902 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002903 __ j(kAboveEqual, &done);
2904 // if input == NaN goto nan
2905 __ j(kUnordered, &nan);
2906 // output = double-to-long-truncate(input)
2907 __ cvttsd2si(output, input, true);
2908 __ jmp(&done);
2909 __ Bind(&nan);
2910 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04002911 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002912 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00002913 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002914 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002915
2916 default:
2917 LOG(FATAL) << "Unexpected type conversion from " << input_type
2918 << " to " << result_type;
2919 }
2920 break;
2921
Roland Levillain981e4542014-11-14 11:47:14 +00002922 case Primitive::kPrimChar:
2923 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002924 case Primitive::kPrimLong:
2925 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002926 case Primitive::kPrimBoolean:
2927 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002928 case Primitive::kPrimByte:
2929 case Primitive::kPrimShort:
2930 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002931 // Processing a Dex `int-to-char' instruction.
2932 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002933 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002934 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002935 __ movzxw(out.AsRegister<CpuRegister>(),
Roland Levillain981e4542014-11-14 11:47:14 +00002936 Address(CpuRegister(RSP), in.GetStackIndex()));
2937 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002938 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002939 Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain981e4542014-11-14 11:47:14 +00002940 }
2941 break;
2942
2943 default:
2944 LOG(FATAL) << "Unexpected type conversion from " << input_type
2945 << " to " << result_type;
2946 }
2947 break;
2948
Roland Levillaindff1f282014-11-05 14:15:05 +00002949 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002950 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002951 case Primitive::kPrimBoolean:
2952 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002953 case Primitive::kPrimByte:
2954 case Primitive::kPrimShort:
2955 case Primitive::kPrimInt:
2956 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002957 // Processing a Dex `int-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002958 if (in.IsRegister()) {
2959 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
2960 } else if (in.IsConstant()) {
2961 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
2962 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05002963 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()), false);
2967 }
Roland Levillaincff13742014-11-17 14:32:17 +00002968 break;
2969
2970 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002971 // Processing a Dex `long-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002972 if (in.IsRegister()) {
2973 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
2974 } else if (in.IsConstant()) {
2975 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
2976 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Pavel Vyssotski4c858cd2016-03-16 13:59:53 +06002977 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04002978 } else {
2979 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
2980 Address(CpuRegister(RSP), in.GetStackIndex()), true);
2981 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002982 break;
2983
Roland Levillaincff13742014-11-17 14:32:17 +00002984 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002985 // Processing a Dex `double-to-float' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04002986 if (in.IsFpuRegister()) {
2987 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
2988 } else if (in.IsConstant()) {
2989 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
2990 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05002991 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04002992 } else {
2993 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
2994 Address(CpuRegister(RSP), in.GetStackIndex()));
2995 }
Roland Levillaincff13742014-11-17 14:32:17 +00002996 break;
2997
2998 default:
2999 LOG(FATAL) << "Unexpected type conversion from " << input_type
3000 << " to " << result_type;
3001 };
3002 break;
3003
Roland Levillaindff1f282014-11-05 14:15:05 +00003004 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003005 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003006 case Primitive::kPrimBoolean:
3007 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003008 case Primitive::kPrimByte:
3009 case Primitive::kPrimShort:
3010 case Primitive::kPrimInt:
3011 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00003012 // Processing a Dex `int-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04003013 if (in.IsRegister()) {
3014 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
3015 } else if (in.IsConstant()) {
3016 int32_t v = in.GetConstant()->AsIntConstant()->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()), false);
3022 }
Roland Levillaincff13742014-11-17 14:32:17 +00003023 break;
3024
3025 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003026 // Processing a Dex `long-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04003027 if (in.IsRegister()) {
3028 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
3029 } else if (in.IsConstant()) {
3030 int64_t v = in.GetConstant()->AsLongConstant()->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 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
3035 Address(CpuRegister(RSP), in.GetStackIndex()), true);
3036 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00003037 break;
3038
Roland Levillaincff13742014-11-17 14:32:17 +00003039 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003040 // Processing a Dex `float-to-double' instruction.
Mark Mendell40741f32015-04-20 22:10:34 -04003041 if (in.IsFpuRegister()) {
3042 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3043 } else if (in.IsConstant()) {
3044 float v = in.GetConstant()->AsFloatConstant()->GetValue();
3045 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003046 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003047 } else {
3048 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
3049 Address(CpuRegister(RSP), in.GetStackIndex()));
3050 }
Roland Levillaincff13742014-11-17 14:32:17 +00003051 break;
3052
3053 default:
3054 LOG(FATAL) << "Unexpected type conversion from " << input_type
3055 << " to " << result_type;
3056 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003057 break;
3058
3059 default:
3060 LOG(FATAL) << "Unexpected type conversion from " << input_type
3061 << " to " << result_type;
3062 }
3063}
3064
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003065void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003066 LocationSummary* locations =
3067 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003068 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003069 case Primitive::kPrimInt: {
3070 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003071 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3072 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003073 break;
3074 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003075
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003076 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003077 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05003078 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendellea5af682015-10-22 17:35:49 -04003079 locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05003080 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003081 break;
3082 }
3083
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003084 case Primitive::kPrimDouble:
3085 case Primitive::kPrimFloat: {
3086 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003087 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003088 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003089 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003090 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003091
3092 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003093 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003094 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003095}
3096
3097void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
3098 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003099 Location first = locations->InAt(0);
3100 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003101 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01003102
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003103 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003104 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003105 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003106 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3107 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003108 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3109 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003110 } else {
3111 __ leal(out.AsRegister<CpuRegister>(), Address(
3112 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3113 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003114 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003115 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3116 __ addl(out.AsRegister<CpuRegister>(),
3117 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
3118 } else {
3119 __ leal(out.AsRegister<CpuRegister>(), Address(
3120 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
3121 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003122 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003123 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003124 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003125 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003126 break;
3127 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003128
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003129 case Primitive::kPrimLong: {
Mark Mendell09b84632015-02-13 17:48:38 -05003130 if (second.IsRegister()) {
3131 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3132 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003133 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3134 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05003135 } else {
3136 __ leaq(out.AsRegister<CpuRegister>(), Address(
3137 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3138 }
3139 } else {
3140 DCHECK(second.IsConstant());
3141 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3142 int32_t int32_value = Low32Bits(value);
3143 DCHECK_EQ(int32_value, value);
3144 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3145 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
3146 } else {
3147 __ leaq(out.AsRegister<CpuRegister>(), Address(
3148 first.AsRegister<CpuRegister>(), int32_value));
3149 }
3150 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003151 break;
3152 }
3153
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003154 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003155 if (second.IsFpuRegister()) {
3156 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3157 } else if (second.IsConstant()) {
3158 __ addss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003159 codegen_->LiteralFloatAddress(
3160 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003161 } else {
3162 DCHECK(second.IsStackSlot());
3163 __ addss(first.AsFpuRegister<XmmRegister>(),
3164 Address(CpuRegister(RSP), second.GetStackIndex()));
3165 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003166 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003167 }
3168
3169 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003170 if (second.IsFpuRegister()) {
3171 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3172 } else if (second.IsConstant()) {
3173 __ addsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003174 codegen_->LiteralDoubleAddress(
3175 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003176 } else {
3177 DCHECK(second.IsDoubleStackSlot());
3178 __ addsd(first.AsFpuRegister<XmmRegister>(),
3179 Address(CpuRegister(RSP), second.GetStackIndex()));
3180 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003181 break;
3182 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003183
3184 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003185 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003186 }
3187}
3188
3189void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003190 LocationSummary* locations =
3191 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003192 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003193 case Primitive::kPrimInt: {
3194 locations->SetInAt(0, Location::RequiresRegister());
3195 locations->SetInAt(1, Location::Any());
3196 locations->SetOut(Location::SameAsFirstInput());
3197 break;
3198 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003199 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003200 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04003201 locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003202 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003203 break;
3204 }
Calin Juravle11351682014-10-23 15:38:15 +01003205 case Primitive::kPrimFloat:
3206 case Primitive::kPrimDouble: {
3207 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003208 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01003209 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003210 break;
Calin Juravle11351682014-10-23 15:38:15 +01003211 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003212 default:
Calin Juravle11351682014-10-23 15:38:15 +01003213 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003214 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003215}
3216
3217void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
3218 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003219 Location first = locations->InAt(0);
3220 Location second = locations->InAt(1);
3221 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003222 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003223 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01003224 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003225 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01003226 } else if (second.IsConstant()) {
3227 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003228 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003229 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003230 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003231 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003232 break;
3233 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003234 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003235 if (second.IsConstant()) {
3236 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3237 DCHECK(IsInt<32>(value));
3238 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
3239 } else {
3240 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
3241 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003242 break;
3243 }
3244
Calin Juravle11351682014-10-23 15:38:15 +01003245 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003246 if (second.IsFpuRegister()) {
3247 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3248 } else if (second.IsConstant()) {
3249 __ subss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003250 codegen_->LiteralFloatAddress(
3251 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003252 } else {
3253 DCHECK(second.IsStackSlot());
3254 __ subss(first.AsFpuRegister<XmmRegister>(),
3255 Address(CpuRegister(RSP), second.GetStackIndex()));
3256 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003257 break;
Calin Juravle11351682014-10-23 15:38:15 +01003258 }
3259
3260 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003261 if (second.IsFpuRegister()) {
3262 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3263 } else if (second.IsConstant()) {
3264 __ subsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003265 codegen_->LiteralDoubleAddress(
3266 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003267 } else {
3268 DCHECK(second.IsDoubleStackSlot());
3269 __ subsd(first.AsFpuRegister<XmmRegister>(),
3270 Address(CpuRegister(RSP), second.GetStackIndex()));
3271 }
Calin Juravle11351682014-10-23 15:38:15 +01003272 break;
3273 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003274
3275 default:
Calin Juravle11351682014-10-23 15:38:15 +01003276 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003277 }
3278}
3279
Calin Juravle34bacdf2014-10-07 20:23:36 +01003280void LocationsBuilderX86_64::VisitMul(HMul* mul) {
3281 LocationSummary* locations =
3282 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3283 switch (mul->GetResultType()) {
3284 case Primitive::kPrimInt: {
3285 locations->SetInAt(0, Location::RequiresRegister());
3286 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003287 if (mul->InputAt(1)->IsIntConstant()) {
3288 // Can use 3 operand multiply.
3289 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3290 } else {
3291 locations->SetOut(Location::SameAsFirstInput());
3292 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003293 break;
3294 }
3295 case Primitive::kPrimLong: {
3296 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003297 locations->SetInAt(1, Location::Any());
3298 if (mul->InputAt(1)->IsLongConstant() &&
3299 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003300 // Can use 3 operand multiply.
3301 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3302 } else {
3303 locations->SetOut(Location::SameAsFirstInput());
3304 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003305 break;
3306 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003307 case Primitive::kPrimFloat:
3308 case Primitive::kPrimDouble: {
3309 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003310 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01003311 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003312 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003313 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003314
3315 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003316 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003317 }
3318}
3319
3320void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
3321 LocationSummary* locations = mul->GetLocations();
3322 Location first = locations->InAt(0);
3323 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003324 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003325 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003326 case Primitive::kPrimInt:
3327 // The constant may have ended up in a register, so test explicitly to avoid
3328 // problems where the output may not be the same as the first operand.
3329 if (mul->InputAt(1)->IsIntConstant()) {
3330 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3331 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
3332 } else if (second.IsRegister()) {
3333 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003334 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003335 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003336 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003337 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00003338 __ imull(first.AsRegister<CpuRegister>(),
3339 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003340 }
3341 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01003342 case Primitive::kPrimLong: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003343 // The constant may have ended up in a register, so test explicitly to avoid
3344 // problems where the output may not be the same as the first operand.
3345 if (mul->InputAt(1)->IsLongConstant()) {
3346 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
3347 if (IsInt<32>(value)) {
3348 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
3349 Immediate(static_cast<int32_t>(value)));
3350 } else {
3351 // Have to use the constant area.
3352 DCHECK(first.Equals(out));
3353 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
3354 }
3355 } else if (second.IsRegister()) {
3356 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003357 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003358 } else {
3359 DCHECK(second.IsDoubleStackSlot());
3360 DCHECK(first.Equals(out));
3361 __ imulq(first.AsRegister<CpuRegister>(),
3362 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003363 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003364 break;
3365 }
3366
Calin Juravleb5bfa962014-10-21 18:02:24 +01003367 case Primitive::kPrimFloat: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003368 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003369 if (second.IsFpuRegister()) {
3370 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3371 } else if (second.IsConstant()) {
3372 __ mulss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003373 codegen_->LiteralFloatAddress(
3374 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003375 } else {
3376 DCHECK(second.IsStackSlot());
3377 __ mulss(first.AsFpuRegister<XmmRegister>(),
3378 Address(CpuRegister(RSP), second.GetStackIndex()));
3379 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003380 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003381 }
3382
3383 case Primitive::kPrimDouble: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003384 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003385 if (second.IsFpuRegister()) {
3386 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3387 } else if (second.IsConstant()) {
3388 __ mulsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003389 codegen_->LiteralDoubleAddress(
3390 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003391 } else {
3392 DCHECK(second.IsDoubleStackSlot());
3393 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3394 Address(CpuRegister(RSP), second.GetStackIndex()));
3395 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003396 break;
3397 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003398
3399 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003400 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003401 }
3402}
3403
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003404void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
3405 uint32_t stack_adjustment, bool is_float) {
3406 if (source.IsStackSlot()) {
3407 DCHECK(is_float);
3408 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3409 } else if (source.IsDoubleStackSlot()) {
3410 DCHECK(!is_float);
3411 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3412 } else {
3413 // Write the value to the temporary location on the stack and load to FP stack.
3414 if (is_float) {
3415 Location stack_temp = Location::StackSlot(temp_offset);
3416 codegen_->Move(stack_temp, source);
3417 __ flds(Address(CpuRegister(RSP), temp_offset));
3418 } else {
3419 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3420 codegen_->Move(stack_temp, source);
3421 __ fldl(Address(CpuRegister(RSP), temp_offset));
3422 }
3423 }
3424}
3425
3426void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
3427 Primitive::Type type = rem->GetResultType();
3428 bool is_float = type == Primitive::kPrimFloat;
3429 size_t elem_size = Primitive::ComponentSize(type);
3430 LocationSummary* locations = rem->GetLocations();
3431 Location first = locations->InAt(0);
3432 Location second = locations->InAt(1);
3433 Location out = locations->Out();
3434
3435 // Create stack space for 2 elements.
3436 // TODO: enhance register allocator to ask for stack temporaries.
3437 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
3438
3439 // Load the values to the FP stack in reverse order, using temporaries if needed.
3440 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
3441 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
3442
3443 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003444 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003445 __ Bind(&retry);
3446 __ fprem();
3447
3448 // Move FP status to AX.
3449 __ fstsw();
3450
3451 // And see if the argument reduction is complete. This is signaled by the
3452 // C2 FPU flag bit set to 0.
3453 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
3454 __ j(kNotEqual, &retry);
3455
3456 // We have settled on the final value. Retrieve it into an XMM register.
3457 // Store FP top of stack to real stack.
3458 if (is_float) {
3459 __ fsts(Address(CpuRegister(RSP), 0));
3460 } else {
3461 __ fstl(Address(CpuRegister(RSP), 0));
3462 }
3463
3464 // Pop the 2 items from the FP stack.
3465 __ fucompp();
3466
3467 // Load the value from the stack into an XMM register.
3468 DCHECK(out.IsFpuRegister()) << out;
3469 if (is_float) {
3470 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3471 } else {
3472 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3473 }
3474
3475 // And remove the temporary stack space we allocated.
3476 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
3477}
3478
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003479void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3480 DCHECK(instruction->IsDiv() || instruction->IsRem());
3481
3482 LocationSummary* locations = instruction->GetLocations();
3483 Location second = locations->InAt(1);
3484 DCHECK(second.IsConstant());
3485
3486 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3487 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003488 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003489
3490 DCHECK(imm == 1 || imm == -1);
3491
3492 switch (instruction->GetResultType()) {
3493 case Primitive::kPrimInt: {
3494 if (instruction->IsRem()) {
3495 __ xorl(output_register, output_register);
3496 } else {
3497 __ movl(output_register, input_register);
3498 if (imm == -1) {
3499 __ negl(output_register);
3500 }
3501 }
3502 break;
3503 }
3504
3505 case Primitive::kPrimLong: {
3506 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003507 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003508 } else {
3509 __ movq(output_register, input_register);
3510 if (imm == -1) {
3511 __ negq(output_register);
3512 }
3513 }
3514 break;
3515 }
3516
3517 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003518 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003519 }
3520}
3521
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003522void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003523 LocationSummary* locations = instruction->GetLocations();
3524 Location second = locations->InAt(1);
3525
3526 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3527 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3528
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003529 int64_t imm = Int64FromConstant(second.GetConstant());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003530 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3531 uint64_t abs_imm = AbsOrMin(imm);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003532
3533 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3534
3535 if (instruction->GetResultType() == Primitive::kPrimInt) {
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003536 __ leal(tmp, Address(numerator, abs_imm - 1));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003537 __ testl(numerator, numerator);
3538 __ cmov(kGreaterEqual, tmp, numerator);
3539 int shift = CTZ(imm);
3540 __ sarl(tmp, Immediate(shift));
3541
3542 if (imm < 0) {
3543 __ negl(tmp);
3544 }
3545
3546 __ movl(output_register, tmp);
3547 } else {
3548 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3549 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
3550
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003551 codegen_->Load64BitValue(rdx, abs_imm - 1);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003552 __ addq(rdx, numerator);
3553 __ testq(numerator, numerator);
3554 __ cmov(kGreaterEqual, rdx, numerator);
3555 int shift = CTZ(imm);
3556 __ sarq(rdx, Immediate(shift));
3557
3558 if (imm < 0) {
3559 __ negq(rdx);
3560 }
3561
3562 __ movq(output_register, rdx);
3563 }
3564}
3565
3566void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3567 DCHECK(instruction->IsDiv() || instruction->IsRem());
3568
3569 LocationSummary* locations = instruction->GetLocations();
3570 Location second = locations->InAt(1);
3571
3572 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3573 : locations->GetTemp(0).AsRegister<CpuRegister>();
3574 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3575 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3576 : locations->Out().AsRegister<CpuRegister>();
3577 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3578
3579 DCHECK_EQ(RAX, eax.AsRegister());
3580 DCHECK_EQ(RDX, edx.AsRegister());
3581 if (instruction->IsDiv()) {
3582 DCHECK_EQ(RAX, out.AsRegister());
3583 } else {
3584 DCHECK_EQ(RDX, out.AsRegister());
3585 }
3586
3587 int64_t magic;
3588 int shift;
3589
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003590 // TODO: can these branches be written as one?
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003591 if (instruction->GetResultType() == Primitive::kPrimInt) {
3592 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3593
3594 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3595
3596 __ movl(numerator, eax);
3597
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003598 __ movl(eax, Immediate(magic));
3599 __ imull(numerator);
3600
3601 if (imm > 0 && magic < 0) {
3602 __ addl(edx, numerator);
3603 } else if (imm < 0 && magic > 0) {
3604 __ subl(edx, numerator);
3605 }
3606
3607 if (shift != 0) {
3608 __ sarl(edx, Immediate(shift));
3609 }
3610
3611 __ movl(eax, edx);
3612 __ shrl(edx, Immediate(31));
3613 __ addl(edx, eax);
3614
3615 if (instruction->IsRem()) {
3616 __ movl(eax, numerator);
3617 __ imull(edx, Immediate(imm));
3618 __ subl(eax, edx);
3619 __ movl(edx, eax);
3620 } else {
3621 __ movl(eax, edx);
3622 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003623 } else {
3624 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3625
3626 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3627
3628 CpuRegister rax = eax;
3629 CpuRegister rdx = edx;
3630
3631 CalculateMagicAndShiftForDivRem(imm, true /* is_long */, &magic, &shift);
3632
3633 // Save the numerator.
3634 __ movq(numerator, rax);
3635
3636 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003637 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003638
3639 // RDX:RAX = magic * numerator
3640 __ imulq(numerator);
3641
3642 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003643 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003644 __ addq(rdx, numerator);
3645 } else if (imm < 0 && magic > 0) {
3646 // RDX -= numerator
3647 __ subq(rdx, numerator);
3648 }
3649
3650 // Shift if needed.
3651 if (shift != 0) {
3652 __ sarq(rdx, Immediate(shift));
3653 }
3654
3655 // RDX += 1 if RDX < 0
3656 __ movq(rax, rdx);
3657 __ shrq(rdx, Immediate(63));
3658 __ addq(rdx, rax);
3659
3660 if (instruction->IsRem()) {
3661 __ movq(rax, numerator);
3662
3663 if (IsInt<32>(imm)) {
3664 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3665 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003666 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003667 }
3668
3669 __ subq(rax, rdx);
3670 __ movq(rdx, rax);
3671 } else {
3672 __ movq(rax, rdx);
3673 }
3674 }
3675}
3676
Calin Juravlebacfec32014-11-14 15:54:36 +00003677void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3678 DCHECK(instruction->IsDiv() || instruction->IsRem());
3679 Primitive::Type type = instruction->GetResultType();
Calin Juravlec70d1d92017-03-27 18:10:04 -07003680 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
Calin Juravlebacfec32014-11-14 15:54:36 +00003681
3682 bool is_div = instruction->IsDiv();
3683 LocationSummary* locations = instruction->GetLocations();
3684
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003685 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3686 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003687
Roland Levillain271ab9c2014-11-27 15:23:57 +00003688 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003689 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003690
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003691 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003692 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003693
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003694 if (imm == 0) {
3695 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3696 } else if (imm == 1 || imm == -1) {
3697 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003698 } else if (instruction->IsDiv() && IsPowerOfTwo(AbsOrMin(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003699 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003700 } else {
3701 DCHECK(imm <= -2 || imm >= 2);
3702 GenerateDivRemWithAnyConstant(instruction);
3703 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003704 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003705 SlowPathCode* slow_path =
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003706 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
David Srbecky9cd6d372016-02-09 15:24:47 +00003707 instruction, out.AsRegister(), type, is_div);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003708 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003709
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003710 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3711 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3712 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3713 // so it's safe to just use negl instead of more complex comparisons.
3714 if (type == Primitive::kPrimInt) {
3715 __ cmpl(second_reg, Immediate(-1));
3716 __ j(kEqual, slow_path->GetEntryLabel());
3717 // edx:eax <- sign-extended of eax
3718 __ cdq();
3719 // eax = quotient, edx = remainder
3720 __ idivl(second_reg);
3721 } else {
3722 __ cmpq(second_reg, Immediate(-1));
3723 __ j(kEqual, slow_path->GetEntryLabel());
3724 // rdx:rax <- sign-extended of rax
3725 __ cqo();
3726 // rax = quotient, rdx = remainder
3727 __ idivq(second_reg);
3728 }
3729 __ Bind(slow_path->GetExitLabel());
3730 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003731}
3732
Calin Juravle7c4954d2014-10-28 16:57:40 +00003733void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3734 LocationSummary* locations =
3735 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3736 switch (div->GetResultType()) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003737 case Primitive::kPrimInt:
3738 case Primitive::kPrimLong: {
Calin Juravled0d48522014-11-04 16:40:20 +00003739 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003740 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003741 locations->SetOut(Location::SameAsFirstInput());
3742 // Intel uses edx:eax as the dividend.
3743 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003744 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3745 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3746 // output and request another temp.
3747 if (div->InputAt(1)->IsConstant()) {
3748 locations->AddTemp(Location::RequiresRegister());
3749 }
Calin Juravled0d48522014-11-04 16:40:20 +00003750 break;
3751 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003752
Calin Juravle7c4954d2014-10-28 16:57:40 +00003753 case Primitive::kPrimFloat:
3754 case Primitive::kPrimDouble: {
3755 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003756 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003757 locations->SetOut(Location::SameAsFirstInput());
3758 break;
3759 }
3760
3761 default:
3762 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3763 }
3764}
3765
3766void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3767 LocationSummary* locations = div->GetLocations();
3768 Location first = locations->InAt(0);
3769 Location second = locations->InAt(1);
3770 DCHECK(first.Equals(locations->Out()));
3771
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003772 Primitive::Type type = div->GetResultType();
3773 switch (type) {
3774 case Primitive::kPrimInt:
3775 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003776 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003777 break;
3778 }
3779
Calin Juravle7c4954d2014-10-28 16:57:40 +00003780 case Primitive::kPrimFloat: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003781 if (second.IsFpuRegister()) {
3782 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3783 } else if (second.IsConstant()) {
3784 __ divss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003785 codegen_->LiteralFloatAddress(
3786 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003787 } else {
3788 DCHECK(second.IsStackSlot());
3789 __ divss(first.AsFpuRegister<XmmRegister>(),
3790 Address(CpuRegister(RSP), second.GetStackIndex()));
3791 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003792 break;
3793 }
3794
3795 case Primitive::kPrimDouble: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003796 if (second.IsFpuRegister()) {
3797 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3798 } else if (second.IsConstant()) {
3799 __ divsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003800 codegen_->LiteralDoubleAddress(
3801 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003802 } else {
3803 DCHECK(second.IsDoubleStackSlot());
3804 __ divsd(first.AsFpuRegister<XmmRegister>(),
3805 Address(CpuRegister(RSP), second.GetStackIndex()));
3806 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003807 break;
3808 }
3809
3810 default:
3811 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3812 }
3813}
3814
Calin Juravlebacfec32014-11-14 15:54:36 +00003815void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003816 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003817 LocationSummary* locations =
3818 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003819
3820 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003821 case Primitive::kPrimInt:
3822 case Primitive::kPrimLong: {
3823 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003824 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003825 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3826 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003827 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3828 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3829 // output and request another temp.
3830 if (rem->InputAt(1)->IsConstant()) {
3831 locations->AddTemp(Location::RequiresRegister());
3832 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003833 break;
3834 }
3835
3836 case Primitive::kPrimFloat:
3837 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003838 locations->SetInAt(0, Location::Any());
3839 locations->SetInAt(1, Location::Any());
3840 locations->SetOut(Location::RequiresFpuRegister());
3841 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003842 break;
3843 }
3844
3845 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003846 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003847 }
3848}
3849
3850void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
3851 Primitive::Type type = rem->GetResultType();
3852 switch (type) {
3853 case Primitive::kPrimInt:
3854 case Primitive::kPrimLong: {
3855 GenerateDivRemIntegral(rem);
3856 break;
3857 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003858 case Primitive::kPrimFloat:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003859 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003860 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003861 break;
3862 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003863 default:
3864 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
3865 }
3866}
3867
Calin Juravled0d48522014-11-04 16:40:20 +00003868void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003869 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003870 locations->SetInAt(0, Location::Any());
Calin Juravled0d48522014-11-04 16:40:20 +00003871}
3872
3873void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003874 SlowPathCode* slow_path =
Calin Juravled0d48522014-11-04 16:40:20 +00003875 new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
3876 codegen_->AddSlowPath(slow_path);
3877
3878 LocationSummary* locations = instruction->GetLocations();
3879 Location value = locations->InAt(0);
3880
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003881 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003882 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003883 case Primitive::kPrimByte:
3884 case Primitive::kPrimChar:
3885 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003886 case Primitive::kPrimInt: {
3887 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003888 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003889 __ j(kEqual, slow_path->GetEntryLabel());
3890 } else if (value.IsStackSlot()) {
3891 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3892 __ j(kEqual, slow_path->GetEntryLabel());
3893 } else {
3894 DCHECK(value.IsConstant()) << value;
3895 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01003896 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003897 }
3898 }
3899 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003900 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003901 case Primitive::kPrimLong: {
3902 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003903 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003904 __ j(kEqual, slow_path->GetEntryLabel());
3905 } else if (value.IsDoubleStackSlot()) {
3906 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
3907 __ j(kEqual, slow_path->GetEntryLabel());
3908 } else {
3909 DCHECK(value.IsConstant()) << value;
3910 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01003911 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003912 }
3913 }
3914 break;
3915 }
3916 default:
3917 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003918 }
Calin Juravled0d48522014-11-04 16:40:20 +00003919}
3920
Calin Juravle9aec02f2014-11-18 23:06:35 +00003921void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
3922 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3923
3924 LocationSummary* locations =
3925 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3926
3927 switch (op->GetResultType()) {
3928 case Primitive::kPrimInt:
3929 case Primitive::kPrimLong: {
3930 locations->SetInAt(0, Location::RequiresRegister());
3931 // The shift count needs to be in CL.
3932 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
3933 locations->SetOut(Location::SameAsFirstInput());
3934 break;
3935 }
3936 default:
3937 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3938 }
3939}
3940
3941void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
3942 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3943
3944 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003945 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003946 Location second = locations->InAt(1);
3947
3948 switch (op->GetResultType()) {
3949 case Primitive::kPrimInt: {
3950 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003951 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003952 if (op->IsShl()) {
3953 __ shll(first_reg, second_reg);
3954 } else if (op->IsShr()) {
3955 __ sarl(first_reg, second_reg);
3956 } else {
3957 __ shrl(first_reg, second_reg);
3958 }
3959 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003960 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003961 if (op->IsShl()) {
3962 __ shll(first_reg, imm);
3963 } else if (op->IsShr()) {
3964 __ sarl(first_reg, imm);
3965 } else {
3966 __ shrl(first_reg, imm);
3967 }
3968 }
3969 break;
3970 }
3971 case Primitive::kPrimLong: {
3972 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003973 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003974 if (op->IsShl()) {
3975 __ shlq(first_reg, second_reg);
3976 } else if (op->IsShr()) {
3977 __ sarq(first_reg, second_reg);
3978 } else {
3979 __ shrq(first_reg, second_reg);
3980 }
3981 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003982 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003983 if (op->IsShl()) {
3984 __ shlq(first_reg, imm);
3985 } else if (op->IsShr()) {
3986 __ sarq(first_reg, imm);
3987 } else {
3988 __ shrq(first_reg, imm);
3989 }
3990 }
3991 break;
3992 }
3993 default:
3994 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
Vladimir Marko351dddf2015-12-11 16:34:46 +00003995 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003996 }
3997}
3998
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003999void LocationsBuilderX86_64::VisitRor(HRor* ror) {
4000 LocationSummary* locations =
4001 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4002
4003 switch (ror->GetResultType()) {
4004 case Primitive::kPrimInt:
4005 case Primitive::kPrimLong: {
4006 locations->SetInAt(0, Location::RequiresRegister());
4007 // The shift count needs to be in CL (unless it is a constant).
4008 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, ror->InputAt(1)));
4009 locations->SetOut(Location::SameAsFirstInput());
4010 break;
4011 }
4012 default:
4013 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4014 UNREACHABLE();
4015 }
4016}
4017
4018void InstructionCodeGeneratorX86_64::VisitRor(HRor* ror) {
4019 LocationSummary* locations = ror->GetLocations();
4020 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
4021 Location second = locations->InAt(1);
4022
4023 switch (ror->GetResultType()) {
4024 case Primitive::kPrimInt:
4025 if (second.IsRegister()) {
4026 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4027 __ rorl(first_reg, second_reg);
4028 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004029 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004030 __ rorl(first_reg, imm);
4031 }
4032 break;
4033 case Primitive::kPrimLong:
4034 if (second.IsRegister()) {
4035 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4036 __ rorq(first_reg, second_reg);
4037 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004038 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004039 __ rorq(first_reg, imm);
4040 }
4041 break;
4042 default:
4043 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4044 UNREACHABLE();
4045 }
4046}
4047
Calin Juravle9aec02f2014-11-18 23:06:35 +00004048void LocationsBuilderX86_64::VisitShl(HShl* shl) {
4049 HandleShift(shl);
4050}
4051
4052void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
4053 HandleShift(shl);
4054}
4055
4056void LocationsBuilderX86_64::VisitShr(HShr* shr) {
4057 HandleShift(shr);
4058}
4059
4060void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
4061 HandleShift(shr);
4062}
4063
4064void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
4065 HandleShift(ushr);
4066}
4067
4068void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
4069 HandleShift(ushr);
4070}
4071
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004072void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004073 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004074 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004075 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00004076 if (instruction->IsStringAlloc()) {
4077 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4078 } else {
4079 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00004080 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004081 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004082}
4083
4084void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004085 // Note: if heap poisoning is enabled, the entry point takes cares
4086 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00004087 if (instruction->IsStringAlloc()) {
4088 // String is allocated through StringFactory. Call NewEmptyString entry point.
4089 CpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
Andreas Gampe542451c2016-07-26 09:02:02 -07004090 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64PointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00004091 __ gs()->movq(temp, Address::Absolute(QUICK_ENTRY_POINT(pNewEmptyString), /* no_rip */ true));
4092 __ call(Address(temp, code_offset.SizeValue()));
4093 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4094 } else {
Serban Constantinescuba45db02016-07-12 22:53:02 +01004095 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00004096 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00004097 DCHECK(!codegen_->IsLeafMethod());
4098 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004099}
4100
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004101void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
4102 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004103 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004104 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004105 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004106 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4107 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004108}
4109
4110void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004111 // Note: if heap poisoning is enabled, the entry point takes cares
4112 // of poisoning the reference.
Nicolas Geoffrayb048cb72017-01-23 22:50:24 +00004113 QuickEntrypointEnum entrypoint =
4114 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
4115 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004116 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004117 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004118}
4119
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004120void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004121 LocationSummary* locations =
4122 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004123 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4124 if (location.IsStackSlot()) {
4125 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4126 } else if (location.IsDoubleStackSlot()) {
4127 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4128 }
4129 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004130}
4131
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004132void InstructionCodeGeneratorX86_64::VisitParameterValue(
4133 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004134 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004135}
4136
4137void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
4138 LocationSummary* locations =
4139 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4140 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4141}
4142
4143void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
4144 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4145 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004146}
4147
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004148void LocationsBuilderX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4149 LocationSummary* locations =
4150 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4151 locations->SetInAt(0, Location::RequiresRegister());
4152 locations->SetOut(Location::RequiresRegister());
4153}
4154
4155void InstructionCodeGeneratorX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4156 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00004157 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004158 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004159 instruction->GetIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004160 __ movq(locations->Out().AsRegister<CpuRegister>(),
4161 Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004162 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004163 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00004164 instruction->GetIndex(), kX86_64PointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00004165 __ movq(locations->Out().AsRegister<CpuRegister>(),
4166 Address(locations->InAt(0).AsRegister<CpuRegister>(),
4167 mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004168 __ movq(locations->Out().AsRegister<CpuRegister>(),
4169 Address(locations->Out().AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004170 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004171}
4172
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004173void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004174 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004175 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004176 locations->SetInAt(0, Location::RequiresRegister());
4177 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004178}
4179
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004180void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
4181 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004182 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4183 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004184 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004185 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004186 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004187 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004188 break;
4189
4190 case Primitive::kPrimLong:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004191 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004192 break;
4193
4194 default:
4195 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4196 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004197}
4198
David Brazdil66d126e2015-04-03 16:02:44 +01004199void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
4200 LocationSummary* locations =
4201 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4202 locations->SetInAt(0, Location::RequiresRegister());
4203 locations->SetOut(Location::SameAsFirstInput());
4204}
4205
4206void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004207 LocationSummary* locations = bool_not->GetLocations();
4208 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4209 locations->Out().AsRegister<CpuRegister>().AsRegister());
4210 Location out = locations->Out();
4211 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
4212}
4213
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004214void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004215 LocationSummary* locations =
4216 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01004217 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004218 locations->SetInAt(i, Location::Any());
4219 }
4220 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004221}
4222
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004223void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004224 LOG(FATAL) << "Unimplemented";
4225}
4226
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004227void CodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
Calin Juravle52c48962014-12-16 17:02:57 +00004228 /*
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004229 * According to the JSR-133 Cookbook, for x86-64 only StoreLoad/AnyAny barriers need memory fence.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004230 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86-64 memory model.
Calin Juravle52c48962014-12-16 17:02:57 +00004231 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
4232 */
4233 switch (kind) {
4234 case MemBarrierKind::kAnyAny: {
Mark P Mendell17077d82015-12-16 19:15:59 +00004235 MemoryFence();
Calin Juravle52c48962014-12-16 17:02:57 +00004236 break;
4237 }
4238 case MemBarrierKind::kAnyStore:
4239 case MemBarrierKind::kLoadAny:
4240 case MemBarrierKind::kStoreStore: {
4241 // nop
4242 break;
4243 }
Mark Mendell7aa04a12016-01-27 22:39:07 -05004244 case MemBarrierKind::kNTStoreStore:
4245 // Non-Temporal Store/Store needs an explicit fence.
4246 MemoryFence(/* non-temporal */ true);
4247 break;
Calin Juravle52c48962014-12-16 17:02:57 +00004248 }
4249}
4250
4251void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
4252 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4253
Roland Levillain0d5a2812015-11-13 10:07:31 +00004254 bool object_field_get_with_read_barrier =
4255 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004256 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004257 new (GetGraph()->GetArena()) LocationSummary(instruction,
4258 object_field_get_with_read_barrier ?
4259 LocationSummary::kCallOnSlowPath :
4260 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004261 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004262 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004263 }
Calin Juravle52c48962014-12-16 17:02:57 +00004264 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004265 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4266 locations->SetOut(Location::RequiresFpuRegister());
4267 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004268 // The output overlaps for an object field get when read barriers
4269 // are enabled: we do not want the move to overwrite the object's
4270 // location, as we need it to emit the read barrier.
4271 locations->SetOut(
4272 Location::RequiresRegister(),
4273 object_field_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004274 }
Calin Juravle52c48962014-12-16 17:02:57 +00004275}
4276
4277void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
4278 const FieldInfo& field_info) {
4279 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4280
4281 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004282 Location base_loc = locations->InAt(0);
4283 CpuRegister base = base_loc.AsRegister<CpuRegister>();
Calin Juravle52c48962014-12-16 17:02:57 +00004284 Location out = locations->Out();
4285 bool is_volatile = field_info.IsVolatile();
4286 Primitive::Type field_type = field_info.GetFieldType();
4287 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4288
4289 switch (field_type) {
4290 case Primitive::kPrimBoolean: {
4291 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4292 break;
4293 }
4294
4295 case Primitive::kPrimByte: {
4296 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4297 break;
4298 }
4299
4300 case Primitive::kPrimShort: {
4301 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
4302 break;
4303 }
4304
4305 case Primitive::kPrimChar: {
4306 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
4307 break;
4308 }
4309
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004310 case Primitive::kPrimInt: {
Calin Juravle52c48962014-12-16 17:02:57 +00004311 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4312 break;
4313 }
4314
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004315 case Primitive::kPrimNot: {
4316 // /* HeapReference<Object> */ out = *(base + offset)
4317 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004318 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01004319 // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004320 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00004321 instruction, out, base, offset, /* needs_null_check */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004322 if (is_volatile) {
4323 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4324 }
4325 } else {
4326 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4327 codegen_->MaybeRecordImplicitNullCheck(instruction);
4328 if (is_volatile) {
4329 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4330 }
4331 // If read barriers are enabled, emit read barriers other than
4332 // Baker's using a slow path (and also unpoison the loaded
4333 // reference, if heap poisoning is enabled).
4334 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4335 }
4336 break;
4337 }
4338
Calin Juravle52c48962014-12-16 17:02:57 +00004339 case Primitive::kPrimLong: {
4340 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
4341 break;
4342 }
4343
4344 case Primitive::kPrimFloat: {
4345 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4346 break;
4347 }
4348
4349 case Primitive::kPrimDouble: {
4350 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4351 break;
4352 }
4353
4354 case Primitive::kPrimVoid:
4355 LOG(FATAL) << "Unreachable type " << field_type;
4356 UNREACHABLE();
4357 }
4358
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004359 if (field_type == Primitive::kPrimNot) {
4360 // Potential implicit null checks, in the case of reference
4361 // fields, are handled in the previous switch statement.
4362 } else {
4363 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004364 }
Roland Levillain4d027112015-07-01 15:41:14 +01004365
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004366 if (is_volatile) {
4367 if (field_type == Primitive::kPrimNot) {
4368 // Memory barriers, in the case of references, are also handled
4369 // in the previous switch statement.
4370 } else {
4371 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4372 }
Roland Levillain4d027112015-07-01 15:41:14 +01004373 }
Calin Juravle52c48962014-12-16 17:02:57 +00004374}
4375
4376void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
4377 const FieldInfo& field_info) {
4378 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4379
4380 LocationSummary* locations =
4381 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain4d027112015-07-01 15:41:14 +01004382 Primitive::Type field_type = field_info.GetFieldType();
Mark Mendellea5af682015-10-22 17:35:49 -04004383 bool is_volatile = field_info.IsVolatile();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004384 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01004385 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004386
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004387 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004388 if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
Mark Mendellea5af682015-10-22 17:35:49 -04004389 if (is_volatile) {
4390 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4391 locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
4392 } else {
4393 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
4394 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004395 } else {
Mark Mendellea5af682015-10-22 17:35:49 -04004396 if (is_volatile) {
4397 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4398 locations->SetInAt(1, Location::RegisterOrInt32Constant(instruction->InputAt(1)));
4399 } else {
4400 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4401 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004402 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004403 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004404 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01004405 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004406 locations->AddTemp(Location::RequiresRegister());
Roland Levillain4d027112015-07-01 15:41:14 +01004407 } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4408 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004409 locations->AddTemp(Location::RequiresRegister());
4410 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004411}
4412
Calin Juravle52c48962014-12-16 17:02:57 +00004413void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004414 const FieldInfo& field_info,
4415 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004416 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4417
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004418 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004419 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
4420 Location value = locations->InAt(1);
4421 bool is_volatile = field_info.IsVolatile();
4422 Primitive::Type field_type = field_info.GetFieldType();
4423 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4424
4425 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004426 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00004427 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004428
Mark Mendellea5af682015-10-22 17:35:49 -04004429 bool maybe_record_implicit_null_check_done = false;
4430
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004431 switch (field_type) {
4432 case Primitive::kPrimBoolean:
4433 case Primitive::kPrimByte: {
Mark Mendell40741f32015-04-20 22:10:34 -04004434 if (value.IsConstant()) {
Nicolas Geoffray78612082017-07-24 14:18:53 +01004435 __ movb(Address(base, offset),
4436 Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
Mark Mendell40741f32015-04-20 22:10:34 -04004437 } else {
4438 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
4439 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004440 break;
4441 }
4442
4443 case Primitive::kPrimShort:
4444 case Primitive::kPrimChar: {
Mark Mendell40741f32015-04-20 22:10:34 -04004445 if (value.IsConstant()) {
Nicolas Geoffray78612082017-07-24 14:18:53 +01004446 __ movw(Address(base, offset),
4447 Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Mark Mendell40741f32015-04-20 22:10:34 -04004448 } else {
4449 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
4450 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004451 break;
4452 }
4453
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004454 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004455 case Primitive::kPrimNot: {
Mark Mendell40741f32015-04-20 22:10:34 -04004456 if (value.IsConstant()) {
4457 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Roland Levillain4d027112015-07-01 15:41:14 +01004458 // `field_type == Primitive::kPrimNot` implies `v == 0`.
4459 DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
4460 // Note: if heap poisoning is enabled, no need to poison
4461 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01004462 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04004463 } else {
Roland Levillain4d027112015-07-01 15:41:14 +01004464 if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
4465 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4466 __ movl(temp, value.AsRegister<CpuRegister>());
4467 __ PoisonHeapReference(temp);
4468 __ movl(Address(base, offset), temp);
4469 } else {
4470 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
4471 }
Mark Mendell40741f32015-04-20 22:10:34 -04004472 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004473 break;
4474 }
4475
4476 case Primitive::kPrimLong: {
Mark Mendell40741f32015-04-20 22:10:34 -04004477 if (value.IsConstant()) {
4478 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004479 codegen_->MoveInt64ToAddress(Address(base, offset),
4480 Address(base, offset + sizeof(int32_t)),
4481 v,
4482 instruction);
4483 maybe_record_implicit_null_check_done = true;
Mark Mendell40741f32015-04-20 22:10:34 -04004484 } else {
4485 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
4486 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004487 break;
4488 }
4489
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004490 case Primitive::kPrimFloat: {
Mark Mendellea5af682015-10-22 17:35:49 -04004491 if (value.IsConstant()) {
4492 int32_t v =
4493 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4494 __ movl(Address(base, offset), Immediate(v));
4495 } else {
4496 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4497 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004498 break;
4499 }
4500
4501 case Primitive::kPrimDouble: {
Mark Mendellea5af682015-10-22 17:35:49 -04004502 if (value.IsConstant()) {
4503 int64_t v =
4504 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4505 codegen_->MoveInt64ToAddress(Address(base, offset),
4506 Address(base, offset + sizeof(int32_t)),
4507 v,
4508 instruction);
4509 maybe_record_implicit_null_check_done = true;
4510 } else {
4511 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4512 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004513 break;
4514 }
4515
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004516 case Primitive::kPrimVoid:
4517 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004518 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004519 }
Calin Juravle52c48962014-12-16 17:02:57 +00004520
Mark Mendellea5af682015-10-22 17:35:49 -04004521 if (!maybe_record_implicit_null_check_done) {
4522 codegen_->MaybeRecordImplicitNullCheck(instruction);
4523 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004524
4525 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4526 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4527 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004528 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004529 }
4530
Calin Juravle52c48962014-12-16 17:02:57 +00004531 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004532 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00004533 }
4534}
4535
4536void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4537 HandleFieldSet(instruction, instruction->GetFieldInfo());
4538}
4539
4540void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004541 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004542}
4543
4544void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004545 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004546}
4547
4548void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004549 HandleFieldGet(instruction, instruction->GetFieldInfo());
4550}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004551
Calin Juravle52c48962014-12-16 17:02:57 +00004552void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4553 HandleFieldGet(instruction);
4554}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004555
Calin Juravle52c48962014-12-16 17:02:57 +00004556void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4557 HandleFieldGet(instruction, instruction->GetFieldInfo());
4558}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004559
Calin Juravle52c48962014-12-16 17:02:57 +00004560void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4561 HandleFieldSet(instruction, instruction->GetFieldInfo());
4562}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004563
Calin Juravle52c48962014-12-16 17:02:57 +00004564void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004565 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004566}
4567
Calin Juravlee460d1d2015-09-29 04:52:17 +01004568void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
4569 HUnresolvedInstanceFieldGet* instruction) {
4570 FieldAccessCallingConventionX86_64 calling_convention;
4571 codegen_->CreateUnresolvedFieldLocationSummary(
4572 instruction, instruction->GetFieldType(), calling_convention);
4573}
4574
4575void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
4576 HUnresolvedInstanceFieldGet* instruction) {
4577 FieldAccessCallingConventionX86_64 calling_convention;
4578 codegen_->GenerateUnresolvedFieldAccess(instruction,
4579 instruction->GetFieldType(),
4580 instruction->GetFieldIndex(),
4581 instruction->GetDexPc(),
4582 calling_convention);
4583}
4584
4585void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
4586 HUnresolvedInstanceFieldSet* instruction) {
4587 FieldAccessCallingConventionX86_64 calling_convention;
4588 codegen_->CreateUnresolvedFieldLocationSummary(
4589 instruction, instruction->GetFieldType(), calling_convention);
4590}
4591
4592void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
4593 HUnresolvedInstanceFieldSet* instruction) {
4594 FieldAccessCallingConventionX86_64 calling_convention;
4595 codegen_->GenerateUnresolvedFieldAccess(instruction,
4596 instruction->GetFieldType(),
4597 instruction->GetFieldIndex(),
4598 instruction->GetDexPc(),
4599 calling_convention);
4600}
4601
4602void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
4603 HUnresolvedStaticFieldGet* instruction) {
4604 FieldAccessCallingConventionX86_64 calling_convention;
4605 codegen_->CreateUnresolvedFieldLocationSummary(
4606 instruction, instruction->GetFieldType(), calling_convention);
4607}
4608
4609void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
4610 HUnresolvedStaticFieldGet* instruction) {
4611 FieldAccessCallingConventionX86_64 calling_convention;
4612 codegen_->GenerateUnresolvedFieldAccess(instruction,
4613 instruction->GetFieldType(),
4614 instruction->GetFieldIndex(),
4615 instruction->GetDexPc(),
4616 calling_convention);
4617}
4618
4619void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
4620 HUnresolvedStaticFieldSet* instruction) {
4621 FieldAccessCallingConventionX86_64 calling_convention;
4622 codegen_->CreateUnresolvedFieldLocationSummary(
4623 instruction, instruction->GetFieldType(), calling_convention);
4624}
4625
4626void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
4627 HUnresolvedStaticFieldSet* instruction) {
4628 FieldAccessCallingConventionX86_64 calling_convention;
4629 codegen_->GenerateUnresolvedFieldAccess(instruction,
4630 instruction->GetFieldType(),
4631 instruction->GetFieldIndex(),
4632 instruction->GetDexPc(),
4633 calling_convention);
4634}
4635
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004636void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004637 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4638 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
4639 ? Location::RequiresRegister()
4640 : Location::Any();
4641 locations->SetInAt(0, loc);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004642}
4643
Calin Juravle2ae48182016-03-16 14:05:09 +00004644void CodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
4645 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004646 return;
4647 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004648 LocationSummary* locations = instruction->GetLocations();
4649 Location obj = locations->InAt(0);
4650
4651 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
Calin Juravle2ae48182016-03-16 14:05:09 +00004652 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004653}
4654
Calin Juravle2ae48182016-03-16 14:05:09 +00004655void CodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004656 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004657 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004658
4659 LocationSummary* locations = instruction->GetLocations();
4660 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004661
4662 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00004663 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004664 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004665 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004666 } else {
4667 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004668 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004669 __ jmp(slow_path->GetEntryLabel());
4670 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004671 }
4672 __ j(kEqual, slow_path->GetEntryLabel());
4673}
4674
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004675void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004676 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004677}
4678
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004679void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004680 bool object_array_get_with_read_barrier =
4681 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004682 LocationSummary* locations =
Roland Levillain0d5a2812015-11-13 10:07:31 +00004683 new (GetGraph()->GetArena()) LocationSummary(instruction,
4684 object_array_get_with_read_barrier ?
4685 LocationSummary::kCallOnSlowPath :
4686 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004687 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004688 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004689 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004690 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04004691 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004692 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4693 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4694 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004695 // The output overlaps for an object array get when read barriers
4696 // are enabled: we do not want the move to overwrite the array's
4697 // location, as we need it to emit the read barrier.
4698 locations->SetOut(
4699 Location::RequiresRegister(),
4700 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004701 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004702}
4703
4704void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
4705 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004706 Location obj_loc = locations->InAt(0);
4707 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004708 Location index = locations->InAt(1);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004709 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004710 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004711
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004712 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004713 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004714 case Primitive::kPrimBoolean: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004715 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004716 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004717 break;
4718 }
4719
4720 case Primitive::kPrimByte: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004721 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004722 __ movsxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004723 break;
4724 }
4725
4726 case Primitive::kPrimShort: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004727 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004728 __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004729 break;
4730 }
4731
4732 case Primitive::kPrimChar: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004733 CpuRegister out = out_loc.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07004734 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
4735 // Branch cases into compressed and uncompressed for each index's type.
4736 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
4737 NearLabel done, not_compressed;
Vladimir Marko3c89d422017-02-17 11:30:23 +00004738 __ testb(Address(obj, count_offset), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07004739 codegen_->MaybeRecordImplicitNullCheck(instruction);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01004740 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4741 "Expecting 0=compressed, 1=uncompressed");
4742 __ j(kNotZero, &not_compressed);
jessicahandojo4877b792016-09-08 19:49:13 -07004743 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
4744 __ jmp(&done);
4745 __ Bind(&not_compressed);
4746 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
4747 __ Bind(&done);
4748 } else {
4749 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
4750 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004751 break;
4752 }
4753
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004754 case Primitive::kPrimInt: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004755 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004756 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004757 break;
4758 }
4759
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004760 case Primitive::kPrimNot: {
4761 static_assert(
4762 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4763 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004764 // /* HeapReference<Object> */ out =
4765 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4766 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004767 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01004768 // CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004769 codegen_->GenerateArrayLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00004770 instruction, out_loc, obj, data_offset, index, /* needs_null_check */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004771 } else {
4772 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004773 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
4774 codegen_->MaybeRecordImplicitNullCheck(instruction);
4775 // If read barriers are enabled, emit read barriers other than
4776 // Baker's using a slow path (and also unpoison the loaded
4777 // reference, if heap poisoning is enabled).
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004778 if (index.IsConstant()) {
4779 uint32_t offset =
4780 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004781 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4782 } else {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004783 codegen_->MaybeGenerateReadBarrierSlow(
4784 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4785 }
4786 }
4787 break;
4788 }
4789
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004790 case Primitive::kPrimLong: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004791 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004792 __ movq(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004793 break;
4794 }
4795
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004796 case Primitive::kPrimFloat: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004797 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004798 __ movss(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004799 break;
4800 }
4801
4802 case Primitive::kPrimDouble: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004803 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004804 __ movsd(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01004805 break;
4806 }
4807
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004808 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004809 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004810 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004811 }
Roland Levillain4d027112015-07-01 15:41:14 +01004812
4813 if (type == Primitive::kPrimNot) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004814 // Potential implicit null checks, in the case of reference
4815 // arrays, are handled in the previous switch statement.
4816 } else {
4817 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004818 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004819}
4820
4821void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004822 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004823
4824 bool needs_write_barrier =
4825 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004826 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004827
Nicolas Geoffray39468442014-09-02 15:17:15 +01004828 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004829 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01004830 may_need_runtime_call_for_type_check ?
Roland Levillain0d5a2812015-11-13 10:07:31 +00004831 LocationSummary::kCallOnSlowPath :
4832 LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004833
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004834 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04004835 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4836 if (Primitive::IsFloatingPointType(value_type)) {
4837 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004838 } else {
4839 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4840 }
4841
4842 if (needs_write_barrier) {
4843 // Temporary registers for the write barrier.
Roland Levillain16d9f942016-08-25 17:27:56 +01004844 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004845 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004846 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004847}
4848
4849void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
4850 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004851 Location array_loc = locations->InAt(0);
4852 CpuRegister array = array_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004853 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004854 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004855 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004856 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004857 bool needs_write_barrier =
4858 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004859 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4860 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4861 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004862
4863 switch (value_type) {
4864 case Primitive::kPrimBoolean:
4865 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004866 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004867 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_1, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004868 if (value.IsRegister()) {
4869 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004870 } else {
Nicolas Geoffray78612082017-07-24 14:18:53 +01004871 __ movb(address, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004872 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004873 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004874 break;
4875 }
4876
4877 case Primitive::kPrimShort:
4878 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004879 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004880 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_2, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004881 if (value.IsRegister()) {
4882 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004883 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004884 DCHECK(value.IsConstant()) << value;
Nicolas Geoffray78612082017-07-24 14:18:53 +01004885 __ movw(address, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004886 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004887 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004888 break;
4889 }
4890
4891 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004892 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004893 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00004894
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004895 if (!value.IsRegister()) {
4896 // Just setting null.
4897 DCHECK(instruction->InputAt(2)->IsNullConstant());
4898 DCHECK(value.IsConstant()) << value;
4899 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004900 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004901 DCHECK(!needs_write_barrier);
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004902 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004903 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004904 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004905
4906 DCHECK(needs_write_barrier);
4907 CpuRegister register_value = value.AsRegister<CpuRegister>();
Roland Levillain16d9f942016-08-25 17:27:56 +01004908 // We cannot use a NearLabel for `done`, as its range may be too
4909 // short when Baker read barriers are enabled.
4910 Label done;
4911 NearLabel not_null, do_put;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004912 SlowPathCode* slow_path = nullptr;
Roland Levillain16d9f942016-08-25 17:27:56 +01004913 Location temp_loc = locations->GetTemp(0);
4914 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004915 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004916 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86_64(instruction);
4917 codegen_->AddSlowPath(slow_path);
4918 if (instruction->GetValueCanBeNull()) {
4919 __ testl(register_value, register_value);
4920 __ j(kNotEqual, &not_null);
4921 __ movl(address, Immediate(0));
4922 codegen_->MaybeRecordImplicitNullCheck(instruction);
4923 __ jmp(&done);
4924 __ Bind(&not_null);
4925 }
4926
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004927 // Note that when Baker read barriers are enabled, the type
4928 // checks are performed without read barriers. This is fine,
4929 // even in the case where a class object is in the from-space
4930 // after the flip, as a comparison involving such a type would
4931 // not produce a false positive; it may of course produce a
4932 // false negative, in which case we would take the ArraySet
4933 // slow path.
Roland Levillain16d9f942016-08-25 17:27:56 +01004934
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004935 // /* HeapReference<Class> */ temp = array->klass_
4936 __ movl(temp, Address(array, class_offset));
4937 codegen_->MaybeRecordImplicitNullCheck(instruction);
4938 __ MaybeUnpoisonHeapReference(temp);
Roland Levillain16d9f942016-08-25 17:27:56 +01004939
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004940 // /* HeapReference<Class> */ temp = temp->component_type_
4941 __ movl(temp, Address(temp, component_offset));
4942 // If heap poisoning is enabled, no need to unpoison `temp`
4943 // nor the object reference in `register_value->klass`, as
4944 // we are comparing two poisoned references.
4945 __ cmpl(temp, Address(register_value, class_offset));
Roland Levillain16d9f942016-08-25 17:27:56 +01004946
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004947 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4948 __ j(kEqual, &do_put);
4949 // If heap poisoning is enabled, the `temp` reference has
4950 // not been unpoisoned yet; unpoison it now.
Roland Levillain0d5a2812015-11-13 10:07:31 +00004951 __ MaybeUnpoisonHeapReference(temp);
4952
Roland Levillain9d6e1f82016-09-05 15:57:33 +01004953 // If heap poisoning is enabled, no need to unpoison the
4954 // heap reference loaded below, as it is only used for a
4955 // comparison with null.
4956 __ cmpl(Address(temp, super_offset), Immediate(0));
4957 __ j(kNotEqual, slow_path->GetEntryLabel());
4958 __ Bind(&do_put);
4959 } else {
4960 __ j(kNotEqual, slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004961 }
4962 }
4963
4964 if (kPoisonHeapReferences) {
4965 __ movl(temp, register_value);
4966 __ PoisonHeapReference(temp);
4967 __ movl(address, temp);
4968 } else {
4969 __ movl(address, register_value);
4970 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00004971 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004972 codegen_->MaybeRecordImplicitNullCheck(instruction);
4973 }
4974
4975 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
4976 codegen_->MarkGCCard(
4977 temp, card, array, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
4978 __ Bind(&done);
4979
4980 if (slow_path != nullptr) {
4981 __ Bind(slow_path->GetExitLabel());
4982 }
4983
4984 break;
4985 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00004986
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004987 case Primitive::kPrimInt: {
4988 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004989 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004990 if (value.IsRegister()) {
4991 __ movl(address, value.AsRegister<CpuRegister>());
4992 } else {
4993 DCHECK(value.IsConstant()) << value;
4994 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4995 __ movl(address, Immediate(v));
4996 }
4997 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004998 break;
4999 }
5000
5001 case Primitive::kPrimLong: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005002 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005003 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005004 if (value.IsRegister()) {
5005 __ movq(address, value.AsRegister<CpuRegister>());
Mark Mendellea5af682015-10-22 17:35:49 -04005006 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005007 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005008 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005009 Address address_high =
5010 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04005011 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005012 }
5013 break;
5014 }
5015
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005016 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005017 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005018 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005019 if (value.IsFpuRegister()) {
5020 __ movss(address, value.AsFpuRegister<XmmRegister>());
5021 } else {
5022 DCHECK(value.IsConstant());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005023 int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
Mark Mendellea5af682015-10-22 17:35:49 -04005024 __ movl(address, Immediate(v));
5025 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005026 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005027 break;
5028 }
5029
5030 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005031 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005032 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005033 if (value.IsFpuRegister()) {
5034 __ movsd(address, value.AsFpuRegister<XmmRegister>());
5035 codegen_->MaybeRecordImplicitNullCheck(instruction);
5036 } else {
5037 int64_t v =
5038 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005039 Address address_high =
5040 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04005041 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
5042 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005043 break;
5044 }
5045
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005046 case Primitive::kPrimVoid:
5047 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07005048 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005049 }
5050}
5051
5052void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005053 LocationSummary* locations =
5054 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005055 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellee8d9712016-07-12 11:13:15 -04005056 if (!instruction->IsEmittedAtUseSite()) {
5057 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5058 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005059}
5060
5061void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
Mark Mendellee8d9712016-07-12 11:13:15 -04005062 if (instruction->IsEmittedAtUseSite()) {
5063 return;
5064 }
5065
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005066 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01005067 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005068 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
5069 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005070 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00005071 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo4877b792016-09-08 19:49:13 -07005072 // Mask out most significant bit in case the array is String's array of char.
5073 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005074 __ shrl(out, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005075 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005076}
5077
5078void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005079 RegisterSet caller_saves = RegisterSet::Empty();
5080 InvokeRuntimeCallingConvention calling_convention;
5081 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5082 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5083 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Mark Mendellf60c90b2015-03-04 15:12:59 -05005084 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendellee8d9712016-07-12 11:13:15 -04005085 HInstruction* length = instruction->InputAt(1);
5086 if (!length->IsEmittedAtUseSite()) {
5087 locations->SetInAt(1, Location::RegisterOrConstant(length));
5088 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005089}
5090
5091void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
5092 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05005093 Location index_loc = locations->InAt(0);
5094 Location length_loc = locations->InAt(1);
Mark Mendellee8d9712016-07-12 11:13:15 -04005095 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005096
Mark Mendell99dbd682015-04-22 16:18:52 -04005097 if (length_loc.IsConstant()) {
5098 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
5099 if (index_loc.IsConstant()) {
5100 // BCE will remove the bounds check if we are guarenteed to pass.
5101 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5102 if (index < 0 || index >= length) {
5103 codegen_->AddSlowPath(slow_path);
5104 __ jmp(slow_path->GetEntryLabel());
5105 } else {
5106 // Some optimization after BCE may have generated this, and we should not
5107 // generate a bounds check if it is a valid range.
5108 }
5109 return;
5110 }
5111
5112 // We have to reverse the jump condition because the length is the constant.
5113 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
5114 __ cmpl(index_reg, Immediate(length));
5115 codegen_->AddSlowPath(slow_path);
5116 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005117 } else {
Mark Mendellee8d9712016-07-12 11:13:15 -04005118 HInstruction* array_length = instruction->InputAt(1);
5119 if (array_length->IsEmittedAtUseSite()) {
5120 // Address the length field in the array.
5121 DCHECK(array_length->IsArrayLength());
5122 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
5123 Location array_loc = array_length->GetLocations()->InAt(0);
5124 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
jessicahandojo4877b792016-09-08 19:49:13 -07005125 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005126 // TODO: if index_loc.IsConstant(), compare twice the index (to compensate for
5127 // the string compression flag) with the in-memory length and avoid the temporary.
jessicahandojo4877b792016-09-08 19:49:13 -07005128 CpuRegister length_reg = CpuRegister(TMP);
5129 __ movl(length_reg, array_len);
5130 codegen_->MaybeRecordImplicitNullCheck(array_length);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005131 __ shrl(length_reg, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005132 codegen_->GenerateIntCompare(length_reg, index_loc);
Mark Mendellee8d9712016-07-12 11:13:15 -04005133 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07005134 // Checking the bound for general case:
5135 // Array of char or String's array when the compression feature off.
5136 if (index_loc.IsConstant()) {
5137 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5138 __ cmpl(array_len, Immediate(value));
5139 } else {
5140 __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
5141 }
5142 codegen_->MaybeRecordImplicitNullCheck(array_length);
Mark Mendellee8d9712016-07-12 11:13:15 -04005143 }
Mark Mendell99dbd682015-04-22 16:18:52 -04005144 } else {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005145 codegen_->GenerateIntCompare(length_loc, index_loc);
Mark Mendell99dbd682015-04-22 16:18:52 -04005146 }
5147 codegen_->AddSlowPath(slow_path);
5148 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005149 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005150}
5151
5152void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
5153 CpuRegister card,
5154 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005155 CpuRegister value,
5156 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04005157 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005158 if (value_can_be_null) {
5159 __ testl(value, value);
5160 __ j(kEqual, &is_null);
5161 }
Andreas Gampe542451c2016-07-26 09:02:02 -07005162 __ gs()->movq(card, Address::Absolute(Thread::CardTableOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005163 /* no_rip */ true));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005164 __ movq(temp, object);
5165 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillain4d027112015-07-01 15:41:14 +01005166 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005167 if (value_can_be_null) {
5168 __ Bind(&is_null);
5169 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005170}
5171
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005172void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005173 LOG(FATAL) << "Unimplemented";
5174}
5175
5176void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005177 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5178}
5179
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005180void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01005181 LocationSummary* locations =
5182 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Aart Bikb13c65b2017-03-21 20:14:07 -07005183 // In suspend check slow path, usually there are no caller-save registers at all.
5184 // If SIMD instructions are present, however, we force spilling all live SIMD
5185 // registers in full width (since the runtime only saves/restores lower part).
Aart Bik5576f372017-03-23 16:17:37 -07005186 locations->SetCustomSlowPathCallerSaves(
5187 GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005188}
5189
5190void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005191 HBasicBlock* block = instruction->GetBlock();
5192 if (block->GetLoopInformation() != nullptr) {
5193 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5194 // The back edge will generate the suspend check.
5195 return;
5196 }
5197 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5198 // The goto will generate the suspend check.
5199 return;
5200 }
5201 GenerateSuspendCheck(instruction, nullptr);
5202}
5203
5204void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
5205 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005206 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005207 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
5208 if (slow_path == nullptr) {
5209 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction, successor);
5210 instruction->SetSlowPath(slow_path);
5211 codegen_->AddSlowPath(slow_path);
5212 if (successor != nullptr) {
5213 DCHECK(successor->IsLoopHeader());
5214 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5215 }
5216 } else {
5217 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5218 }
5219
Andreas Gampe542451c2016-07-26 09:02:02 -07005220 __ gs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005221 /* no_rip */ true),
5222 Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005223 if (successor == nullptr) {
5224 __ j(kNotEqual, slow_path->GetEntryLabel());
5225 __ Bind(slow_path->GetReturnLabel());
5226 } else {
5227 __ j(kEqual, codegen_->GetLabelOf(successor));
5228 __ jmp(slow_path->GetEntryLabel());
5229 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005230}
5231
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005232X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
5233 return codegen_->GetAssembler();
5234}
5235
5236void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005237 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005238 Location source = move->GetSource();
5239 Location destination = move->GetDestination();
5240
5241 if (source.IsRegister()) {
5242 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005243 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005244 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005245 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005246 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005247 } else {
5248 DCHECK(destination.IsDoubleStackSlot());
5249 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005250 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005251 }
5252 } else if (source.IsStackSlot()) {
5253 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005254 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005255 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005256 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005257 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005258 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005259 } else {
5260 DCHECK(destination.IsStackSlot());
5261 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5262 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5263 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005264 } else if (source.IsDoubleStackSlot()) {
5265 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005266 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005267 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005268 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005269 __ movsd(destination.AsFpuRegister<XmmRegister>(),
5270 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005271 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01005272 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005273 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5274 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5275 }
Aart Bik5576f372017-03-23 16:17:37 -07005276 } else if (source.IsSIMDStackSlot()) {
5277 DCHECK(destination.IsFpuRegister());
5278 __ movups(destination.AsFpuRegister<XmmRegister>(),
5279 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005280 } else if (source.IsConstant()) {
5281 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005282 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5283 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005284 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005285 if (value == 0) {
5286 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
5287 } else {
5288 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
5289 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005290 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005291 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005292 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005293 }
5294 } else if (constant->IsLongConstant()) {
5295 int64_t value = constant->AsLongConstant()->GetValue();
5296 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04005297 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005298 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005299 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005300 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005301 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005302 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005303 float fp_value = constant->AsFloatConstant()->GetValue();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005304 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005305 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005306 codegen_->Load32BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005307 } else {
5308 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005309 Immediate imm(bit_cast<int32_t, float>(fp_value));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005310 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
5311 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005312 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005313 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005314 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00005315 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005316 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005317 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005318 codegen_->Load64BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005319 } else {
5320 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005321 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005322 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005323 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005324 } else if (source.IsFpuRegister()) {
5325 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005326 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005327 } else if (destination.IsStackSlot()) {
5328 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005329 source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07005330 } else if (destination.IsDoubleStackSlot()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005331 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005332 source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07005333 } else {
5334 DCHECK(destination.IsSIMDStackSlot());
5335 __ movups(Address(CpuRegister(RSP), destination.GetStackIndex()),
5336 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005337 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005338 }
5339}
5340
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005341void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005342 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005343 __ movl(Address(CpuRegister(RSP), mem), reg);
5344 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005345}
5346
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005347void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005348 ScratchRegisterScope ensure_scratch(
5349 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5350
5351 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5352 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5353 __ movl(CpuRegister(ensure_scratch.GetRegister()),
5354 Address(CpuRegister(RSP), mem2 + stack_offset));
5355 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5356 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
5357 CpuRegister(ensure_scratch.GetRegister()));
5358}
5359
Mark Mendell8a1c7282015-06-29 15:41:28 -04005360void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg1, CpuRegister reg2) {
5361 __ movq(CpuRegister(TMP), reg1);
5362 __ movq(reg1, reg2);
5363 __ movq(reg2, CpuRegister(TMP));
5364}
5365
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005366void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
5367 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5368 __ movq(Address(CpuRegister(RSP), mem), reg);
5369 __ movq(reg, CpuRegister(TMP));
5370}
5371
5372void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
5373 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005374 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005375
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005376 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5377 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5378 __ movq(CpuRegister(ensure_scratch.GetRegister()),
5379 Address(CpuRegister(RSP), mem2 + stack_offset));
5380 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5381 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
5382 CpuRegister(ensure_scratch.GetRegister()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005383}
5384
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005385void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
5386 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5387 __ movss(Address(CpuRegister(RSP), mem), reg);
5388 __ movd(reg, CpuRegister(TMP));
5389}
5390
5391void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
5392 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5393 __ movsd(Address(CpuRegister(RSP), mem), reg);
5394 __ movd(reg, CpuRegister(TMP));
5395}
5396
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005397void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005398 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005399 Location source = move->GetSource();
5400 Location destination = move->GetDestination();
5401
5402 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell8a1c7282015-06-29 15:41:28 -04005403 Exchange64(source.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005404 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005405 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005406 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005407 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005408 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005409 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
5410 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005411 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005412 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005413 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005414 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5415 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005416 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005417 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
5418 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5419 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005420 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005421 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005422 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005423 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005424 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005425 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005426 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005427 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005428 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005429 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005430 }
5431}
5432
5433
5434void ParallelMoveResolverX86_64::SpillScratch(int reg) {
5435 __ pushq(CpuRegister(reg));
5436}
5437
5438
5439void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
5440 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005441}
5442
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005443void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005444 SlowPathCode* slow_path, CpuRegister class_reg) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005445 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5446 Immediate(mirror::Class::kStatusInitialized));
5447 __ j(kLess, slow_path->GetEntryLabel());
5448 __ Bind(slow_path->GetExitLabel());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005449 // No need for memory fence, thanks to the x86-64 memory model.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005450}
5451
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005452HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
5453 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005454 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00005455 case HLoadClass::LoadKind::kInvalid:
5456 LOG(FATAL) << "UNREACHABLE";
5457 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005458 case HLoadClass::LoadKind::kReferrersClass:
5459 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005460 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko94ec2db2017-09-06 17:21:03 +01005461 case HLoadClass::LoadKind::kBootImageClassTable:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005462 case HLoadClass::LoadKind::kBssEntry:
5463 DCHECK(!Runtime::Current()->UseJitCompilation());
5464 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005465 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005466 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005467 break;
Vladimir Marko764d4542017-05-16 10:31:41 +01005468 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005469 case HLoadClass::LoadKind::kRuntimeCall:
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005470 break;
5471 }
5472 return desired_class_load_kind;
5473}
5474
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005475void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005476 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005477 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00005478 // Custom calling convention: RAX serves as both input and output.
Vladimir Marko41559982017-01-06 14:04:23 +00005479 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005480 cls,
Vladimir Markoea4c1262017-02-06 19:59:33 +00005481 Location::RegisterLocation(RAX),
Vladimir Marko41559982017-01-06 14:04:23 +00005482 Location::RegisterLocation(RAX));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005483 return;
5484 }
Vladimir Marko41559982017-01-06 14:04:23 +00005485 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005486
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005487 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5488 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005489 ? LocationSummary::kCallOnSlowPath
5490 : LocationSummary::kNoCall;
5491 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005492 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005493 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005494 }
5495
Vladimir Marko41559982017-01-06 14:04:23 +00005496 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005497 locations->SetInAt(0, Location::RequiresRegister());
5498 }
5499 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00005500 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
5501 if (!kUseReadBarrier || kUseBakerReadBarrier) {
5502 // Rely on the type resolution and/or initialization to save everything.
5503 // Custom calling convention: RAX serves as both input and output.
5504 RegisterSet caller_saves = RegisterSet::Empty();
5505 caller_saves.Add(Location::RegisterLocation(RAX));
5506 locations->SetCustomSlowPathCallerSaves(caller_saves);
5507 } else {
5508 // For non-Baker read barrier we have a temp-clobbering call.
5509 }
5510 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005511}
5512
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005513Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
5514 dex::TypeIndex dex_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005515 Handle<mirror::Class> handle) {
5516 jit_class_roots_.Overwrite(
5517 TypeReference(&dex_file, dex_index), reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005518 // Add a patch entry and return the label.
5519 jit_class_patches_.emplace_back(dex_file, dex_index.index_);
5520 PatchInfo<Label>* info = &jit_class_patches_.back();
5521 return &info->label;
5522}
5523
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005524// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5525// move.
5526void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00005527 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005528 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00005529 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01005530 return;
5531 }
Vladimir Marko41559982017-01-06 14:04:23 +00005532 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01005533
Vladimir Marko41559982017-01-06 14:04:23 +00005534 LocationSummary* locations = cls->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005535 Location out_loc = locations->Out();
5536 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005537
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005538 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
5539 ? kWithoutReadBarrier
5540 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005541 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00005542 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005543 case HLoadClass::LoadKind::kReferrersClass: {
5544 DCHECK(!cls->CanCallRuntime());
5545 DCHECK(!cls->MustGenerateClinitCheck());
5546 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5547 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
5548 GenerateGcRootFieldLoad(
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005549 cls,
5550 out_loc,
5551 Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
Roland Levillain00468f32016-10-27 18:02:48 +01005552 /* fixup_label */ nullptr,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005553 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005554 break;
5555 }
5556 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005557 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005558 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005559 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
Vladimir Marko1998cd02017-01-13 13:02:58 +00005560 codegen_->RecordBootTypePatch(cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005561 break;
5562 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005563 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005564 uint32_t address = dchecked_integral_cast<uint32_t>(
5565 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5566 DCHECK_NE(address, 0u);
Colin Cross0bd97172017-03-15 16:33:27 -07005567 __ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended.
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005568 break;
5569 }
Vladimir Marko94ec2db2017-09-06 17:21:03 +01005570 case HLoadClass::LoadKind::kBootImageClassTable: {
5571 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5572 __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
5573 codegen_->RecordBootTypePatch(cls);
5574 // Extract the reference from the slot data, i.e. clear the hash bits.
5575 int32_t masked_hash = ClassTable::TableSlot::MaskHash(
5576 ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
5577 if (masked_hash != 0) {
5578 __ subl(out, Immediate(masked_hash));
5579 }
5580 break;
5581 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005582 case HLoadClass::LoadKind::kBssEntry: {
5583 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5584 /* no_rip */ false);
5585 Label* fixup_label = codegen_->NewTypeBssEntryPatch(cls);
5586 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
5587 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
5588 generate_null_check = true;
5589 break;
5590 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005591 case HLoadClass::LoadKind::kJitTableAddress: {
5592 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5593 /* no_rip */ true);
5594 Label* fixup_label =
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005595 codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005596 // /* GcRoot<mirror::Class> */ out = *address
Vladimir Markoea4c1262017-02-06 19:59:33 +00005597 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005598 break;
5599 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005600 default:
5601 LOG(FATAL) << "Unexpected load kind: " << cls->GetLoadKind();
5602 UNREACHABLE();
5603 }
5604
5605 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5606 DCHECK(cls->CanCallRuntime());
5607 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
5608 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5609 codegen_->AddSlowPath(slow_path);
5610 if (generate_null_check) {
5611 __ testl(out, out);
5612 __ j(kEqual, slow_path->GetEntryLabel());
5613 }
5614 if (cls->MustGenerateClinitCheck()) {
5615 GenerateClassInitializationCheck(slow_path, out);
5616 } else {
5617 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005618 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005619 }
5620}
5621
5622void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
5623 LocationSummary* locations =
5624 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5625 locations->SetInAt(0, Location::RequiresRegister());
5626 if (check->HasUses()) {
5627 locations->SetOut(Location::SameAsFirstInput());
5628 }
5629}
5630
5631void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005632 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005633 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005634 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005635 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005636 GenerateClassInitializationCheck(slow_path,
5637 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005638}
5639
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005640HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
5641 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005642 switch (desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005643 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01005644 case HLoadString::LoadKind::kBootImageInternTable:
Vladimir Markoaad75c62016-10-03 08:46:48 +00005645 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01005646 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005647 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005648 case HLoadString::LoadKind::kJitTableAddress:
5649 DCHECK(Runtime::Current()->UseJitCompilation());
5650 break;
Vladimir Marko764d4542017-05-16 10:31:41 +01005651 case HLoadString::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005652 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005653 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005654 }
5655 return desired_string_load_kind;
5656}
5657
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005658void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005659 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005660 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005661 if (load->GetLoadKind() == HLoadString::LoadKind::kRuntimeCall) {
Christina Wadsworthabb341b2016-08-31 16:29:44 -07005662 locations->SetOut(Location::RegisterLocation(RAX));
5663 } else {
5664 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005665 if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) {
5666 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00005667 // Rely on the pResolveString to save everything.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005668 // Custom calling convention: RAX serves as both input and output.
5669 RegisterSet caller_saves = RegisterSet::Empty();
5670 caller_saves.Add(Location::RegisterLocation(RAX));
5671 locations->SetCustomSlowPathCallerSaves(caller_saves);
5672 } else {
5673 // For non-Baker read barrier we have a temp-clobbering call.
5674 }
5675 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005676 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005677}
5678
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005679Label* CodeGeneratorX86_64::NewJitRootStringPatch(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005680 dex::StringIndex dex_index,
5681 Handle<mirror::String> handle) {
5682 jit_string_roots_.Overwrite(
5683 StringReference(&dex_file, dex_index), reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005684 // Add a patch entry and return the label.
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005685 jit_string_patches_.emplace_back(dex_file, dex_index.index_);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005686 PatchInfo<Label>* info = &jit_string_patches_.back();
5687 return &info->label;
5688}
5689
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005690// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5691// move.
5692void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005693 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005694 Location out_loc = locations->Out();
5695 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005696
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005697 switch (load->GetLoadKind()) {
5698 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005699 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005700 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
Vladimir Markoaad75c62016-10-03 08:46:48 +00005701 codegen_->RecordBootStringPatch(load);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01005702 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005703 }
5704 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005705 uint32_t address = dchecked_integral_cast<uint32_t>(
5706 reinterpret_cast<uintptr_t>(load->GetString().Get()));
5707 DCHECK_NE(address, 0u);
Colin Cross0bd97172017-03-15 16:33:27 -07005708 __ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended.
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01005709 return;
5710 }
5711 case HLoadString::LoadKind::kBootImageInternTable: {
5712 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5713 __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
5714 codegen_->RecordBootStringPatch(load);
5715 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005716 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00005717 case HLoadString::LoadKind::kBssEntry: {
5718 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5719 /* no_rip */ false);
5720 Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
5721 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005722 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005723 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
5724 codegen_->AddSlowPath(slow_path);
5725 __ testl(out, out);
5726 __ j(kEqual, slow_path->GetEntryLabel());
5727 __ Bind(slow_path->GetExitLabel());
5728 return;
5729 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005730 case HLoadString::LoadKind::kJitTableAddress: {
5731 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
5732 /* no_rip */ true);
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005733 Label* fixup_label = codegen_->NewJitRootStringPatch(
5734 load->GetDexFile(), load->GetStringIndex(), load->GetString());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005735 // /* GcRoot<mirror::String> */ out = *address
5736 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
5737 return;
5738 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005739 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005740 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005741 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005742
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005743 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01005744 // Custom calling convention: RAX serves as both input and output.
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005745 __ movl(CpuRegister(RAX), Immediate(load->GetStringIndex().index_));
Christina Wadsworthabb341b2016-08-31 16:29:44 -07005746 codegen_->InvokeRuntime(kQuickResolveString,
5747 load,
5748 load->GetDexPc());
5749 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005750}
5751
David Brazdilcb1c0552015-08-04 16:22:25 +01005752static Address GetExceptionTlsAddress() {
Andreas Gampe542451c2016-07-26 09:02:02 -07005753 return Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>().Int32Value(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005754 /* no_rip */ true);
David Brazdilcb1c0552015-08-04 16:22:25 +01005755}
5756
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005757void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
5758 LocationSummary* locations =
5759 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5760 locations->SetOut(Location::RequiresRegister());
5761}
5762
5763void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005764 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
5765}
5766
5767void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
5768 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5769}
5770
5771void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5772 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005773}
5774
5775void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
5776 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005777 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005778 InvokeRuntimeCallingConvention calling_convention;
5779 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5780}
5781
5782void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01005783 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00005784 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005785}
5786
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005787static bool CheckCastTypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5788 if (type_check_kind == TypeCheckKind::kInterfaceCheck && !kPoisonHeapReferences) {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07005789 // We need a temporary for holding the iftable length.
5790 return true;
5791 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005792 return kEmitCompilerReadBarrier &&
Vladimir Marko953437b2016-08-24 08:30:46 +00005793 !kUseBakerReadBarrier &&
5794 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005795 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5796 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5797}
5798
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005799static bool InstanceOfTypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5800 return kEmitCompilerReadBarrier &&
5801 !kUseBakerReadBarrier &&
5802 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5803 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5804 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5805}
5806
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005807void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005808 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005809 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01005810 bool baker_read_barrier_slow_path = false;
Roland Levillain0d5a2812015-11-13 10:07:31 +00005811 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005812 case TypeCheckKind::kExactCheck:
5813 case TypeCheckKind::kAbstractClassCheck:
5814 case TypeCheckKind::kClassHierarchyCheck:
5815 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005816 call_kind =
5817 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01005818 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005819 break;
5820 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00005821 case TypeCheckKind::kUnresolvedCheck:
5822 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005823 call_kind = LocationSummary::kCallOnSlowPath;
5824 break;
5825 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005826
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005827 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01005828 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005829 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005830 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005831 locations->SetInAt(0, Location::RequiresRegister());
5832 locations->SetInAt(1, Location::Any());
5833 // Note that TypeCheckSlowPathX86_64 uses this "out" register too.
5834 locations->SetOut(Location::RequiresRegister());
5835 // When read barriers are enabled, we need a temporary register for
5836 // some cases.
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005837 if (InstanceOfTypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005838 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005839 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005840}
5841
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005842void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005843 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005844 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005845 Location obj_loc = locations->InAt(0);
5846 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005847 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005848 Location out_loc = locations->Out();
5849 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00005850 Location maybe_temp_loc = InstanceOfTypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005851 locations->GetTemp(0) :
5852 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005853 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005854 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5855 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5856 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005857 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005858 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005859
5860 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005861 // Avoid null check if we know obj is not null.
5862 if (instruction->MustDoNullCheck()) {
5863 __ testl(obj, obj);
5864 __ j(kEqual, &zero);
5865 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005866
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005867 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005868 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005869 // /* HeapReference<Class> */ out = obj->klass_
5870 GenerateReferenceLoadTwoRegisters(instruction,
5871 out_loc,
5872 obj_loc,
5873 class_offset,
5874 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005875 if (cls.IsRegister()) {
5876 __ cmpl(out, cls.AsRegister<CpuRegister>());
5877 } else {
5878 DCHECK(cls.IsStackSlot()) << cls;
5879 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5880 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005881 if (zero.IsLinked()) {
5882 // Classes must be equal for the instanceof to succeed.
5883 __ j(kNotEqual, &zero);
5884 __ movl(out, Immediate(1));
5885 __ jmp(&done);
5886 } else {
5887 __ setcc(kEqual, out);
5888 // setcc only sets the low byte.
5889 __ andl(out, Immediate(1));
5890 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005891 break;
5892 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005893
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005894 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005895 // /* HeapReference<Class> */ out = obj->klass_
5896 GenerateReferenceLoadTwoRegisters(instruction,
5897 out_loc,
5898 obj_loc,
5899 class_offset,
5900 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005901 // If the class is abstract, we eagerly fetch the super class of the
5902 // object to avoid doing a comparison we know will fail.
5903 NearLabel loop, success;
5904 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005905 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005906 GenerateReferenceLoadOneRegister(instruction,
5907 out_loc,
5908 super_offset,
5909 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005910 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005911 __ testl(out, out);
5912 // If `out` is null, we use it for the result, and jump to `done`.
5913 __ j(kEqual, &done);
5914 if (cls.IsRegister()) {
5915 __ cmpl(out, cls.AsRegister<CpuRegister>());
5916 } else {
5917 DCHECK(cls.IsStackSlot()) << cls;
5918 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5919 }
5920 __ j(kNotEqual, &loop);
5921 __ movl(out, Immediate(1));
5922 if (zero.IsLinked()) {
5923 __ jmp(&done);
5924 }
5925 break;
5926 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005927
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005928 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005929 // /* HeapReference<Class> */ out = obj->klass_
5930 GenerateReferenceLoadTwoRegisters(instruction,
5931 out_loc,
5932 obj_loc,
5933 class_offset,
5934 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005935 // Walk over the class hierarchy to find a match.
5936 NearLabel loop, success;
5937 __ Bind(&loop);
5938 if (cls.IsRegister()) {
5939 __ cmpl(out, cls.AsRegister<CpuRegister>());
5940 } else {
5941 DCHECK(cls.IsStackSlot()) << cls;
5942 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5943 }
5944 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005945 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005946 GenerateReferenceLoadOneRegister(instruction,
5947 out_loc,
5948 super_offset,
5949 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005950 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005951 __ testl(out, out);
5952 __ j(kNotEqual, &loop);
5953 // If `out` is null, we use it for the result, and jump to `done`.
5954 __ jmp(&done);
5955 __ Bind(&success);
5956 __ movl(out, Immediate(1));
5957 if (zero.IsLinked()) {
5958 __ jmp(&done);
5959 }
5960 break;
5961 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005962
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005963 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005964 // /* HeapReference<Class> */ out = obj->klass_
5965 GenerateReferenceLoadTwoRegisters(instruction,
5966 out_loc,
5967 obj_loc,
5968 class_offset,
5969 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005970 // Do an exact check.
5971 NearLabel exact_check;
5972 if (cls.IsRegister()) {
5973 __ cmpl(out, cls.AsRegister<CpuRegister>());
5974 } else {
5975 DCHECK(cls.IsStackSlot()) << cls;
5976 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
5977 }
5978 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005979 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005980 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08005981 GenerateReferenceLoadOneRegister(instruction,
5982 out_loc,
5983 component_offset,
5984 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08005985 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005986 __ testl(out, out);
5987 // If `out` is null, we use it for the result, and jump to `done`.
5988 __ j(kEqual, &done);
5989 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5990 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005991 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005992 __ movl(out, Immediate(1));
5993 __ jmp(&done);
5994 break;
5995 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005996
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005997 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08005998 // No read barrier since the slow path will retry upon failure.
5999 // /* HeapReference<Class> */ out = obj->klass_
6000 GenerateReferenceLoadTwoRegisters(instruction,
6001 out_loc,
6002 obj_loc,
6003 class_offset,
6004 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006005 if (cls.IsRegister()) {
6006 __ cmpl(out, cls.AsRegister<CpuRegister>());
6007 } else {
6008 DCHECK(cls.IsStackSlot()) << cls;
6009 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6010 }
6011 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain0d5a2812015-11-13 10:07:31 +00006012 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
6013 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006014 codegen_->AddSlowPath(slow_path);
6015 __ j(kNotEqual, slow_path->GetEntryLabel());
6016 __ movl(out, Immediate(1));
6017 if (zero.IsLinked()) {
6018 __ jmp(&done);
6019 }
6020 break;
6021 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006022
Calin Juravle98893e12015-10-02 21:05:03 +01006023 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00006024 case TypeCheckKind::kInterfaceCheck: {
6025 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006026 // into the slow path for the unresolved and interface check
Roland Levillain0d5a2812015-11-13 10:07:31 +00006027 // cases.
6028 //
6029 // We cannot directly call the InstanceofNonTrivial runtime
6030 // entry point without resorting to a type checking slow path
6031 // here (i.e. by calling InvokeRuntime directly), as it would
6032 // require to assign fixed registers for the inputs of this
6033 // HInstanceOf instruction (following the runtime calling
6034 // convention), which might be cluttered by the potential first
6035 // read barrier emission at the beginning of this method.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006036 //
6037 // TODO: Introduce a new runtime entry point taking the object
6038 // to test (instead of its class) as argument, and let it deal
6039 // with the read barrier issues. This will let us refactor this
6040 // case of the `switch` code as it was previously (with a direct
6041 // call to the runtime not using a type checking slow path).
6042 // This should also be beneficial for the other cases above.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006043 DCHECK(locations->OnlyCallsOnSlowPath());
6044 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
6045 /* is_fatal */ false);
6046 codegen_->AddSlowPath(slow_path);
6047 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006048 if (zero.IsLinked()) {
6049 __ jmp(&done);
6050 }
6051 break;
6052 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006053 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006054
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006055 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006056 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006057 __ xorl(out, out);
6058 }
6059
6060 if (done.IsLinked()) {
6061 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006062 }
6063
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006064 if (slow_path != nullptr) {
6065 __ Bind(slow_path->GetExitLabel());
6066 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006067}
6068
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006069static bool IsTypeCheckSlowPathFatal(TypeCheckKind type_check_kind, bool throws_into_catch) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006070 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006071 case TypeCheckKind::kExactCheck:
6072 case TypeCheckKind::kAbstractClassCheck:
6073 case TypeCheckKind::kClassHierarchyCheck:
6074 case TypeCheckKind::kArrayObjectCheck:
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006075 return !throws_into_catch && !kEmitCompilerReadBarrier;
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006076 case TypeCheckKind::kInterfaceCheck:
6077 return !throws_into_catch && !kEmitCompilerReadBarrier && !kPoisonHeapReferences;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006078 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00006079 case TypeCheckKind::kUnresolvedCheck:
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006080 return false;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006081 }
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006082 LOG(FATAL) << "Unreachable";
6083 UNREACHABLE();
6084}
6085
6086void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
6087 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
6088 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6089 bool is_fatal_slow_path = IsTypeCheckSlowPathFatal(type_check_kind, throws_into_catch);
6090 LocationSummary::CallKind call_kind = is_fatal_slow_path
6091 ? LocationSummary::kNoCall
6092 : LocationSummary::kCallOnSlowPath;
Roland Levillain0d5a2812015-11-13 10:07:31 +00006093 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6094 locations->SetInAt(0, Location::RequiresRegister());
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006095 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6096 // Require a register for the interface check since there is a loop that compares the class to
6097 // a memory address.
6098 locations->SetInAt(1, Location::RequiresRegister());
6099 } else {
6100 locations->SetInAt(1, Location::Any());
6101 }
6102
Roland Levillain0d5a2812015-11-13 10:07:31 +00006103 // Note that TypeCheckSlowPathX86_64 uses this "temp" register too.
6104 locations->AddTemp(Location::RequiresRegister());
6105 // When read barriers are enabled, we need an additional temporary
6106 // register for some cases.
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006107 if (CheckCastTypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006108 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006109 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006110}
6111
6112void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006113 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006114 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006115 Location obj_loc = locations->InAt(0);
6116 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006117 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006118 Location temp_loc = locations->GetTemp(0);
6119 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006120 Location maybe_temp2_loc = CheckCastTypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006121 locations->GetTemp(1) :
6122 Location::NoLocation();
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006123 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6124 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6125 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6126 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6127 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6128 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006129 const uint32_t object_array_data_offset =
6130 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006131
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006132 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
6133 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
6134 // read barriers is done for performance and code size reasons.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006135 bool is_type_check_slow_path_fatal =
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006136 IsTypeCheckSlowPathFatal(type_check_kind, instruction->CanThrowIntoCatchBlock());
Roland Levillain0d5a2812015-11-13 10:07:31 +00006137 SlowPathCode* type_check_slow_path =
6138 new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(instruction,
6139 is_type_check_slow_path_fatal);
6140 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006141
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006142
6143 NearLabel done;
6144 // Avoid null check if we know obj is not null.
6145 if (instruction->MustDoNullCheck()) {
6146 __ testl(obj, obj);
6147 __ j(kEqual, &done);
6148 }
6149
Roland Levillain0d5a2812015-11-13 10:07:31 +00006150 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006151 case TypeCheckKind::kExactCheck:
6152 case TypeCheckKind::kArrayCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006153 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006154 GenerateReferenceLoadTwoRegisters(instruction,
6155 temp_loc,
6156 obj_loc,
6157 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006158 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006159 if (cls.IsRegister()) {
6160 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6161 } else {
6162 DCHECK(cls.IsStackSlot()) << cls;
6163 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6164 }
6165 // Jump to slow path for throwing the exception or doing a
6166 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006167 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006168 break;
6169 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006170
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006171 case TypeCheckKind::kAbstractClassCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006172 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006173 GenerateReferenceLoadTwoRegisters(instruction,
6174 temp_loc,
6175 obj_loc,
6176 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006177 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006178 // If the class is abstract, we eagerly fetch the super class of the
6179 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006180 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006181 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006182 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006183 GenerateReferenceLoadOneRegister(instruction,
6184 temp_loc,
6185 super_offset,
6186 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006187 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006188
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006189 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6190 // exception.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006191 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006192 // Otherwise, compare the classes.
6193 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006194 if (cls.IsRegister()) {
6195 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6196 } else {
6197 DCHECK(cls.IsStackSlot()) << cls;
6198 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6199 }
6200 __ j(kNotEqual, &loop);
6201 break;
6202 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006203
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006204 case TypeCheckKind::kClassHierarchyCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006205 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006206 GenerateReferenceLoadTwoRegisters(instruction,
6207 temp_loc,
6208 obj_loc,
6209 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006210 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006211 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006212 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006213 __ Bind(&loop);
6214 if (cls.IsRegister()) {
6215 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6216 } else {
6217 DCHECK(cls.IsStackSlot()) << cls;
6218 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6219 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006220 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006221
Roland Levillain0d5a2812015-11-13 10:07:31 +00006222 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006223 GenerateReferenceLoadOneRegister(instruction,
6224 temp_loc,
6225 super_offset,
6226 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006227 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006228
6229 // If the class reference currently in `temp` is not null, jump
6230 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006231 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006232 __ j(kNotZero, &loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006233 // Otherwise, jump to the slow path to throw the exception.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006234 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006235 break;
6236 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006237
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006238 case TypeCheckKind::kArrayObjectCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006239 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006240 GenerateReferenceLoadTwoRegisters(instruction,
6241 temp_loc,
6242 obj_loc,
6243 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006244 kWithoutReadBarrier);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006245 // Do an exact check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006246 NearLabel check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006247 if (cls.IsRegister()) {
6248 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6249 } else {
6250 DCHECK(cls.IsStackSlot()) << cls;
6251 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6252 }
6253 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006254
6255 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006256 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006257 GenerateReferenceLoadOneRegister(instruction,
6258 temp_loc,
6259 component_offset,
6260 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006261 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006262
6263 // If the component type is not null (i.e. the object is indeed
6264 // an array), jump to label `check_non_primitive_component_type`
6265 // to further check that this component type is not a primitive
6266 // type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006267 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006268 // Otherwise, jump to the slow path to throw the exception.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006269 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006270 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006271 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006272 break;
6273 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006274
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006275 case TypeCheckKind::kUnresolvedCheck: {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006276 // We always go into the type check slow path for the unresolved case.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006277 //
6278 // We cannot directly call the CheckCast runtime entry point
6279 // without resorting to a type checking slow path here (i.e. by
6280 // calling InvokeRuntime directly), as it would require to
6281 // assign fixed registers for the inputs of this HInstanceOf
6282 // instruction (following the runtime calling convention), which
6283 // might be cluttered by the potential first read barrier
6284 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006285 __ jmp(type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006286 break;
6287 }
6288
6289 case TypeCheckKind::kInterfaceCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006290 // Fast path for the interface check. We always go slow path for heap poisoning since
6291 // unpoisoning cls would require an extra temp.
6292 if (!kPoisonHeapReferences) {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006293 // Try to avoid read barriers to improve the fast path. We can not get false positives by
6294 // doing this.
6295 // /* HeapReference<Class> */ temp = obj->klass_
6296 GenerateReferenceLoadTwoRegisters(instruction,
6297 temp_loc,
6298 obj_loc,
6299 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006300 kWithoutReadBarrier);
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006301
6302 // /* HeapReference<Class> */ temp = temp->iftable_
6303 GenerateReferenceLoadTwoRegisters(instruction,
6304 temp_loc,
6305 temp_loc,
6306 iftable_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006307 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006308 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006309 __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006310 // Loop through the iftable and check if any class matches.
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006311 NearLabel start_loop;
6312 __ Bind(&start_loop);
Mathieu Chartier6beced42016-11-15 15:51:31 -08006313 // Need to subtract first to handle the empty array case.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006314 __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
Mathieu Chartier6beced42016-11-15 15:51:31 -08006315 __ j(kNegative, type_check_slow_path->GetEntryLabel());
6316 // Go to next interface if the classes do not match.
6317 __ cmpl(cls.AsRegister<CpuRegister>(),
6318 CodeGeneratorX86_64::ArrayAddress(temp,
6319 maybe_temp2_loc,
6320 TIMES_4,
6321 object_array_data_offset));
6322 __ j(kNotEqual, &start_loop); // Return if same class.
6323 } else {
6324 __ jmp(type_check_slow_path->GetEntryLabel());
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006325 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006326 break;
6327 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006328
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006329 if (done.IsLinked()) {
6330 __ Bind(&done);
6331 }
6332
Roland Levillain0d5a2812015-11-13 10:07:31 +00006333 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006334}
6335
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006336void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
6337 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006338 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006339 InvokeRuntimeCallingConvention calling_convention;
6340 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6341}
6342
6343void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01006344 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
Alexandre Rames8158f282015-08-07 10:26:17 +01006345 instruction,
Serban Constantinescuba45db02016-07-12 22:53:02 +01006346 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006347 if (instruction->IsEnter()) {
6348 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6349 } else {
6350 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6351 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006352}
6353
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006354void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
6355void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
6356void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
6357
6358void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6359 LocationSummary* locations =
6360 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6361 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6362 || instruction->GetResultType() == Primitive::kPrimLong);
6363 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04006364 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006365 locations->SetOut(Location::SameAsFirstInput());
6366}
6367
6368void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
6369 HandleBitwiseOperation(instruction);
6370}
6371
6372void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
6373 HandleBitwiseOperation(instruction);
6374}
6375
6376void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
6377 HandleBitwiseOperation(instruction);
6378}
6379
6380void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6381 LocationSummary* locations = instruction->GetLocations();
6382 Location first = locations->InAt(0);
6383 Location second = locations->InAt(1);
6384 DCHECK(first.Equals(locations->Out()));
6385
6386 if (instruction->GetResultType() == Primitive::kPrimInt) {
6387 if (second.IsRegister()) {
6388 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006389 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006390 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006391 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006392 } else {
6393 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006394 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006395 }
6396 } else if (second.IsConstant()) {
6397 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
6398 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006399 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006400 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006401 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006402 } else {
6403 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006404 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006405 }
6406 } else {
6407 Address address(CpuRegister(RSP), second.GetStackIndex());
6408 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006409 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006410 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006411 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006412 } else {
6413 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006414 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006415 }
6416 }
6417 } else {
6418 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006419 CpuRegister first_reg = first.AsRegister<CpuRegister>();
6420 bool second_is_constant = false;
6421 int64_t value = 0;
6422 if (second.IsConstant()) {
6423 second_is_constant = true;
6424 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006425 }
Mark Mendell40741f32015-04-20 22:10:34 -04006426 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006427
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006428 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006429 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006430 if (is_int32_value) {
6431 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
6432 } else {
6433 __ andq(first_reg, codegen_->LiteralInt64Address(value));
6434 }
6435 } else if (second.IsDoubleStackSlot()) {
6436 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006437 } else {
6438 __ andq(first_reg, second.AsRegister<CpuRegister>());
6439 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006440 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006441 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006442 if (is_int32_value) {
6443 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
6444 } else {
6445 __ orq(first_reg, codegen_->LiteralInt64Address(value));
6446 }
6447 } else if (second.IsDoubleStackSlot()) {
6448 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006449 } else {
6450 __ orq(first_reg, second.AsRegister<CpuRegister>());
6451 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006452 } else {
6453 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006454 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006455 if (is_int32_value) {
6456 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
6457 } else {
6458 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
6459 }
6460 } else if (second.IsDoubleStackSlot()) {
6461 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006462 } else {
6463 __ xorq(first_reg, second.AsRegister<CpuRegister>());
6464 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006465 }
6466 }
6467}
6468
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006469void InstructionCodeGeneratorX86_64::GenerateReferenceLoadOneRegister(
6470 HInstruction* instruction,
6471 Location out,
6472 uint32_t offset,
6473 Location maybe_temp,
6474 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006475 CpuRegister out_reg = out.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006476 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006477 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006478 if (kUseBakerReadBarrier) {
6479 // Load with fast path based Baker's read barrier.
6480 // /* HeapReference<Object> */ out = *(out + offset)
6481 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00006482 instruction, out, out_reg, offset, /* needs_null_check */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006483 } else {
6484 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006485 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006486 // in the following move operation, as we will need it for the
6487 // read barrier below.
Vladimir Marko953437b2016-08-24 08:30:46 +00006488 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006489 __ movl(maybe_temp.AsRegister<CpuRegister>(), out_reg);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006490 // /* HeapReference<Object> */ out = *(out + offset)
6491 __ movl(out_reg, Address(out_reg, offset));
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006492 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006493 }
6494 } else {
6495 // Plain load with no read barrier.
6496 // /* HeapReference<Object> */ out = *(out + offset)
6497 __ movl(out_reg, Address(out_reg, offset));
6498 __ MaybeUnpoisonHeapReference(out_reg);
6499 }
6500}
6501
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006502void InstructionCodeGeneratorX86_64::GenerateReferenceLoadTwoRegisters(
6503 HInstruction* instruction,
6504 Location out,
6505 Location obj,
6506 uint32_t offset,
6507 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006508 CpuRegister out_reg = out.AsRegister<CpuRegister>();
6509 CpuRegister obj_reg = obj.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006510 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006511 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006512 if (kUseBakerReadBarrier) {
6513 // Load with fast path based Baker's read barrier.
6514 // /* HeapReference<Object> */ out = *(obj + offset)
6515 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Vladimir Marko953437b2016-08-24 08:30:46 +00006516 instruction, out, obj_reg, offset, /* needs_null_check */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006517 } else {
6518 // Load with slow path based read barrier.
6519 // /* HeapReference<Object> */ out = *(obj + offset)
6520 __ movl(out_reg, Address(obj_reg, offset));
6521 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6522 }
6523 } else {
6524 // Plain load with no read barrier.
6525 // /* HeapReference<Object> */ out = *(obj + offset)
6526 __ movl(out_reg, Address(obj_reg, offset));
6527 __ MaybeUnpoisonHeapReference(out_reg);
6528 }
6529}
6530
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006531void InstructionCodeGeneratorX86_64::GenerateGcRootFieldLoad(
6532 HInstruction* instruction,
6533 Location root,
6534 const Address& address,
6535 Label* fixup_label,
6536 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006537 CpuRegister root_reg = root.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006538 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006539 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006540 if (kUseBakerReadBarrier) {
6541 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6542 // Baker's read barrier are used:
6543 //
Roland Levillaind966ce72017-02-09 16:20:14 +00006544 // root = obj.field;
6545 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6546 // if (temp != null) {
6547 // root = temp(root)
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006548 // }
6549
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006550 // /* GcRoot<mirror::Object> */ root = *address
6551 __ movl(root_reg, address);
6552 if (fixup_label != nullptr) {
6553 __ Bind(fixup_label);
6554 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006555 static_assert(
6556 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6557 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6558 "have different sizes.");
6559 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6560 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6561 "have different sizes.");
6562
Vladimir Marko953437b2016-08-24 08:30:46 +00006563 // Slow path marking the GC root `root`.
6564 SlowPathCode* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006565 instruction, root, /* unpoison_ref_before_marking */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006566 codegen_->AddSlowPath(slow_path);
6567
Roland Levillaind966ce72017-02-09 16:20:14 +00006568 // Test the `Thread::Current()->pReadBarrierMarkReg ## root.reg()` entrypoint.
6569 const int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +01006570 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(root.reg());
Roland Levillaind966ce72017-02-09 16:20:14 +00006571 __ gs()->cmpl(Address::Absolute(entry_point_offset, /* no_rip */ true), Immediate(0));
6572 // The entrypoint is null when the GC is not marking.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006573 __ j(kNotEqual, slow_path->GetEntryLabel());
6574 __ Bind(slow_path->GetExitLabel());
6575 } else {
6576 // GC root loaded through a slow path for read barriers other
6577 // than Baker's.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006578 // /* GcRoot<mirror::Object>* */ root = address
6579 __ leaq(root_reg, address);
6580 if (fixup_label != nullptr) {
6581 __ Bind(fixup_label);
6582 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006583 // /* mirror::Object* */ root = root->Read()
6584 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6585 }
6586 } else {
6587 // Plain GC root load with no read barrier.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006588 // /* GcRoot<mirror::Object> */ root = *address
6589 __ movl(root_reg, address);
6590 if (fixup_label != nullptr) {
6591 __ Bind(fixup_label);
6592 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006593 // Note that GC roots are not affected by heap poisoning, thus we
6594 // do not have to unpoison `root_reg` here.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006595 }
6596}
6597
6598void CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6599 Location ref,
6600 CpuRegister obj,
6601 uint32_t offset,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006602 bool needs_null_check) {
6603 DCHECK(kEmitCompilerReadBarrier);
6604 DCHECK(kUseBakerReadBarrier);
6605
6606 // /* HeapReference<Object> */ ref = *(obj + offset)
6607 Address src(obj, offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00006608 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006609}
6610
6611void CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6612 Location ref,
6613 CpuRegister obj,
6614 uint32_t data_offset,
6615 Location index,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006616 bool needs_null_check) {
6617 DCHECK(kEmitCompilerReadBarrier);
6618 DCHECK(kUseBakerReadBarrier);
6619
Roland Levillain3d312422016-06-23 13:53:42 +01006620 static_assert(
6621 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6622 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006623 // /* HeapReference<Object> */ ref =
6624 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006625 Address src = CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00006626 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006627}
6628
6629void CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6630 Location ref,
6631 CpuRegister obj,
6632 const Address& src,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006633 bool needs_null_check,
6634 bool always_update_field,
6635 CpuRegister* temp1,
6636 CpuRegister* temp2) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006637 DCHECK(kEmitCompilerReadBarrier);
6638 DCHECK(kUseBakerReadBarrier);
6639
6640 // In slow path based read barriers, the read barrier call is
6641 // inserted after the original load. However, in fast path based
6642 // Baker's read barriers, we need to perform the load of
6643 // mirror::Object::monitor_ *before* the original reference load.
6644 // This load-load ordering is required by the read barrier.
6645 // The fast path/slow path (for Baker's algorithm) should look like:
6646 //
6647 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6648 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6649 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006650 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006651 // if (is_gray) {
6652 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6653 // }
6654 //
6655 // Note: the original implementation in ReadBarrier::Barrier is
6656 // slightly more complex as:
6657 // - it implements the load-load fence using a data dependency on
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006658 // the high-bits of rb_state, which are expected to be all zeroes
6659 // (we use CodeGeneratorX86_64::GenerateMemoryBarrier instead
6660 // here, which is a no-op thanks to the x86-64 memory model);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006661 // - it performs additional checks that we do not do here for
6662 // performance reasons.
6663
6664 CpuRegister ref_reg = ref.AsRegister<CpuRegister>();
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006665 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6666
Vladimir Marko953437b2016-08-24 08:30:46 +00006667 // Given the numeric representation, it's enough to check the low bit of the rb_state.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006668 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
6669 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko953437b2016-08-24 08:30:46 +00006670 constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
6671 constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
6672 constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
6673
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07006674 // if (rb_state == ReadBarrier::GrayState())
Vladimir Marko953437b2016-08-24 08:30:46 +00006675 // ref = ReadBarrier::Mark(ref);
6676 // At this point, just do the "if" and make sure that flags are preserved until the branch.
6677 __ testb(Address(obj, monitor_offset + gray_byte_position), Immediate(test_value));
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006678 if (needs_null_check) {
6679 MaybeRecordImplicitNullCheck(instruction);
6680 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006681
6682 // Load fence to prevent load-load reordering.
6683 // Note that this is a no-op, thanks to the x86-64 memory model.
6684 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6685
6686 // The actual reference load.
6687 // /* HeapReference<Object> */ ref = *src
Vladimir Marko953437b2016-08-24 08:30:46 +00006688 __ movl(ref_reg, src); // Flags are unaffected.
6689
6690 // Note: Reference unpoisoning modifies the flags, so we need to delay it after the branch.
6691 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01006692 SlowPathCode* slow_path;
6693 if (always_update_field) {
6694 DCHECK(temp1 != nullptr);
6695 DCHECK(temp2 != nullptr);
6696 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkAndUpdateFieldSlowPathX86_64(
6697 instruction, ref, obj, src, /* unpoison_ref_before_marking */ true, *temp1, *temp2);
6698 } else {
6699 slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(
6700 instruction, ref, /* unpoison_ref_before_marking */ true);
6701 }
Vladimir Marko953437b2016-08-24 08:30:46 +00006702 AddSlowPath(slow_path);
6703
6704 // We have done the "if" of the gray bit check above, now branch based on the flags.
6705 __ j(kNotZero, slow_path->GetEntryLabel());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006706
6707 // Object* ref = ref_addr->AsMirrorPtr()
6708 __ MaybeUnpoisonHeapReference(ref_reg);
6709
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006710 __ Bind(slow_path->GetExitLabel());
6711}
6712
6713void CodeGeneratorX86_64::GenerateReadBarrierSlow(HInstruction* instruction,
6714 Location out,
6715 Location ref,
6716 Location obj,
6717 uint32_t offset,
6718 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006719 DCHECK(kEmitCompilerReadBarrier);
6720
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006721 // Insert a slow path based read barrier *after* the reference load.
6722 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00006723 // If heap poisoning is enabled, the unpoisoning of the loaded
6724 // reference will be carried out by the runtime within the slow
6725 // path.
6726 //
6727 // Note that `ref` currently does not get unpoisoned (when heap
6728 // poisoning is enabled), which is alright as the `ref` argument is
6729 // not used by the artReadBarrierSlow entry point.
6730 //
6731 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6732 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6733 ReadBarrierForHeapReferenceSlowPathX86_64(instruction, out, ref, obj, offset, index);
6734 AddSlowPath(slow_path);
6735
Roland Levillain0d5a2812015-11-13 10:07:31 +00006736 __ jmp(slow_path->GetEntryLabel());
6737 __ Bind(slow_path->GetExitLabel());
6738}
6739
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006740void CodeGeneratorX86_64::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6741 Location out,
6742 Location ref,
6743 Location obj,
6744 uint32_t offset,
6745 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006746 if (kEmitCompilerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006747 // Baker's read barriers shall be handled by the fast path
6748 // (CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier).
6749 DCHECK(!kUseBakerReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006750 // If heap poisoning is enabled, unpoisoning will be taken care of
6751 // by the runtime within the slow path.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006752 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006753 } else if (kPoisonHeapReferences) {
6754 __ UnpoisonHeapReference(out.AsRegister<CpuRegister>());
6755 }
6756}
6757
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006758void CodeGeneratorX86_64::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6759 Location out,
6760 Location root) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006761 DCHECK(kEmitCompilerReadBarrier);
6762
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006763 // Insert a slow path based read barrier *after* the GC root load.
6764 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00006765 // Note that GC roots are not affected by heap poisoning, so we do
6766 // not need to do anything special for this here.
6767 SlowPathCode* slow_path =
6768 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathX86_64(instruction, out, root);
6769 AddSlowPath(slow_path);
6770
Roland Levillain0d5a2812015-11-13 10:07:31 +00006771 __ jmp(slow_path->GetEntryLabel());
6772 __ Bind(slow_path->GetExitLabel());
6773}
6774
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006775void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006776 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006777 LOG(FATAL) << "Unreachable";
6778}
6779
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006780void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006781 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006782 LOG(FATAL) << "Unreachable";
6783}
6784
Mark Mendellfe57faa2015-09-18 09:26:15 -04006785// Simple implementation of packed switch - generate cascaded compare/jumps.
6786void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6787 LocationSummary* locations =
6788 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6789 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04006790 locations->AddTemp(Location::RequiresRegister());
6791 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04006792}
6793
6794void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6795 int32_t lower_bound = switch_instr->GetStartValue();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006796 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006797 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04006798 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
6799 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
6800 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006801 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6802
6803 // Should we generate smaller inline compare/jumps?
6804 if (num_entries <= kPackedSwitchJumpTableThreshold) {
6805 // Figure out the correct compare values and jump conditions.
6806 // Handle the first compare/branch as a special case because it might
6807 // jump to the default case.
6808 DCHECK_GT(num_entries, 2u);
6809 Condition first_condition;
6810 uint32_t index;
6811 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6812 if (lower_bound != 0) {
6813 first_condition = kLess;
6814 __ cmpl(value_reg_in, Immediate(lower_bound));
6815 __ j(first_condition, codegen_->GetLabelOf(default_block));
6816 __ j(kEqual, codegen_->GetLabelOf(successors[0]));
6817
6818 index = 1;
6819 } else {
6820 // Handle all the compare/jumps below.
6821 first_condition = kBelow;
6822 index = 0;
6823 }
6824
6825 // Handle the rest of the compare/jumps.
6826 for (; index + 1 < num_entries; index += 2) {
6827 int32_t compare_to_value = lower_bound + index + 1;
6828 __ cmpl(value_reg_in, Immediate(compare_to_value));
6829 // Jump to successors[index] if value < case_value[index].
6830 __ j(first_condition, codegen_->GetLabelOf(successors[index]));
6831 // Jump to successors[index + 1] if value == case_value[index + 1].
6832 __ j(kEqual, codegen_->GetLabelOf(successors[index + 1]));
6833 }
6834
6835 if (index != num_entries) {
6836 // There are an odd number of entries. Handle the last one.
6837 DCHECK_EQ(index + 1, num_entries);
Nicolas Geoffray6ce01732015-12-30 14:10:13 +00006838 __ cmpl(value_reg_in, Immediate(static_cast<int32_t>(lower_bound + index)));
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006839 __ j(kEqual, codegen_->GetLabelOf(successors[index]));
6840 }
6841
6842 // And the default for any other value.
6843 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6844 __ jmp(codegen_->GetLabelOf(default_block));
6845 }
6846 return;
6847 }
Mark Mendell9c86b482015-09-18 13:36:07 -04006848
6849 // Remove the bias, if needed.
6850 Register value_reg_out = value_reg_in.AsRegister();
6851 if (lower_bound != 0) {
6852 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
6853 value_reg_out = temp_reg.AsRegister();
6854 }
6855 CpuRegister value_reg(value_reg_out);
6856
6857 // Is the value in range?
Mark Mendell9c86b482015-09-18 13:36:07 -04006858 __ cmpl(value_reg, Immediate(num_entries - 1));
6859 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006860
Mark Mendell9c86b482015-09-18 13:36:07 -04006861 // We are in the range of the table.
6862 // Load the address of the jump table in the constant area.
6863 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04006864
Mark Mendell9c86b482015-09-18 13:36:07 -04006865 // Load the (signed) offset from the jump table.
6866 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
6867
6868 // Add the offset to the address of the table base.
6869 __ addq(temp_reg, base_reg);
6870
6871 // And jump.
6872 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006873}
6874
Aart Bikc5d47542016-01-27 17:00:35 -08006875void CodeGeneratorX86_64::Load32BitValue(CpuRegister dest, int32_t value) {
6876 if (value == 0) {
6877 __ xorl(dest, dest);
6878 } else {
6879 __ movl(dest, Immediate(value));
6880 }
6881}
6882
Mark Mendell92e83bf2015-05-07 11:25:03 -04006883void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
6884 if (value == 0) {
Aart Bikc5d47542016-01-27 17:00:35 -08006885 // Clears upper bits too.
Mark Mendell92e83bf2015-05-07 11:25:03 -04006886 __ xorl(dest, dest);
Vladimir Markoed009782016-02-22 16:54:39 +00006887 } else if (IsUint<32>(value)) {
6888 // We can use a 32 bit move, as it will zero-extend and is shorter.
Mark Mendell92e83bf2015-05-07 11:25:03 -04006889 __ movl(dest, Immediate(static_cast<int32_t>(value)));
6890 } else {
6891 __ movq(dest, Immediate(value));
6892 }
6893}
6894
Mark Mendell7c0b44f2016-02-01 10:08:35 -05006895void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, int32_t value) {
6896 if (value == 0) {
6897 __ xorps(dest, dest);
6898 } else {
6899 __ movss(dest, LiteralInt32Address(value));
6900 }
6901}
6902
6903void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, int64_t value) {
6904 if (value == 0) {
6905 __ xorpd(dest, dest);
6906 } else {
6907 __ movsd(dest, LiteralInt64Address(value));
6908 }
6909}
6910
6911void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, float value) {
6912 Load32BitValue(dest, bit_cast<int32_t, float>(value));
6913}
6914
6915void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, double value) {
6916 Load64BitValue(dest, bit_cast<int64_t, double>(value));
6917}
6918
Aart Bika19616e2016-02-01 18:57:58 -08006919void CodeGeneratorX86_64::Compare32BitValue(CpuRegister dest, int32_t value) {
6920 if (value == 0) {
6921 __ testl(dest, dest);
6922 } else {
6923 __ cmpl(dest, Immediate(value));
6924 }
6925}
6926
6927void CodeGeneratorX86_64::Compare64BitValue(CpuRegister dest, int64_t value) {
6928 if (IsInt<32>(value)) {
6929 if (value == 0) {
6930 __ testq(dest, dest);
6931 } else {
6932 __ cmpq(dest, Immediate(static_cast<int32_t>(value)));
6933 }
6934 } else {
6935 // Value won't fit in an int.
6936 __ cmpq(dest, LiteralInt64Address(value));
6937 }
6938}
6939
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006940void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
6941 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07006942 GenerateIntCompare(lhs_reg, rhs);
6943}
6944
6945void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006946 if (rhs.IsConstant()) {
6947 int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
jessicahandojo4877b792016-09-08 19:49:13 -07006948 Compare32BitValue(lhs, value);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006949 } else if (rhs.IsStackSlot()) {
jessicahandojo4877b792016-09-08 19:49:13 -07006950 __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006951 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07006952 __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006953 }
6954}
6955
6956void CodeGeneratorX86_64::GenerateLongCompare(Location lhs, Location rhs) {
6957 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
6958 if (rhs.IsConstant()) {
6959 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
6960 Compare64BitValue(lhs_reg, value);
6961 } else if (rhs.IsDoubleStackSlot()) {
6962 __ cmpq(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
6963 } else {
6964 __ cmpq(lhs_reg, rhs.AsRegister<CpuRegister>());
6965 }
6966}
6967
6968Address CodeGeneratorX86_64::ArrayAddress(CpuRegister obj,
6969 Location index,
6970 ScaleFactor scale,
6971 uint32_t data_offset) {
6972 return index.IsConstant() ?
6973 Address(obj, (index.GetConstant()->AsIntConstant()->GetValue() << scale) + data_offset) :
6974 Address(obj, index.AsRegister<CpuRegister>(), scale, data_offset);
6975}
6976
Mark Mendellcfa410b2015-05-25 16:02:44 -04006977void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
6978 DCHECK(dest.IsDoubleStackSlot());
6979 if (IsInt<32>(value)) {
6980 // Can move directly as an int32 constant.
6981 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
6982 Immediate(static_cast<int32_t>(value)));
6983 } else {
6984 Load64BitValue(CpuRegister(TMP), value);
6985 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
6986 }
6987}
6988
Mark Mendell9c86b482015-09-18 13:36:07 -04006989/**
6990 * Class to handle late fixup of offsets into constant area.
6991 */
6992class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
6993 public:
6994 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
6995 : codegen_(&codegen), offset_into_constant_area_(offset) {}
6996
6997 protected:
6998 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
6999
7000 CodeGeneratorX86_64* codegen_;
7001
7002 private:
7003 void Process(const MemoryRegion& region, int pos) OVERRIDE {
7004 // Patch the correct offset for the instruction. We use the address of the
7005 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
7006 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
7007 int32_t relative_position = constant_offset - pos;
7008
7009 // Patch in the right value.
7010 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
7011 }
7012
7013 // Location in constant area that the fixup refers to.
7014 size_t offset_into_constant_area_;
7015};
7016
7017/**
7018 t * Class to handle late fixup of offsets to a jump table that will be created in the
7019 * constant area.
7020 */
7021class JumpTableRIPFixup : public RIPFixup {
7022 public:
7023 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
7024 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
7025
7026 void CreateJumpTable() {
7027 X86_64Assembler* assembler = codegen_->GetAssembler();
7028
7029 // Ensure that the reference to the jump table has the correct offset.
7030 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
7031 SetOffset(offset_in_constant_table);
7032
7033 // Compute the offset from the start of the function to this jump table.
7034 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
7035
7036 // Populate the jump table with the correct values for the jump table.
7037 int32_t num_entries = switch_instr_->GetNumEntries();
7038 HBasicBlock* block = switch_instr_->GetBlock();
7039 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
7040 // The value that we want is the target offset - the position of the table.
7041 for (int32_t i = 0; i < num_entries; i++) {
7042 HBasicBlock* b = successors[i];
7043 Label* l = codegen_->GetLabelOf(b);
7044 DCHECK(l->IsBound());
7045 int32_t offset_to_block = l->Position() - current_table_offset;
7046 assembler->AppendInt32(offset_to_block);
7047 }
7048 }
7049
7050 private:
7051 const HPackedSwitch* switch_instr_;
7052};
7053
Mark Mendellf55c3e02015-03-26 21:07:46 -04007054void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
7055 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04007056 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04007057 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
7058 // 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 -04007059 assembler->Align(4, 0);
7060 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04007061
7062 // Populate any jump tables.
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007063 for (JumpTableRIPFixup* jump_table : fixups_to_jump_tables_) {
Mark Mendell9c86b482015-09-18 13:36:07 -04007064 jump_table->CreateJumpTable();
7065 }
7066
7067 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04007068 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04007069 }
7070
7071 // And finish up.
7072 CodeGenerator::Finalize(allocator);
7073}
7074
Mark Mendellf55c3e02015-03-26 21:07:46 -04007075Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
7076 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
7077 return Address::RIP(fixup);
7078}
7079
7080Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
7081 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
7082 return Address::RIP(fixup);
7083}
7084
7085Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
7086 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
7087 return Address::RIP(fixup);
7088}
7089
7090Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
7091 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
7092 return Address::RIP(fixup);
7093}
7094
Andreas Gampe85b62f22015-09-09 13:15:38 -07007095// TODO: trg as memory.
7096void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7097 if (!trg.IsValid()) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007098 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007099 return;
7100 }
7101
7102 DCHECK_NE(type, Primitive::kPrimVoid);
7103
7104 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
7105 if (trg.Equals(return_loc)) {
7106 return;
7107 }
7108
7109 // Let the parallel move resolver take care of all of this.
7110 HParallelMove parallel_move(GetGraph()->GetArena());
7111 parallel_move.AddMove(return_loc, trg, type, nullptr);
7112 GetMoveResolver()->EmitNativeCode(&parallel_move);
7113}
7114
Mark Mendell9c86b482015-09-18 13:36:07 -04007115Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
7116 // Create a fixup to be used to create and address the jump table.
7117 JumpTableRIPFixup* table_fixup =
7118 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
7119
7120 // We have to populate the jump tables.
7121 fixups_to_jump_tables_.push_back(table_fixup);
7122 return Address::RIP(table_fixup);
7123}
7124
Mark Mendellea5af682015-10-22 17:35:49 -04007125void CodeGeneratorX86_64::MoveInt64ToAddress(const Address& addr_low,
7126 const Address& addr_high,
7127 int64_t v,
7128 HInstruction* instruction) {
7129 if (IsInt<32>(v)) {
7130 int32_t v_32 = v;
7131 __ movq(addr_low, Immediate(v_32));
7132 MaybeRecordImplicitNullCheck(instruction);
7133 } else {
7134 // Didn't fit in a register. Do it in pieces.
7135 int32_t low_v = Low32Bits(v);
7136 int32_t high_v = High32Bits(v);
7137 __ movl(addr_low, Immediate(low_v));
7138 MaybeRecordImplicitNullCheck(instruction);
7139 __ movl(addr_high, Immediate(high_v));
7140 }
7141}
7142
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007143void CodeGeneratorX86_64::PatchJitRootUse(uint8_t* code,
7144 const uint8_t* roots_data,
7145 const PatchInfo<Label>& info,
7146 uint64_t index_in_table) const {
7147 uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
7148 uintptr_t address =
7149 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
7150 typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
7151 reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
7152 dchecked_integral_cast<uint32_t>(address);
7153}
7154
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007155void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7156 for (const PatchInfo<Label>& info : jit_string_patches_) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007157 const auto it = jit_string_roots_.find(
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007158 StringReference(&info.dex_file, dex::StringIndex(info.index)));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007159 DCHECK(it != jit_string_roots_.end());
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007160 uint64_t index_in_table = it->second;
7161 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007162 }
7163
7164 for (const PatchInfo<Label>& info : jit_class_patches_) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007165 const auto it = jit_class_roots_.find(
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007166 TypeReference(&info.dex_file, dex::TypeIndex(info.index)));
7167 DCHECK(it != jit_class_roots_.end());
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007168 uint64_t index_in_table = it->second;
7169 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007170 }
7171}
7172
Roland Levillain4d027112015-07-01 15:41:14 +01007173#undef __
7174
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01007175} // namespace x86_64
7176} // namespace art