blob: 5d4cfb4ecd4e00716a7e2491d30e2b5cdf363735 [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
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000019#include "art_method-inl.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"
Vladimir Markoeebb8212018-06-05 14:57:24 +010025#include "gc/space/image_space.h"
Andreas Gampe09659c22017-09-18 18:23:32 -070026#include "heap_poisoning.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080027#include "intrinsics.h"
28#include "intrinsics_x86_64.h"
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000029#include "jit/profiling_info.h"
Vladimir Markod8dbc8d2017-09-20 13:37:47 +010030#include "linker/linker_patch.h"
Andreas Gamped4901292017-05-30 18:41:34 -070031#include "lock_word.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070032#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070033#include "mirror/class-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010034#include "mirror/object_reference.h"
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000035#include "scoped_thread_state_change-inl.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010036#include "thread.h"
37#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038#include "utils/stack_checks.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010039#include "utils/x86_64/assembler_x86_64.h"
40#include "utils/x86_64/managed_register_x86_64.h"
41
Vladimir Marko0a516052019-10-14 13:00:44 +000042namespace art {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010043
Roland Levillain0d5a2812015-11-13 10:07:31 +000044template<class MirrorType>
45class GcRoot;
46
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010047namespace x86_64 {
48
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010049static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010050static constexpr Register kMethodRegisterArgument = RDI;
Vladimir Markof3e0ee22015-12-17 15:23:13 +000051// The compare/jump sequence will generate about (1.5 * num_entries) instructions. A jump
52// table version generates 7 instructions and num_entries literals. Compare/jump sequence will
53// generates less code/data with a small num_entries.
54static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010055
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +000056static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000057static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010058
Mark Mendell24f2dfa2015-01-14 19:51:45 -050059static constexpr int kC2ConditionMask = 0x400;
60
Vladimir Marko3232dbb2018-07-25 15:42:46 +010061static RegisterSet OneRegInReferenceOutSaveEverythingCallerSaves() {
62 // Custom calling convention: RAX serves as both input and output.
63 RegisterSet caller_saves = RegisterSet::Empty();
64 caller_saves.Add(Location::RegisterLocation(RAX));
65 return caller_saves;
66}
67
Roland Levillain7cbd27f2016-08-11 23:53:33 +010068// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
69#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070070#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64PointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071
Andreas Gampe85b62f22015-09-09 13:15:38 -070072class NullCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000074 explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010076 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +000077 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010078 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000079 if (instruction_->CanThrowIntoCatchBlock()) {
80 // Live registers will be restored in the catch block if caught.
81 SaveLiveRegisters(codegen, instruction_->GetLocations());
82 }
Serban Constantinescuba45db02016-07-12 22:53:02 +010083 x86_64_codegen->InvokeRuntime(kQuickThrowNullPointer,
Roland Levillain0d5a2812015-11-13 10:07:31 +000084 instruction_,
85 instruction_->GetDexPc(),
86 this);
Roland Levillain888d0672015-11-23 18:53:50 +000087 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010088 }
89
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010090 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +010091
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010092 const char* GetDescription() const override { return "NullCheckSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +010093
Nicolas Geoffraye5038322014-07-04 09:41:32 +010094 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010095 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
96};
97
Andreas Gampe85b62f22015-09-09 13:15:38 -070098class DivZeroCheckSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000099 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000100 explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000101
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100102 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000103 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +0000104 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +0100105 x86_64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000106 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000107 }
108
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100109 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +0100110
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100111 const char* GetDescription() const override { return "DivZeroCheckSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100112
Calin Juravled0d48522014-11-04 16:40:20 +0000113 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000114 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
115};
116
Andreas Gampe85b62f22015-09-09 13:15:38 -0700117class DivRemMinusOneSlowPathX86_64 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000118 public:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100119 DivRemMinusOneSlowPathX86_64(HInstruction* at, Register reg, DataType::Type type, bool is_div)
David Srbecky9cd6d372016-02-09 15:24:47 +0000120 : SlowPathCode(at), cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000121
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100122 void EmitNativeCode(CodeGenerator* codegen) override {
Calin Juravled0d48522014-11-04 16:40:20 +0000123 __ Bind(GetEntryLabel());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100124 if (type_ == DataType::Type::kInt32) {
Calin Juravlebacfec32014-11-14 15:54:36 +0000125 if (is_div_) {
126 __ negl(cpu_reg_);
127 } else {
Mark Mendellcfa410b2015-05-25 16:02:44 -0400128 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000129 }
130
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000131 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100132 DCHECK_EQ(DataType::Type::kInt64, type_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000133 if (is_div_) {
134 __ negq(cpu_reg_);
135 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -0400136 __ xorl(cpu_reg_, cpu_reg_);
Calin Juravlebacfec32014-11-14 15:54:36 +0000137 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000138 }
Calin Juravled0d48522014-11-04 16:40:20 +0000139 __ jmp(GetExitLabel());
140 }
141
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100142 const char* GetDescription() const override { return "DivRemMinusOneSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100143
Calin Juravled0d48522014-11-04 16:40:20 +0000144 private:
Calin Juravlebacfec32014-11-14 15:54:36 +0000145 const CpuRegister cpu_reg_;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100146 const DataType::Type type_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000147 const bool is_div_;
148 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
Calin Juravled0d48522014-11-04 16:40:20 +0000149};
150
Andreas Gampe85b62f22015-09-09 13:15:38 -0700151class SuspendCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000152 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100153 SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000154 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000155
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100156 void EmitNativeCode(CodeGenerator* codegen) override {
Aart Bikb13c65b2017-03-21 20:14:07 -0700157 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000158 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000159 __ Bind(GetEntryLabel());
Aart Bik24b905f2017-04-06 09:59:06 -0700160 SaveLiveRegisters(codegen, locations); // Only saves full width XMM for SIMD.
Serban Constantinescuba45db02016-07-12 22:53:02 +0100161 x86_64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000162 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Aart Bik24b905f2017-04-06 09:59:06 -0700163 RestoreLiveRegisters(codegen, locations); // Only restores full width XMM for SIMD.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100164 if (successor_ == nullptr) {
165 __ jmp(GetReturnLabel());
166 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000167 __ jmp(x86_64_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100168 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000169 }
170
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100171 Label* GetReturnLabel() {
172 DCHECK(successor_ == nullptr);
173 return &return_label_;
174 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000175
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100176 HBasicBlock* GetSuccessor() const {
177 return successor_;
178 }
179
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100180 const char* GetDescription() const override { return "SuspendCheckSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100181
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000182 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100183 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000184 Label return_label_;
185
186 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
187};
188
Andreas Gampe85b62f22015-09-09 13:15:38 -0700189class BoundsCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100190 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100191 explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000192 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100193
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100194 void EmitNativeCode(CodeGenerator* codegen) override {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100195 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000196 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100197 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000198 if (instruction_->CanThrowIntoCatchBlock()) {
199 // Live registers will be restored in the catch block if caught.
200 SaveLiveRegisters(codegen, instruction_->GetLocations());
201 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400202 // Are we using an array length from memory?
203 HInstruction* array_length = instruction_->InputAt(1);
204 Location length_loc = locations->InAt(1);
205 InvokeRuntimeCallingConvention calling_convention;
206 if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
207 // Load the array length into our temporary.
Nicolas Geoffray0aff3a82017-10-13 13:12:36 +0100208 HArrayLength* length = array_length->AsArrayLength();
Nicolas Geoffray003444a2017-10-17 10:58:42 +0100209 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
Mark Mendellee8d9712016-07-12 11:13:15 -0400210 Location array_loc = array_length->GetLocations()->InAt(0);
211 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
212 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
213 // Check for conflicts with index.
214 if (length_loc.Equals(locations->InAt(0))) {
215 // We know we aren't using parameter 2.
216 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
217 }
218 __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
Nicolas Geoffray0aff3a82017-10-13 13:12:36 +0100219 if (mirror::kUseStringCompression && length->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +0100220 __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -0700221 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400222 }
223
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000224 // We're moving two locations to locations that could overlap, so we need a parallel
225 // move resolver.
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000226 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100227 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000228 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100229 DataType::Type::kInt32,
Mark Mendellee8d9712016-07-12 11:13:15 -0400230 length_loc,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100231 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100232 DataType::Type::kInt32);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100233 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
234 ? kQuickThrowStringBounds
235 : kQuickThrowArrayBounds;
236 x86_64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100237 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000238 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100239 }
240
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100241 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +0100242
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100243 const char* GetDescription() const override { return "BoundsCheckSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100244
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100245 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100246 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
247};
248
Andreas Gampe85b62f22015-09-09 13:15:38 -0700249class LoadClassSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100250 public:
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100251 LoadClassSlowPathX86_64(HLoadClass* cls, HInstruction* at)
252 : SlowPathCode(at), cls_(cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000253 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100254 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000255 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100256
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100257 void EmitNativeCode(CodeGenerator* codegen) override {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000258 LocationSummary* locations = instruction_->GetLocations();
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100259 Location out = locations->Out();
260 const uint32_t dex_pc = instruction_->GetDexPc();
261 bool must_resolve_type = instruction_->IsLoadClass() && cls_->MustResolveTypeOnSlowPath();
262 bool must_do_clinit = instruction_->IsClinitCheck() || cls_->MustGenerateClinitCheck();
263
Roland Levillain0d5a2812015-11-13 10:07:31 +0000264 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100265 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000266 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000267
Vladimir Markoea4c1262017-02-06 19:59:33 +0000268 // Custom calling convention: RAX serves as both input and output.
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100269 if (must_resolve_type) {
270 DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_64_codegen->GetGraph()->GetDexFile()));
271 dex::TypeIndex type_index = cls_->GetTypeIndex();
272 __ movl(CpuRegister(RAX), Immediate(type_index.index_));
Vladimir Marko9d479252018-07-24 11:35:20 +0100273 x86_64_codegen->InvokeRuntime(kQuickResolveType, instruction_, dex_pc, this);
274 CheckEntrypointTypes<kQuickResolveType, void*, uint32_t>();
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100275 // If we also must_do_clinit, the resolved type is now in the correct register.
276 } else {
277 DCHECK(must_do_clinit);
278 Location source = instruction_->IsLoadClass() ? out : locations->InAt(0);
279 x86_64_codegen->Move(Location::RegisterLocation(RAX), source);
280 }
281 if (must_do_clinit) {
282 x86_64_codegen->InvokeRuntime(kQuickInitializeStaticStorage, instruction_, dex_pc, this);
283 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, mirror::Class*>();
Roland Levillain888d0672015-11-23 18:53:50 +0000284 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100285
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000286 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000287 if (out.IsValid()) {
288 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Roland Levillain0d5a2812015-11-13 10:07:31 +0000289 x86_64_codegen->Move(out, Location::RegisterLocation(RAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000290 }
291
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000292 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100293 __ jmp(GetExitLabel());
294 }
295
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100296 const char* GetDescription() const override { return "LoadClassSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100297
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100298 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000299 // The class this slow path will load.
300 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100301
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000302 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100303};
304
Vladimir Markoaad75c62016-10-03 08:46:48 +0000305class LoadStringSlowPathX86_64 : public SlowPathCode {
306 public:
307 explicit LoadStringSlowPathX86_64(HLoadString* instruction) : SlowPathCode(instruction) {}
308
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100309 void EmitNativeCode(CodeGenerator* codegen) override {
Vladimir Markoaad75c62016-10-03 08:46:48 +0000310 LocationSummary* locations = instruction_->GetLocations();
311 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
312
313 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
314 __ Bind(GetEntryLabel());
315 SaveLiveRegisters(codegen, locations);
316
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000317 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100318 // Custom calling convention: RAX serves as both input and output.
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000319 __ movl(CpuRegister(RAX), Immediate(string_index.index_));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000320 x86_64_codegen->InvokeRuntime(kQuickResolveString,
321 instruction_,
322 instruction_->GetDexPc(),
323 this);
324 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
325 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
326 RestoreLiveRegisters(codegen, locations);
327
Vladimir Markoaad75c62016-10-03 08:46:48 +0000328 __ jmp(GetExitLabel());
329 }
330
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100331 const char* GetDescription() const override { return "LoadStringSlowPathX86_64"; }
Vladimir Markoaad75c62016-10-03 08:46:48 +0000332
333 private:
334 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
335};
336
Andreas Gampe85b62f22015-09-09 13:15:38 -0700337class TypeCheckSlowPathX86_64 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000338 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000339 TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000340 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000341
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100342 void EmitNativeCode(CodeGenerator* codegen) override {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000343 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100344 uint32_t dex_pc = instruction_->GetDexPc();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000345 DCHECK(instruction_->IsCheckCast()
346 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000347
Roland Levillain0d5a2812015-11-13 10:07:31 +0000348 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000349 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000350
Vladimir Markoe619f6c2017-12-12 16:00:01 +0000351 if (kPoisonHeapReferences &&
352 instruction_->IsCheckCast() &&
353 instruction_->AsCheckCast()->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) {
354 // First, unpoison the `cls` reference that was poisoned for direct memory comparison.
355 __ UnpoisonHeapReference(locations->InAt(1).AsRegister<CpuRegister>());
356 }
357
Vladimir Marko87584542017-12-12 17:47:52 +0000358 if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000359 SaveLiveRegisters(codegen, locations);
360 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000361
362 // We're moving two locations to locations that could overlap, so we need a parallel
363 // move resolver.
364 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800365 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800366 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100367 DataType::Type::kReference,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800368 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800369 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100370 DataType::Type::kReference);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000371 if (instruction_->IsInstanceOf()) {
Serban Constantinescuba45db02016-07-12 22:53:02 +0100372 x86_64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800373 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000374 } else {
375 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800376 x86_64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
377 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000378 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000379
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000380 if (!is_fatal_) {
381 if (instruction_->IsInstanceOf()) {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000382 x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000383 }
Nicolas Geoffray75374372015-09-17 17:12:19 +0000384
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000385 RestoreLiveRegisters(codegen, locations);
386 __ jmp(GetExitLabel());
387 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000388 }
389
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100390 const char* GetDescription() const override { return "TypeCheckSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100391
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100392 bool IsFatal() const override { return is_fatal_; }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000393
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000394 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000395 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000396
397 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
398};
399
Andreas Gampe85b62f22015-09-09 13:15:38 -0700400class DeoptimizationSlowPathX86_64 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700401 public:
Aart Bik42249c32016-01-07 15:33:50 -0800402 explicit DeoptimizationSlowPathX86_64(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000403 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700404
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100405 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000406 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700407 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100408 LocationSummary* locations = instruction_->GetLocations();
409 SaveLiveRegisters(codegen, locations);
410 InvokeRuntimeCallingConvention calling_convention;
411 x86_64_codegen->Load32BitValue(
412 CpuRegister(calling_convention.GetRegisterAt(0)),
413 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescuba45db02016-07-12 22:53:02 +0100414 x86_64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100415 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700416 }
417
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100418 const char* GetDescription() const override { return "DeoptimizationSlowPathX86_64"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100419
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700420 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700421 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
422};
423
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100424class ArraySetSlowPathX86_64 : public SlowPathCode {
425 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000426 explicit ArraySetSlowPathX86_64(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100427
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100428 void EmitNativeCode(CodeGenerator* codegen) override {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100429 LocationSummary* locations = instruction_->GetLocations();
430 __ Bind(GetEntryLabel());
431 SaveLiveRegisters(codegen, locations);
432
433 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100434 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100435 parallel_move.AddMove(
436 locations->InAt(0),
437 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100438 DataType::Type::kReference,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100439 nullptr);
440 parallel_move.AddMove(
441 locations->InAt(1),
442 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100443 DataType::Type::kInt32,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100444 nullptr);
445 parallel_move.AddMove(
446 locations->InAt(2),
447 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100448 DataType::Type::kReference,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100449 nullptr);
450 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
451
Roland Levillain0d5a2812015-11-13 10:07:31 +0000452 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100453 x86_64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000454 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100455 RestoreLiveRegisters(codegen, locations);
456 __ jmp(GetExitLabel());
457 }
458
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100459 const char* GetDescription() const override { return "ArraySetSlowPathX86_64"; }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100460
461 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100462 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86_64);
463};
464
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100465// Slow path marking an object reference `ref` during a read
466// barrier. The field `obj.field` in the object `obj` holding this
467// reference does not get updated by this slow path after marking (see
468// ReadBarrierMarkAndUpdateFieldSlowPathX86_64 below for that).
469//
470// This means that after the execution of this slow path, `ref` will
471// always be up-to-date, but `obj.field` may not; i.e., after the
472// flip, `ref` will be a to-space reference, but `obj.field` will
473// probably still be a from-space reference (unless it gets updated by
474// another thread, or if another thread installed another object
475// reference (different from `ref`) in `obj.field`).
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000476class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode {
477 public:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100478 ReadBarrierMarkSlowPathX86_64(HInstruction* instruction,
479 Location ref,
480 bool unpoison_ref_before_marking)
481 : SlowPathCode(instruction),
482 ref_(ref),
483 unpoison_ref_before_marking_(unpoison_ref_before_marking) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000484 DCHECK(kEmitCompilerReadBarrier);
485 }
486
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100487 const char* GetDescription() const override { return "ReadBarrierMarkSlowPathX86_64"; }
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000488
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100489 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000490 LocationSummary* locations = instruction_->GetLocations();
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100491 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
492 Register ref_reg = ref_cpu_reg.AsRegister();
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000493 DCHECK(locations->CanCall());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100494 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000495 DCHECK(instruction_->IsInstanceFieldGet() ||
496 instruction_->IsStaticFieldGet() ||
497 instruction_->IsArrayGet() ||
Roland Levillain16d9f942016-08-25 17:27:56 +0100498 instruction_->IsArraySet() ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000499 instruction_->IsLoadClass() ||
500 instruction_->IsLoadString() ||
501 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100502 instruction_->IsCheckCast() ||
Roland Levillain0b671c02016-08-19 12:02:34 +0100503 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
504 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000505 << "Unexpected instruction in read barrier marking slow path: "
506 << instruction_->DebugName();
507
508 __ Bind(GetEntryLabel());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100509 if (unpoison_ref_before_marking_) {
Vladimir Marko953437b2016-08-24 08:30:46 +0000510 // Object* ref = ref_addr->AsMirrorPtr()
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100511 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
Vladimir Marko953437b2016-08-24 08:30:46 +0000512 }
Roland Levillain4359e612016-07-20 11:32:19 +0100513 // No need to save live registers; it's taken care of by the
514 // entrypoint. Also, there is no need to update the stack mask,
515 // as this runtime call will not trigger a garbage collection.
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000516 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100517 DCHECK_NE(ref_reg, RSP);
518 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
Roland Levillain02b75802016-07-13 11:54:35 +0100519 // "Compact" slow path, saving two moves.
520 //
521 // Instead of using the standard runtime calling convention (input
522 // and output in R0):
523 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100524 // RDI <- ref
Roland Levillain02b75802016-07-13 11:54:35 +0100525 // RAX <- ReadBarrierMark(RDI)
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100526 // ref <- RAX
Roland Levillain02b75802016-07-13 11:54:35 +0100527 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100528 // we just use rX (the register containing `ref`) as input and output
Roland Levillain02b75802016-07-13 11:54:35 +0100529 // of a dedicated entrypoint:
530 //
531 // rX <- ReadBarrierMarkRegX(rX)
532 //
533 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100534 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
Roland Levillaindec8f632016-07-22 17:10:06 +0100535 // This runtime call does not require a stack map.
536 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000537 __ jmp(GetExitLabel());
538 }
539
540 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100541 // The location (register) of the marked object reference.
542 const Location ref_;
543 // Should the reference in `ref_` be unpoisoned prior to marking it?
544 const bool unpoison_ref_before_marking_;
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000545
546 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86_64);
547};
548
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100549// Slow path marking an object reference `ref` during a read barrier,
550// and if needed, atomically updating the field `obj.field` in the
551// object `obj` holding this reference after marking (contrary to
552// ReadBarrierMarkSlowPathX86_64 above, which never tries to update
553// `obj.field`).
554//
555// This means that after the execution of this slow path, both `ref`
556// and `obj.field` will be up-to-date; i.e., after the flip, both will
557// hold the same to-space reference (unless another thread installed
558// another object reference (different from `ref`) in `obj.field`).
559class ReadBarrierMarkAndUpdateFieldSlowPathX86_64 : public SlowPathCode {
560 public:
561 ReadBarrierMarkAndUpdateFieldSlowPathX86_64(HInstruction* instruction,
562 Location ref,
563 CpuRegister obj,
564 const Address& field_addr,
565 bool unpoison_ref_before_marking,
566 CpuRegister temp1,
567 CpuRegister temp2)
568 : SlowPathCode(instruction),
569 ref_(ref),
570 obj_(obj),
571 field_addr_(field_addr),
572 unpoison_ref_before_marking_(unpoison_ref_before_marking),
573 temp1_(temp1),
574 temp2_(temp2) {
575 DCHECK(kEmitCompilerReadBarrier);
576 }
577
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100578 const char* GetDescription() const override {
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100579 return "ReadBarrierMarkAndUpdateFieldSlowPathX86_64";
580 }
581
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100582 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100583 LocationSummary* locations = instruction_->GetLocations();
584 CpuRegister ref_cpu_reg = ref_.AsRegister<CpuRegister>();
585 Register ref_reg = ref_cpu_reg.AsRegister();
586 DCHECK(locations->CanCall());
587 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
588 // This slow path is only used by the UnsafeCASObject intrinsic.
589 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
590 << "Unexpected instruction in read barrier marking and field updating slow path: "
591 << instruction_->DebugName();
592 DCHECK(instruction_->GetLocations()->Intrinsified());
593 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
594
595 __ Bind(GetEntryLabel());
596 if (unpoison_ref_before_marking_) {
597 // Object* ref = ref_addr->AsMirrorPtr()
598 __ MaybeUnpoisonHeapReference(ref_cpu_reg);
599 }
600
601 // Save the old (unpoisoned) reference.
602 __ movl(temp1_, ref_cpu_reg);
603
604 // No need to save live registers; it's taken care of by the
605 // entrypoint. Also, there is no need to update the stack mask,
606 // as this runtime call will not trigger a garbage collection.
607 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
608 DCHECK_NE(ref_reg, RSP);
609 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
610 // "Compact" slow path, saving two moves.
611 //
612 // Instead of using the standard runtime calling convention (input
613 // and output in R0):
614 //
615 // RDI <- ref
616 // RAX <- ReadBarrierMark(RDI)
617 // ref <- RAX
618 //
619 // we just use rX (the register containing `ref`) as input and output
620 // of a dedicated entrypoint:
621 //
622 // rX <- ReadBarrierMarkRegX(rX)
623 //
624 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100625 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(ref_reg);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100626 // This runtime call does not require a stack map.
627 x86_64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
628
629 // If the new reference is different from the old reference,
630 // update the field in the holder (`*field_addr`).
631 //
632 // Note that this field could also hold a different object, if
633 // another thread had concurrently changed it. In that case, the
634 // LOCK CMPXCHGL instruction in the compare-and-set (CAS)
635 // operation below would abort the CAS, leaving the field as-is.
636 NearLabel done;
637 __ cmpl(temp1_, ref_cpu_reg);
638 __ j(kEqual, &done);
639
640 // Update the the holder's field atomically. This may fail if
641 // mutator updates before us, but it's OK. This is achived
642 // using a strong compare-and-set (CAS) operation with relaxed
643 // memory synchronization ordering, where the expected value is
644 // the old reference and the desired value is the new reference.
645 // This operation is implemented with a 32-bit LOCK CMPXLCHG
646 // instruction, which requires the expected value (the old
647 // reference) to be in EAX. Save RAX beforehand, and move the
648 // expected value (stored in `temp1_`) into EAX.
649 __ movq(temp2_, CpuRegister(RAX));
650 __ movl(CpuRegister(RAX), temp1_);
651
652 // Convenience aliases.
653 CpuRegister base = obj_;
654 CpuRegister expected = CpuRegister(RAX);
655 CpuRegister value = ref_cpu_reg;
656
657 bool base_equals_value = (base.AsRegister() == value.AsRegister());
658 Register value_reg = ref_reg;
659 if (kPoisonHeapReferences) {
660 if (base_equals_value) {
661 // If `base` and `value` are the same register location, move
662 // `value_reg` to a temporary register. This way, poisoning
663 // `value_reg` won't invalidate `base`.
664 value_reg = temp1_.AsRegister();
665 __ movl(CpuRegister(value_reg), base);
666 }
667
668 // Check that the register allocator did not assign the location
669 // of `expected` (RAX) to `value` nor to `base`, so that heap
670 // poisoning (when enabled) works as intended below.
671 // - If `value` were equal to `expected`, both references would
672 // be poisoned twice, meaning they would not be poisoned at
673 // all, as heap poisoning uses address negation.
674 // - If `base` were equal to `expected`, poisoning `expected`
675 // would invalidate `base`.
676 DCHECK_NE(value_reg, expected.AsRegister());
677 DCHECK_NE(base.AsRegister(), expected.AsRegister());
678
679 __ PoisonHeapReference(expected);
680 __ PoisonHeapReference(CpuRegister(value_reg));
681 }
682
683 __ LockCmpxchgl(field_addr_, CpuRegister(value_reg));
684
685 // If heap poisoning is enabled, we need to unpoison the values
686 // that were poisoned earlier.
687 if (kPoisonHeapReferences) {
688 if (base_equals_value) {
689 // `value_reg` has been moved to a temporary register, no need
690 // to unpoison it.
691 } else {
692 __ UnpoisonHeapReference(CpuRegister(value_reg));
693 }
694 // No need to unpoison `expected` (RAX), as it is be overwritten below.
695 }
696
697 // Restore RAX.
698 __ movq(CpuRegister(RAX), temp2_);
699
700 __ Bind(&done);
701 __ jmp(GetExitLabel());
702 }
703
704 private:
705 // The location (register) of the marked object reference.
706 const Location ref_;
707 // The register containing the object holding the marked object reference field.
708 const CpuRegister obj_;
709 // The address of the marked reference field. The base of this address must be `obj_`.
710 const Address field_addr_;
711
712 // Should the reference in `ref_` be unpoisoned prior to marking it?
713 const bool unpoison_ref_before_marking_;
714
715 const CpuRegister temp1_;
716 const CpuRegister temp2_;
717
718 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathX86_64);
719};
720
Roland Levillain0d5a2812015-11-13 10:07:31 +0000721// Slow path generating a read barrier for a heap reference.
722class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
723 public:
724 ReadBarrierForHeapReferenceSlowPathX86_64(HInstruction* instruction,
725 Location out,
726 Location ref,
727 Location obj,
728 uint32_t offset,
729 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000730 : SlowPathCode(instruction),
Roland Levillain0d5a2812015-11-13 10:07:31 +0000731 out_(out),
732 ref_(ref),
733 obj_(obj),
734 offset_(offset),
735 index_(index) {
736 DCHECK(kEmitCompilerReadBarrier);
737 // If `obj` is equal to `out` or `ref`, it means the initial
738 // object has been overwritten by (or after) the heap object
739 // reference load to be instrumented, e.g.:
740 //
741 // __ movl(out, Address(out, offset));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000742 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000743 //
744 // In that case, we have lost the information about the original
745 // object, and the emitted read barrier cannot work properly.
746 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
747 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
748}
749
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100750 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000751 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
752 LocationSummary* locations = instruction_->GetLocations();
753 CpuRegister reg_out = out_.AsRegister<CpuRegister>();
754 DCHECK(locations->CanCall());
755 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_;
Roland Levillain3d312422016-06-23 13:53:42 +0100756 DCHECK(instruction_->IsInstanceFieldGet() ||
757 instruction_->IsStaticFieldGet() ||
758 instruction_->IsArrayGet() ||
759 instruction_->IsInstanceOf() ||
760 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -0700761 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000762 << "Unexpected instruction in read barrier for heap reference slow path: "
763 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000764
765 __ Bind(GetEntryLabel());
766 SaveLiveRegisters(codegen, locations);
767
768 // We may have to change the index's value, but as `index_` is a
769 // constant member (like other "inputs" of this slow path),
770 // introduce a copy of it, `index`.
771 Location index = index_;
772 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100773 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain0d5a2812015-11-13 10:07:31 +0000774 if (instruction_->IsArrayGet()) {
775 // Compute real offset and store it in index_.
776 Register index_reg = index_.AsRegister<CpuRegister>().AsRegister();
777 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
778 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
779 // We are about to change the value of `index_reg` (see the
780 // calls to art::x86_64::X86_64Assembler::shll and
781 // art::x86_64::X86_64Assembler::AddImmediate below), but it
782 // has not been saved by the previous call to
783 // art::SlowPathCode::SaveLiveRegisters, as it is a
784 // callee-save register --
785 // art::SlowPathCode::SaveLiveRegisters does not consider
786 // callee-save registers, as it has been designed with the
787 // assumption that callee-save registers are supposed to be
788 // handled by the called function. So, as a callee-save
789 // register, `index_reg` _would_ eventually be saved onto
790 // the stack, but it would be too late: we would have
791 // changed its value earlier. Therefore, we manually save
792 // it here into another freely available register,
793 // `free_reg`, chosen of course among the caller-save
794 // registers (as a callee-save `free_reg` register would
795 // exhibit the same problem).
796 //
797 // Note we could have requested a temporary register from
798 // the register allocator instead; but we prefer not to, as
799 // this is a slow path, and we know we can find a
800 // caller-save register that is available.
801 Register free_reg = FindAvailableCallerSaveRegister(codegen).AsRegister();
802 __ movl(CpuRegister(free_reg), CpuRegister(index_reg));
803 index_reg = free_reg;
804 index = Location::RegisterLocation(index_reg);
805 } else {
806 // The initial register stored in `index_` has already been
807 // saved in the call to art::SlowPathCode::SaveLiveRegisters
808 // (as it is not a callee-save register), so we can freely
809 // use it.
810 }
811 // Shifting the index value contained in `index_reg` by the
812 // scale factor (2) cannot overflow in practice, as the
813 // runtime is unable to allocate object arrays with a size
814 // larger than 2^26 - 1 (that is, 2^28 - 4 bytes).
815 __ shll(CpuRegister(index_reg), Immediate(TIMES_4));
816 static_assert(
817 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
818 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
819 __ AddImmediate(CpuRegister(index_reg), Immediate(offset_));
820 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100821 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
822 // intrinsics, `index_` is not shifted by a scale factor of 2
823 // (as in the case of ArrayGet), as it is actually an offset
824 // to an object field within an object.
825 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000826 DCHECK(instruction_->GetLocations()->Intrinsified());
827 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
828 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
829 << instruction_->AsInvoke()->GetIntrinsic();
830 DCHECK_EQ(offset_, 0U);
831 DCHECK(index_.IsRegister());
832 }
833 }
834
835 // We're moving two or three locations to locations that could
836 // overlap, so we need a parallel move resolver.
837 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100838 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Roland Levillain0d5a2812015-11-13 10:07:31 +0000839 parallel_move.AddMove(ref_,
840 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100841 DataType::Type::kReference,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000842 nullptr);
843 parallel_move.AddMove(obj_,
844 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100845 DataType::Type::kReference,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000846 nullptr);
847 if (index.IsValid()) {
848 parallel_move.AddMove(index,
849 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100850 DataType::Type::kInt32,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000851 nullptr);
852 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
853 } else {
854 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
855 __ movl(CpuRegister(calling_convention.GetRegisterAt(2)), Immediate(offset_));
856 }
Serban Constantinescuba45db02016-07-12 22:53:02 +0100857 x86_64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000858 instruction_,
859 instruction_->GetDexPc(),
860 this);
861 CheckEntrypointTypes<
862 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
863 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
864
865 RestoreLiveRegisters(codegen, locations);
866 __ jmp(GetExitLabel());
867 }
868
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100869 const char* GetDescription() const override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000870 return "ReadBarrierForHeapReferenceSlowPathX86_64";
871 }
872
873 private:
874 CpuRegister FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
875 size_t ref = static_cast<int>(ref_.AsRegister<CpuRegister>().AsRegister());
876 size_t obj = static_cast<int>(obj_.AsRegister<CpuRegister>().AsRegister());
877 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
878 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
879 return static_cast<CpuRegister>(i);
880 }
881 }
882 // We shall never fail to find a free caller-save register, as
883 // there are more than two core caller-save registers on x86-64
884 // (meaning it is possible to find one which is different from
885 // `ref` and `obj`).
886 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
887 LOG(FATAL) << "Could not find a free caller-save register";
888 UNREACHABLE();
889 }
890
Roland Levillain0d5a2812015-11-13 10:07:31 +0000891 const Location out_;
892 const Location ref_;
893 const Location obj_;
894 const uint32_t offset_;
895 // An additional location containing an index to an array.
896 // Only used for HArrayGet and the UnsafeGetObject &
897 // UnsafeGetObjectVolatile intrinsics.
898 const Location index_;
899
900 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86_64);
901};
902
903// Slow path generating a read barrier for a GC root.
904class ReadBarrierForRootSlowPathX86_64 : public SlowPathCode {
905 public:
906 ReadBarrierForRootSlowPathX86_64(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000907 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000908 DCHECK(kEmitCompilerReadBarrier);
909 }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000910
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100911 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000912 LocationSummary* locations = instruction_->GetLocations();
913 DCHECK(locations->CanCall());
914 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
Roland Levillain1e7f8db2015-12-15 10:54:19 +0000915 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
916 << "Unexpected instruction in read barrier for GC root slow path: "
917 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000918
919 __ Bind(GetEntryLabel());
920 SaveLiveRegisters(codegen, locations);
921
922 InvokeRuntimeCallingConvention calling_convention;
923 CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
924 x86_64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100925 x86_64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000926 instruction_,
927 instruction_->GetDexPc(),
928 this);
929 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
930 x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
931
932 RestoreLiveRegisters(codegen, locations);
933 __ jmp(GetExitLabel());
934 }
935
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100936 const char* GetDescription() const override { return "ReadBarrierForRootSlowPathX86_64"; }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000937
938 private:
Roland Levillain0d5a2812015-11-13 10:07:31 +0000939 const Location out_;
940 const Location root_;
941
942 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86_64);
943};
944
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100945#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100946// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
947#define __ down_cast<X86_64Assembler*>(GetAssembler())-> // NOLINT
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100948
Roland Levillain4fa13f62015-07-06 18:11:54 +0100949inline Condition X86_64IntegerCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700950 switch (cond) {
951 case kCondEQ: return kEqual;
952 case kCondNE: return kNotEqual;
953 case kCondLT: return kLess;
954 case kCondLE: return kLessEqual;
955 case kCondGT: return kGreater;
956 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700957 case kCondB: return kBelow;
958 case kCondBE: return kBelowEqual;
959 case kCondA: return kAbove;
960 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700961 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100962 LOG(FATAL) << "Unreachable";
963 UNREACHABLE();
964}
965
Aart Bike9f37602015-10-09 11:15:55 -0700966// Maps FP condition to x86_64 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100967inline Condition X86_64FPCondition(IfCondition cond) {
968 switch (cond) {
969 case kCondEQ: return kEqual;
970 case kCondNE: return kNotEqual;
971 case kCondLT: return kBelow;
972 case kCondLE: return kBelowEqual;
973 case kCondGT: return kAbove;
974 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700975 default: break; // should not happen
Igor Murashkin2ffb7032017-11-08 13:35:21 -0800976 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100977 LOG(FATAL) << "Unreachable";
978 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700979}
980
Vladimir Markodc151b22015-10-15 18:02:30 +0100981HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
982 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffraybdb2ecc2018-09-18 14:33:55 +0100983 ArtMethod* method ATTRIBUTE_UNUSED) {
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +0000984 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +0100985}
986
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100987void CodeGeneratorX86_64::GenerateStaticOrDirectCall(
988 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800989 // All registers are assumed to be correctly set up.
Vladimir Marko4ee8e292017-06-02 15:39:30 +0000990
Vladimir Marko58155012015-08-19 12:49:41 +0000991 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
992 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100993 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Vladimir Marko58155012015-08-19 12:49:41 +0000994 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100995 uint32_t offset =
996 GetThreadOffset<kX86_64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Andreas Gampe3db70682018-12-26 15:12:03 -0800997 __ gs()->movq(temp.AsRegister<CpuRegister>(), Address::Absolute(offset, /* no_rip= */ true));
Vladimir Marko58155012015-08-19 12:49:41 +0000998 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +0100999 }
Vladimir Marko58155012015-08-19 12:49:41 +00001000 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00001001 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00001002 break;
Vladimir Marko65979462017-05-19 17:25:12 +01001003 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko44ca0752019-07-29 10:18:25 +01001004 DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
Vladimir Marko65979462017-05-19 17:25:12 +01001005 __ leal(temp.AsRegister<CpuRegister>(),
Andreas Gampe3db70682018-12-26 15:12:03 -08001006 Address::Absolute(kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001007 RecordBootImageMethodPatch(invoke);
Vladimir Marko65979462017-05-19 17:25:12 +01001008 break;
Vladimir Markob066d432018-01-03 13:14:37 +00001009 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
1010 // Note: Boot image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
1011 __ movl(temp.AsRegister<CpuRegister>(),
Andreas Gampe3db70682018-12-26 15:12:03 -08001012 Address::Absolute(kDummy32BitOffset, /* no_rip= */ false));
Vladimir Markoe47f60c2018-02-21 13:43:28 +00001013 RecordBootImageRelRoPatch(GetBootImageOffset(invoke));
Vladimir Markob066d432018-01-03 13:14:37 +00001014 break;
1015 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001016 case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
Vladimir Marko58155012015-08-19 12:49:41 +00001017 __ movq(temp.AsRegister<CpuRegister>(),
Andreas Gampe3db70682018-12-26 15:12:03 -08001018 Address::Absolute(kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001019 RecordMethodBssEntryPatch(invoke);
Vladimir Markod5fd5c32019-07-02 14:46:32 +01001020 // No need for memory fence, thanks to the x86-64 memory model.
Vladimir Marko58155012015-08-19 12:49:41 +00001021 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001022 }
Vladimir Marko8e524ad2018-07-13 10:27:43 +01001023 case HInvokeStaticOrDirect::MethodLoadKind::kJitDirectAddress:
1024 Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress());
1025 break;
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001026 case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
1027 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
1028 return; // No code pointer retrieval; the runtime performs the call directly.
Vladimir Marko9b688a02015-05-06 14:12:42 +01001029 }
Vladimir Marko58155012015-08-19 12:49:41 +00001030 }
1031
1032 switch (invoke->GetCodePtrLocation()) {
1033 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
1034 __ call(&frame_entry_label_);
1035 break;
Vladimir Marko58155012015-08-19 12:49:41 +00001036 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
1037 // (callee_method + offset_of_quick_compiled_code)()
1038 __ call(Address(callee_method.AsRegister<CpuRegister>(),
1039 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001040 kX86_64PointerSize).SizeValue()));
Vladimir Marko58155012015-08-19 12:49:41 +00001041 break;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001042 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001043 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001044
1045 DCHECK(!IsLeafMethod());
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001046}
1047
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001048void CodeGeneratorX86_64::GenerateVirtualCall(
1049 HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001050 CpuRegister temp = temp_in.AsRegister<CpuRegister>();
1051 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1052 invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001053
1054 // Use the calling convention instead of the location of the receiver, as
1055 // intrinsics may have put the receiver in a different register. In the intrinsics
1056 // slow path, the arguments have been moved to the right place, so here we are
1057 // guaranteed that the receiver is the first register of the calling convention.
1058 InvokeDexCallingConvention calling_convention;
1059 Register receiver = calling_convention.GetRegisterAt(0);
1060
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001061 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
Roland Levillain0d5a2812015-11-13 10:07:31 +00001062 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00001063 __ movl(temp, Address(CpuRegister(receiver), class_offset));
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001064 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00001065 // Instead of simply (possibly) unpoisoning `temp` here, we should
1066 // emit a read barrier for the previous class reference load.
1067 // However this is not required in practice, as this is an
1068 // intermediate/temporary reference and because the current
1069 // concurrent copying collector keeps the from-space memory
1070 // intact/accessible until the end of the marking phase (the
1071 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001072 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00001073
Nicolas Geoffray20036d82019-11-28 16:15:00 +00001074 MaybeGenerateInlineCacheCheck(invoke, temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00001075
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001076 // temp = temp->GetMethodAt(method_offset);
1077 __ movq(temp, Address(temp, method_offset));
1078 // call temp->GetEntryPoint();
1079 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07001080 kX86_64PointerSize).SizeValue()));
Vladimir Markoe7197bf2017-06-02 17:00:23 +01001081 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001082}
1083
Vladimir Marko6fd16062018-06-26 11:02:04 +01001084void CodeGeneratorX86_64::RecordBootImageIntrinsicPatch(uint32_t intrinsic_data) {
Vladimir Marko2d06e022019-07-08 15:45:19 +01001085 boot_image_other_patches_.emplace_back(/* target_dex_file= */ nullptr, intrinsic_data);
1086 __ Bind(&boot_image_other_patches_.back().label);
Vladimir Marko6fd16062018-06-26 11:02:04 +01001087}
1088
Vladimir Markob066d432018-01-03 13:14:37 +00001089void CodeGeneratorX86_64::RecordBootImageRelRoPatch(uint32_t boot_image_offset) {
Vladimir Marko2d06e022019-07-08 15:45:19 +01001090 boot_image_other_patches_.emplace_back(/* target_dex_file= */ nullptr, boot_image_offset);
1091 __ Bind(&boot_image_other_patches_.back().label);
Vladimir Markob066d432018-01-03 13:14:37 +00001092}
1093
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001094void CodeGeneratorX86_64::RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke) {
1095 boot_image_method_patches_.emplace_back(
1096 invoke->GetTargetMethod().dex_file, invoke->GetTargetMethod().index);
Vladimir Marko65979462017-05-19 17:25:12 +01001097 __ Bind(&boot_image_method_patches_.back().label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001098}
1099
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001100void CodeGeneratorX86_64::RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke) {
1101 method_bss_entry_patches_.emplace_back(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex());
1102 __ Bind(&method_bss_entry_patches_.back().label);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001103}
1104
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001105void CodeGeneratorX86_64::RecordBootImageTypePatch(HLoadClass* load_class) {
1106 boot_image_type_patches_.emplace_back(
1107 &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001108 __ Bind(&boot_image_type_patches_.back().label);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001109}
1110
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001111Label* CodeGeneratorX86_64::NewTypeBssEntryPatch(HLoadClass* load_class) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001112 type_bss_entry_patches_.emplace_back(
1113 &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001114 return &type_bss_entry_patches_.back().label;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001115}
1116
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001117void CodeGeneratorX86_64::RecordBootImageStringPatch(HLoadString* load_string) {
1118 boot_image_string_patches_.emplace_back(
1119 &load_string->GetDexFile(), load_string->GetStringIndex().index_);
1120 __ Bind(&boot_image_string_patches_.back().label);
Vladimir Marko65979462017-05-19 17:25:12 +01001121}
1122
Vladimir Markoaad75c62016-10-03 08:46:48 +00001123Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001124 string_bss_entry_patches_.emplace_back(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001125 &load_string->GetDexFile(), load_string->GetStringIndex().index_);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001126 return &string_bss_entry_patches_.back().label;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001127}
1128
Vladimir Marko6fd16062018-06-26 11:02:04 +01001129void CodeGeneratorX86_64::LoadBootImageAddress(CpuRegister reg, uint32_t boot_image_reference) {
1130 if (GetCompilerOptions().IsBootImage()) {
Andreas Gampe3db70682018-12-26 15:12:03 -08001131 __ leal(reg, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko6fd16062018-06-26 11:02:04 +01001132 RecordBootImageIntrinsicPatch(boot_image_reference);
Vladimir Markoa2da9b92018-10-10 14:21:55 +01001133 } else if (GetCompilerOptions().GetCompilePic()) {
Andreas Gampe3db70682018-12-26 15:12:03 -08001134 __ movl(reg, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko6fd16062018-06-26 11:02:04 +01001135 RecordBootImageRelRoPatch(boot_image_reference);
Vladimir Markoeebb8212018-06-05 14:57:24 +01001136 } else {
Vladimir Marko8e524ad2018-07-13 10:27:43 +01001137 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markoeebb8212018-06-05 14:57:24 +01001138 gc::Heap* heap = Runtime::Current()->GetHeap();
1139 DCHECK(!heap->GetBootImageSpaces().empty());
Vladimir Marko6fd16062018-06-26 11:02:04 +01001140 const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_reference;
Vladimir Markoeebb8212018-06-05 14:57:24 +01001141 __ movl(reg, Immediate(dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(address))));
1142 }
1143}
1144
Vladimir Marko6fd16062018-06-26 11:02:04 +01001145void CodeGeneratorX86_64::AllocateInstanceForIntrinsic(HInvokeStaticOrDirect* invoke,
1146 uint32_t boot_image_offset) {
1147 DCHECK(invoke->IsStatic());
1148 InvokeRuntimeCallingConvention calling_convention;
1149 CpuRegister argument = CpuRegister(calling_convention.GetRegisterAt(0));
1150 if (GetCompilerOptions().IsBootImage()) {
1151 DCHECK_EQ(boot_image_offset, IntrinsicVisitor::IntegerValueOfInfo::kInvalidReference);
1152 // Load the class the same way as for HLoadClass::LoadKind::kBootImageLinkTimePcRelative.
1153 __ leal(argument,
Andreas Gampe3db70682018-12-26 15:12:03 -08001154 Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko6fd16062018-06-26 11:02:04 +01001155 MethodReference target_method = invoke->GetTargetMethod();
1156 dex::TypeIndex type_idx = target_method.dex_file->GetMethodId(target_method.index).class_idx_;
1157 boot_image_type_patches_.emplace_back(target_method.dex_file, type_idx.index_);
1158 __ Bind(&boot_image_type_patches_.back().label);
1159 } else {
1160 LoadBootImageAddress(argument, boot_image_offset);
1161 }
1162 InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
1163 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
1164}
1165
Vladimir Markoaad75c62016-10-03 08:46:48 +00001166// The label points to the end of the "movl" or another instruction but the literal offset
1167// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
1168constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
1169
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001170template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
Vladimir Markoaad75c62016-10-03 08:46:48 +00001171inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
1172 const ArenaDeque<PatchInfo<Label>>& infos,
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001173 ArenaVector<linker::LinkerPatch>* linker_patches) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00001174 for (const PatchInfo<Label>& info : infos) {
1175 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
1176 linker_patches->push_back(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001177 Factory(literal_offset, info.target_dex_file, info.label.Position(), info.offset_or_index));
Vladimir Markoaad75c62016-10-03 08:46:48 +00001178 }
1179}
1180
Vladimir Marko6fd16062018-06-26 11:02:04 +01001181template <linker::LinkerPatch (*Factory)(size_t, uint32_t, uint32_t)>
1182linker::LinkerPatch NoDexFileAdapter(size_t literal_offset,
1183 const DexFile* target_dex_file,
1184 uint32_t pc_insn_offset,
1185 uint32_t boot_image_offset) {
1186 DCHECK(target_dex_file == nullptr); // Unused for these patches, should be null.
1187 return Factory(literal_offset, pc_insn_offset, boot_image_offset);
Vladimir Markob066d432018-01-03 13:14:37 +00001188}
1189
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001190void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
Vladimir Marko58155012015-08-19 12:49:41 +00001191 DCHECK(linker_patches->empty());
1192 size_t size =
Vladimir Marko65979462017-05-19 17:25:12 +01001193 boot_image_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001194 method_bss_entry_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00001195 boot_image_type_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01001196 type_bss_entry_patches_.size() +
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001197 boot_image_string_patches_.size() +
Vladimir Marko6fd16062018-06-26 11:02:04 +01001198 string_bss_entry_patches_.size() +
Vladimir Marko2d06e022019-07-08 15:45:19 +01001199 boot_image_other_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00001200 linker_patches->reserve(size);
Vladimir Marko44ca0752019-07-29 10:18:25 +01001201 if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001202 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
1203 boot_image_method_patches_, linker_patches);
1204 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
1205 boot_image_type_patches_, linker_patches);
1206 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001207 boot_image_string_patches_, linker_patches);
Vladimir Marko764d4542017-05-16 10:31:41 +01001208 } else {
Vladimir Marko2d06e022019-07-08 15:45:19 +01001209 DCHECK(boot_image_method_patches_.empty());
Vladimir Markoe47f60c2018-02-21 13:43:28 +00001210 DCHECK(boot_image_type_patches_.empty());
1211 DCHECK(boot_image_string_patches_.empty());
Vladimir Marko2d06e022019-07-08 15:45:19 +01001212 }
1213 if (GetCompilerOptions().IsBootImage()) {
1214 EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::IntrinsicReferencePatch>>(
1215 boot_image_other_patches_, linker_patches);
1216 } else {
1217 EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::DataBimgRelRoPatch>>(
1218 boot_image_other_patches_, linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001219 }
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001220 EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
1221 method_bss_entry_patches_, linker_patches);
1222 EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
1223 type_bss_entry_patches_, linker_patches);
1224 EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
1225 string_bss_entry_patches_, linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001226 DCHECK_EQ(size, linker_patches->size());
Vladimir Marko58155012015-08-19 12:49:41 +00001227}
1228
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001229void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001230 stream << Register(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001231}
1232
1233void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001234 stream << FloatRegister(reg);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001235}
1236
Vladimir Markoa0431112018-06-25 09:32:54 +01001237const X86_64InstructionSetFeatures& CodeGeneratorX86_64::GetInstructionSetFeatures() const {
1238 return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86_64InstructionSetFeatures();
1239}
1240
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001241size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1242 __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
1243 return kX86_64WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001244}
1245
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001246size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1247 __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1248 return kX86_64WordSize;
1249}
1250
1251size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001252 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001253 __ movups(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
Aart Bikb13c65b2017-03-21 20:14:07 -07001254 } else {
1255 __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
1256 }
Artem Serov6a0b6572019-07-26 20:38:37 +01001257 return GetSlowPathFPWidth();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001258}
1259
1260size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001261 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001262 __ movups(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
Aart Bikb13c65b2017-03-21 20:14:07 -07001263 } else {
1264 __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
1265 }
Artem Serov6a0b6572019-07-26 20:38:37 +01001266 return GetSlowPathFPWidth();
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001267}
1268
Calin Juravle175dc732015-08-25 15:42:32 +01001269void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint,
1270 HInstruction* instruction,
1271 uint32_t dex_pc,
1272 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001273 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001274 GenerateInvokeRuntime(GetThreadOffset<kX86_64PointerSize>(entrypoint).Int32Value());
1275 if (EntrypointRequiresStackMap(entrypoint)) {
1276 RecordPcInfo(instruction, dex_pc, slow_path);
1277 }
Alexandre Rames8158f282015-08-07 10:26:17 +01001278}
1279
Roland Levillaindec8f632016-07-22 17:10:06 +01001280void CodeGeneratorX86_64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1281 HInstruction* instruction,
1282 SlowPathCode* slow_path) {
1283 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001284 GenerateInvokeRuntime(entry_point_offset);
1285}
1286
1287void CodeGeneratorX86_64::GenerateInvokeRuntime(int32_t entry_point_offset) {
Andreas Gampe3db70682018-12-26 15:12:03 -08001288 __ gs()->call(Address::Absolute(entry_point_offset, /* no_rip= */ true));
Roland Levillaindec8f632016-07-22 17:10:06 +01001289}
1290
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001291static constexpr int kNumberOfCpuRegisterPairs = 0;
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001292// Use a fake return address register to mimic Quick.
1293static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1);
Mark Mendellfb8d2792015-03-31 22:16:59 -04001294CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +00001295 const CompilerOptions& compiler_options,
1296 OptimizingCompilerStats* stats)
Nicolas Geoffray98893962015-01-21 12:32:32 +00001297 : CodeGenerator(graph,
1298 kNumberOfCpuRegisters,
1299 kNumberOfFloatRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001300 kNumberOfCpuRegisterPairs,
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001301 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1302 arraysize(kCoreCalleeSaves))
Nicolas Geoffray4597b5b2015-01-23 21:51:55 +00001303 | (1 << kFakeReturnRegister),
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001304 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1305 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001306 compiler_options,
1307 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001308 block_labels_(nullptr),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001309 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001310 instruction_visitor_(graph, this),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001311 move_resolver_(graph->GetAllocator(), this),
1312 assembler_(graph->GetAllocator()),
Vladimir Marko58155012015-08-19 12:49:41 +00001313 constant_area_start_(0),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001314 boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1315 method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1316 boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1317 type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001318 boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001319 string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko2d06e022019-07-08 15:45:19 +01001320 boot_image_other_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001321 jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1322 jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1323 fixups_to_jump_tables_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001324 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
1325}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001326
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001327InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
1328 CodeGeneratorX86_64* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001329 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001330 assembler_(codegen->GetAssembler()),
1331 codegen_(codegen) {}
1332
David Brazdil58282f42016-01-14 12:45:10 +00001333void CodeGeneratorX86_64::SetupBlockedRegisters() const {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001334 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001335 blocked_core_registers_[RSP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001336
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001337 // Block the register used as TMP.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001338 blocked_core_registers_[TMP] = true;
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001339}
1340
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001341static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001342 return dwarf::Reg::X86_64Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001343}
David Srbecky9d8606d2015-04-12 09:35:32 +01001344
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001345static dwarf::Reg DWARFReg(FloatRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001346 return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001347}
1348
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001349void CodeGeneratorX86_64::MaybeIncrementHotness(bool is_frame_entry) {
1350 if (GetCompilerOptions().CountHotnessInCompiledCode()) {
1351 NearLabel overflow;
1352 Register method = kMethodRegisterArgument;
1353 if (!is_frame_entry) {
1354 CHECK(RequiresCurrentMethod());
1355 method = TMP;
1356 __ movq(CpuRegister(method), Address(CpuRegister(RSP), kCurrentMethodStackOffset));
1357 }
1358 __ cmpw(Address(CpuRegister(method), ArtMethod::HotnessCountOffset().Int32Value()),
1359 Immediate(ArtMethod::MaxCounter()));
1360 __ j(kEqual, &overflow);
1361 __ addw(Address(CpuRegister(method), ArtMethod::HotnessCountOffset().Int32Value()),
1362 Immediate(1));
1363 __ Bind(&overflow);
1364 }
1365
1366 if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) {
1367 ScopedObjectAccess soa(Thread::Current());
1368 ProfilingInfo* info = GetGraph()->GetArtMethod()->GetProfilingInfo(kRuntimePointerSize);
1369 uint64_t address = reinterpret_cast64<uint64_t>(info);
1370 NearLabel done;
1371 __ movq(CpuRegister(TMP), Immediate(address));
1372 __ addw(Address(CpuRegister(TMP), ProfilingInfo::BaselineHotnessCountOffset().Int32Value()),
1373 Immediate(1));
1374 __ j(kCarryClear, &done);
1375 if (HasEmptyFrame()) {
1376 CHECK(is_frame_entry);
1377 // Frame alignment, and the stub expects the method on the stack.
1378 __ pushq(CpuRegister(RDI));
1379 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1380 __ cfi().RelOffset(DWARFReg(RDI), 0);
1381 } else if (!RequiresCurrentMethod()) {
1382 CHECK(is_frame_entry);
1383 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
1384 }
1385 GenerateInvokeRuntime(
1386 GetThreadOffset<kX86_64PointerSize>(kQuickCompileOptimized).Int32Value());
1387 if (HasEmptyFrame()) {
1388 __ popq(CpuRegister(RDI));
1389 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1390 __ cfi().Restore(DWARFReg(RDI));
1391 }
1392 __ Bind(&done);
1393 }
1394}
1395
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001396void CodeGeneratorX86_64::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001397 __ cfi().SetCurrentCFAOffset(kX86_64WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001398 __ Bind(&frame_entry_label_);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001399 bool skip_overflow_check = IsLeafMethod()
Dave Allison648d7112014-07-25 16:15:27 -07001400 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001401 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001402
Nicolas Geoffray8d728322018-01-18 22:44:32 +00001403
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001404 if (!skip_overflow_check) {
Vladimir Marko33bff252017-11-01 14:35:42 +00001405 size_t reserved_bytes = GetStackOverflowReservedBytes(InstructionSet::kX86_64);
1406 __ testq(CpuRegister(RAX), Address(CpuRegister(RSP), -static_cast<int32_t>(reserved_bytes)));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001407 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001408 }
Nicolas Geoffraya26369a2015-01-22 08:46:05 +00001409
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001410 if (!HasEmptyFrame()) {
1411 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
1412 Register reg = kCoreCalleeSaves[i];
1413 if (allocated_registers_.ContainsCoreRegister(reg)) {
1414 __ pushq(CpuRegister(reg));
1415 __ cfi().AdjustCFAOffset(kX86_64WordSize);
1416 __ cfi().RelOffset(DWARFReg(reg), 0);
1417 }
1418 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001419
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001420 int adjust = GetFrameSize() - GetCoreSpillSize();
1421 __ subq(CpuRegister(RSP), Immediate(adjust));
1422 __ cfi().AdjustCFAOffset(adjust);
1423 uint32_t xmm_spill_location = GetFpuSpillStart();
1424 size_t xmm_spill_slot_size = GetCalleePreservedFPWidth();
1425
1426 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1427 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1428 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1429 __ movsd(Address(CpuRegister(RSP), offset), XmmRegister(kFpuCalleeSaves[i]));
1430 __ cfi().RelOffset(DWARFReg(kFpuCalleeSaves[i]), offset);
1431 }
1432 }
1433
1434 // Save the current method if we need it. Note that we do not
1435 // do this in HCurrentMethod, as the instruction might have been removed
1436 // in the SSA graph.
1437 if (RequiresCurrentMethod()) {
1438 CHECK(!HasEmptyFrame());
1439 __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
1440 CpuRegister(kMethodRegisterArgument));
1441 }
1442
1443 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1444 CHECK(!HasEmptyFrame());
1445 // Initialize should_deoptimize flag to 0.
1446 __ movl(Address(CpuRegister(RSP), GetStackOffsetOfShouldDeoptimizeFlag()), Immediate(0));
Nicolas Geoffray98893962015-01-21 12:32:32 +00001447 }
1448 }
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +01001449
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001450 MaybeIncrementHotness(/* is_frame_entry= */ true);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001451}
1452
1453void CodeGeneratorX86_64::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001454 __ cfi().RememberState();
1455 if (!HasEmptyFrame()) {
1456 uint32_t xmm_spill_location = GetFpuSpillStart();
Artem Serov6a0b6572019-07-26 20:38:37 +01001457 size_t xmm_spill_slot_size = GetCalleePreservedFPWidth();
David Srbeckyc34dc932015-04-12 09:27:43 +01001458 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1459 if (allocated_registers_.ContainsFloatingPointRegister(kFpuCalleeSaves[i])) {
1460 int offset = xmm_spill_location + (xmm_spill_slot_size * i);
1461 __ movsd(XmmRegister(kFpuCalleeSaves[i]), Address(CpuRegister(RSP), offset));
1462 __ cfi().Restore(DWARFReg(kFpuCalleeSaves[i]));
1463 }
1464 }
1465
1466 int adjust = GetFrameSize() - GetCoreSpillSize();
1467 __ addq(CpuRegister(RSP), Immediate(adjust));
1468 __ cfi().AdjustCFAOffset(-adjust);
1469
1470 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1471 Register reg = kCoreCalleeSaves[i];
1472 if (allocated_registers_.ContainsCoreRegister(reg)) {
1473 __ popq(CpuRegister(reg));
1474 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86_64WordSize));
1475 __ cfi().Restore(DWARFReg(reg));
1476 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001477 }
1478 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001479 __ ret();
1480 __ cfi().RestoreState();
1481 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001482}
1483
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001484void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
1485 __ Bind(GetLabelOf(block));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001486}
1487
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001488void CodeGeneratorX86_64::Move(Location destination, Location source) {
1489 if (source.Equals(destination)) {
1490 return;
1491 }
1492 if (destination.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001493 CpuRegister dest = destination.AsRegister<CpuRegister>();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001494 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001495 __ movq(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001496 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001497 __ movd(dest, source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001498 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001499 __ movl(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
1500 } else if (source.IsConstant()) {
1501 HConstant* constant = source.GetConstant();
1502 if (constant->IsLongConstant()) {
1503 Load64BitValue(dest, constant->AsLongConstant()->GetValue());
1504 } else {
1505 Load32BitValue(dest, GetInt32ValueOf(constant));
1506 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001507 } else {
1508 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001509 __ movq(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001510 }
1511 } else if (destination.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001512 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001513 if (source.IsRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001514 __ movd(dest, source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001515 } else if (source.IsFpuRegister()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001516 __ movaps(dest, source.AsFpuRegister<XmmRegister>());
1517 } else if (source.IsConstant()) {
1518 HConstant* constant = source.GetConstant();
1519 int64_t value = CodeGenerator::GetInt64ValueOf(constant);
1520 if (constant->IsFloatConstant()) {
1521 Load32BitValue(dest, static_cast<int32_t>(value));
1522 } else {
1523 Load64BitValue(dest, value);
1524 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001525 } else if (source.IsStackSlot()) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001526 __ movss(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001527 } else {
1528 DCHECK(source.IsDoubleStackSlot());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001529 __ movsd(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001530 }
1531 } else if (destination.IsStackSlot()) {
1532 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001533 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001534 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001535 } else if (source.IsFpuRegister()) {
1536 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001537 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001538 } else if (source.IsConstant()) {
1539 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001540 int32_t value = GetInt32ValueOf(constant);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001541 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001542 } else {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001543 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001544 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1545 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001546 }
1547 } else {
1548 DCHECK(destination.IsDoubleStackSlot());
1549 if (source.IsRegister()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001550 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001551 source.AsRegister<CpuRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001552 } else if (source.IsFpuRegister()) {
1553 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00001554 source.AsFpuRegister<XmmRegister>());
Mark Mendell24f2dfa2015-01-14 19:51:45 -05001555 } else if (source.IsConstant()) {
1556 HConstant* constant = source.GetConstant();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001557 DCHECK(constant->IsLongConstant() || constant->IsDoubleConstant());
1558 int64_t value = GetInt64ValueOf(constant);
Mark Mendellcfa410b2015-05-25 16:02:44 -04001559 Store64BitValueToStack(destination, value);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001560 } else {
1561 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001562 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1563 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001564 }
1565 }
1566}
1567
Calin Juravle175dc732015-08-25 15:42:32 +01001568void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
1569 DCHECK(location.IsRegister());
1570 Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
1571}
1572
Calin Juravlee460d1d2015-09-29 04:52:17 +01001573void CodeGeneratorX86_64::MoveLocation(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001574 Location dst, Location src, DataType::Type dst_type ATTRIBUTE_UNUSED) {
Calin Juravlee460d1d2015-09-29 04:52:17 +01001575 Move(dst, src);
1576}
1577
1578void CodeGeneratorX86_64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1579 if (location.IsRegister()) {
1580 locations->AddTemp(location);
1581 } else {
1582 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1583 }
1584}
1585
David Brazdilfc6a86a2015-06-26 10:33:45 +00001586void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Aart Bika8b8e9b2018-01-09 11:01:02 -08001587 if (successor->IsExitBlock()) {
1588 DCHECK(got->GetPrevious()->AlwaysThrows());
1589 return; // no code needed
1590 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001591
1592 HBasicBlock* block = got->GetBlock();
1593 HInstruction* previous = got->GetPrevious();
1594
1595 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001596 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001597 codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001598 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1599 return;
1600 }
1601
1602 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1603 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1604 }
1605 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001606 __ jmp(codegen_->GetLabelOf(successor));
1607 }
1608}
1609
David Brazdilfc6a86a2015-06-26 10:33:45 +00001610void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
1611 got->SetLocations(nullptr);
1612}
1613
1614void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
1615 HandleGoto(got, got->GetSuccessor());
1616}
1617
1618void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1619 try_boundary->SetLocations(nullptr);
1620}
1621
1622void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
1623 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1624 if (!successor->IsExitBlock()) {
1625 HandleGoto(try_boundary, successor);
1626 }
1627}
1628
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001629void LocationsBuilderX86_64::VisitExit(HExit* exit) {
1630 exit->SetLocations(nullptr);
1631}
1632
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001633void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001634}
1635
Mark Mendell152408f2015-12-31 12:28:50 -05001636template<class LabelType>
Mark Mendellc4701932015-04-10 13:18:51 -04001637void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
Mark Mendell152408f2015-12-31 12:28:50 -05001638 LabelType* true_label,
1639 LabelType* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001640 if (cond->IsFPConditionTrueIfNaN()) {
1641 __ j(kUnordered, true_label);
1642 } else if (cond->IsFPConditionFalseIfNaN()) {
1643 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001644 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001645 __ j(X86_64FPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001646}
1647
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001648void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition) {
Mark Mendellc4701932015-04-10 13:18:51 -04001649 LocationSummary* locations = condition->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001650
Mark Mendellc4701932015-04-10 13:18:51 -04001651 Location left = locations->InAt(0);
1652 Location right = locations->InAt(1);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001653 DataType::Type type = condition->InputAt(0)->GetType();
Mark Mendellc4701932015-04-10 13:18:51 -04001654 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001655 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001656 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001657 case DataType::Type::kInt8:
1658 case DataType::Type::kUint16:
1659 case DataType::Type::kInt16:
1660 case DataType::Type::kInt32:
1661 case DataType::Type::kReference: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001662 codegen_->GenerateIntCompare(left, right);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001663 break;
1664 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001665 case DataType::Type::kInt64: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001666 codegen_->GenerateLongCompare(left, right);
Mark Mendellc4701932015-04-10 13:18:51 -04001667 break;
1668 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001669 case DataType::Type::kFloat32: {
Mark Mendellc4701932015-04-10 13:18:51 -04001670 if (right.IsFpuRegister()) {
1671 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1672 } else if (right.IsConstant()) {
1673 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1674 codegen_->LiteralFloatAddress(
1675 right.GetConstant()->AsFloatConstant()->GetValue()));
1676 } else {
1677 DCHECK(right.IsStackSlot());
1678 __ ucomiss(left.AsFpuRegister<XmmRegister>(),
1679 Address(CpuRegister(RSP), right.GetStackIndex()));
1680 }
Mark Mendellc4701932015-04-10 13:18:51 -04001681 break;
1682 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001683 case DataType::Type::kFloat64: {
Mark Mendellc4701932015-04-10 13:18:51 -04001684 if (right.IsFpuRegister()) {
1685 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1686 } else if (right.IsConstant()) {
1687 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1688 codegen_->LiteralDoubleAddress(
1689 right.GetConstant()->AsDoubleConstant()->GetValue()));
1690 } else {
1691 DCHECK(right.IsDoubleStackSlot());
1692 __ ucomisd(left.AsFpuRegister<XmmRegister>(),
1693 Address(CpuRegister(RSP), right.GetStackIndex()));
1694 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001695 break;
1696 }
1697 default:
1698 LOG(FATAL) << "Unexpected condition type " << type;
1699 }
1700}
1701
1702template<class LabelType>
1703void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
1704 LabelType* true_target_in,
1705 LabelType* false_target_in) {
1706 // Generated branching requires both targets to be explicit. If either of the
1707 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1708 LabelType fallthrough_target;
1709 LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1710 LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1711
1712 // Generate the comparison to set the CC.
1713 GenerateCompareTest(condition);
1714
1715 // Now generate the correct jump(s).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001716 DataType::Type type = condition->InputAt(0)->GetType();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001717 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001718 case DataType::Type::kInt64: {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001719 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
1720 break;
1721 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001722 case DataType::Type::kFloat32: {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001723 GenerateFPJumps(condition, true_target, false_target);
1724 break;
1725 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001726 case DataType::Type::kFloat64: {
Mark Mendellc4701932015-04-10 13:18:51 -04001727 GenerateFPJumps(condition, true_target, false_target);
1728 break;
1729 }
1730 default:
1731 LOG(FATAL) << "Unexpected condition type " << type;
1732 }
1733
David Brazdil0debae72015-11-12 18:37:00 +00001734 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001735 __ jmp(false_target);
1736 }
David Brazdil0debae72015-11-12 18:37:00 +00001737
1738 if (fallthrough_target.IsLinked()) {
1739 __ Bind(&fallthrough_target);
1740 }
Mark Mendellc4701932015-04-10 13:18:51 -04001741}
1742
David Brazdil0debae72015-11-12 18:37:00 +00001743static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1744 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1745 // are set only strictly before `branch`. We can't use the eflags on long
1746 // conditions if they are materialized due to the complex branching.
1747 return cond->IsCondition() &&
1748 cond->GetNext() == branch &&
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001749 !DataType::IsFloatingPointType(cond->InputAt(0)->GetType());
David Brazdil0debae72015-11-12 18:37:00 +00001750}
1751
Mark Mendell152408f2015-12-31 12:28:50 -05001752template<class LabelType>
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001753void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001754 size_t condition_input_index,
Mark Mendell152408f2015-12-31 12:28:50 -05001755 LabelType* true_target,
1756 LabelType* false_target) {
David Brazdil0debae72015-11-12 18:37:00 +00001757 HInstruction* cond = instruction->InputAt(condition_input_index);
1758
1759 if (true_target == nullptr && false_target == nullptr) {
1760 // Nothing to do. The code always falls through.
1761 return;
1762 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001763 // Constant condition, statically compared against "true" (integer value 1).
1764 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001765 if (true_target != nullptr) {
1766 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001767 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001768 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001769 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001770 if (false_target != nullptr) {
1771 __ jmp(false_target);
1772 }
1773 }
1774 return;
1775 }
1776
1777 // The following code generates these patterns:
1778 // (1) true_target == nullptr && false_target != nullptr
1779 // - opposite condition true => branch to false_target
1780 // (2) true_target != nullptr && false_target == nullptr
1781 // - condition true => branch to true_target
1782 // (3) true_target != nullptr && false_target != nullptr
1783 // - condition true => branch to true_target
1784 // - branch to false_target
1785 if (IsBooleanValueOrMaterializedCondition(cond)) {
1786 if (AreEflagsSetFrom(cond, instruction)) {
1787 if (true_target == nullptr) {
1788 __ j(X86_64IntegerCondition(cond->AsCondition()->GetOppositeCondition()), false_target);
1789 } else {
1790 __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
1791 }
1792 } else {
1793 // Materialized condition, compare against 0.
1794 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
1795 if (lhs.IsRegister()) {
1796 __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
1797 } else {
1798 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
1799 }
1800 if (true_target == nullptr) {
1801 __ j(kEqual, false_target);
1802 } else {
1803 __ j(kNotEqual, true_target);
1804 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001805 }
1806 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001807 // Condition has not been materialized, use its inputs as the
1808 // comparison and its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001809 HCondition* condition = cond->AsCondition();
Mark Mendellc4701932015-04-10 13:18:51 -04001810
David Brazdil0debae72015-11-12 18:37:00 +00001811 // If this is a long or FP comparison that has been folded into
1812 // the HCondition, generate the comparison directly.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001813 DataType::Type type = condition->InputAt(0)->GetType();
1814 if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
David Brazdil0debae72015-11-12 18:37:00 +00001815 GenerateCompareTestAndBranch(condition, true_target, false_target);
1816 return;
1817 }
1818
1819 Location lhs = condition->GetLocations()->InAt(0);
1820 Location rhs = condition->GetLocations()->InAt(1);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001821 codegen_->GenerateIntCompare(lhs, rhs);
David Brazdil0debae72015-11-12 18:37:00 +00001822 if (true_target == nullptr) {
1823 __ j(X86_64IntegerCondition(condition->GetOppositeCondition()), false_target);
1824 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001825 __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001826 }
Dave Allison20dfc792014-06-16 20:44:29 -07001827 }
David Brazdil0debae72015-11-12 18:37:00 +00001828
1829 // If neither branch falls through (case 3), the conditional branch to `true_target`
1830 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1831 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001832 __ jmp(false_target);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001833 }
1834}
1835
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001836void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001837 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00001838 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001839 locations->SetInAt(0, Location::Any());
1840 }
1841}
1842
1843void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001844 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1845 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1846 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1847 nullptr : codegen_->GetLabelOf(true_successor);
1848 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1849 nullptr : codegen_->GetLabelOf(false_successor);
Andreas Gampe3db70682018-12-26 15:12:03 -08001850 GenerateTestAndBranch(if_instr, /* condition_input_index= */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001851}
1852
1853void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001854 LocationSummary* locations = new (GetGraph()->GetAllocator())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001855 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01001856 InvokeRuntimeCallingConvention calling_convention;
1857 RegisterSet caller_saves = RegisterSet::Empty();
1858 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1859 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00001860 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001861 locations->SetInAt(0, Location::Any());
1862 }
1863}
1864
1865void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001866 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathX86_64>(deoptimize);
David Brazdil74eb1b22015-12-14 11:44:01 +00001867 GenerateTestAndBranch<Label>(deoptimize,
Andreas Gampe3db70682018-12-26 15:12:03 -08001868 /* condition_input_index= */ 0,
David Brazdil74eb1b22015-12-14 11:44:01 +00001869 slow_path->GetEntryLabel(),
Andreas Gampe3db70682018-12-26 15:12:03 -08001870 /* false_target= */ nullptr);
David Brazdil74eb1b22015-12-14 11:44:01 +00001871}
1872
Mingyao Yang063fc772016-08-02 11:02:54 -07001873void LocationsBuilderX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001874 LocationSummary* locations = new (GetGraph()->GetAllocator())
Mingyao Yang063fc772016-08-02 11:02:54 -07001875 LocationSummary(flag, LocationSummary::kNoCall);
1876 locations->SetOut(Location::RequiresRegister());
1877}
1878
1879void InstructionCodeGeneratorX86_64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
1880 __ movl(flag->GetLocations()->Out().AsRegister<CpuRegister>(),
1881 Address(CpuRegister(RSP), codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
1882}
1883
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001884static bool SelectCanUseCMOV(HSelect* select) {
1885 // There are no conditional move instructions for XMMs.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001886 if (DataType::IsFloatingPointType(select->GetType())) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001887 return false;
1888 }
1889
1890 // A FP condition doesn't generate the single CC that we need.
1891 HInstruction* condition = select->GetCondition();
1892 if (condition->IsCondition() &&
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001893 DataType::IsFloatingPointType(condition->InputAt(0)->GetType())) {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001894 return false;
1895 }
1896
1897 // We can generate a CMOV for this Select.
1898 return true;
1899}
1900
David Brazdil74eb1b22015-12-14 11:44:01 +00001901void LocationsBuilderX86_64::VisitSelect(HSelect* select) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001902 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001903 if (DataType::IsFloatingPointType(select->GetType())) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001904 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001905 locations->SetInAt(1, Location::Any());
David Brazdil74eb1b22015-12-14 11:44:01 +00001906 } else {
1907 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001908 if (SelectCanUseCMOV(select)) {
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001909 if (select->InputAt(1)->IsConstant()) {
1910 locations->SetInAt(1, Location::RequiresRegister());
1911 } else {
1912 locations->SetInAt(1, Location::Any());
1913 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001914 } else {
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001915 locations->SetInAt(1, Location::Any());
1916 }
David Brazdil74eb1b22015-12-14 11:44:01 +00001917 }
1918 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1919 locations->SetInAt(2, Location::RequiresRegister());
1920 }
1921 locations->SetOut(Location::SameAsFirstInput());
1922}
1923
1924void InstructionCodeGeneratorX86_64::VisitSelect(HSelect* select) {
1925 LocationSummary* locations = select->GetLocations();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001926 if (SelectCanUseCMOV(select)) {
1927 // If both the condition and the source types are integer, we can generate
1928 // a CMOV to implement Select.
1929 CpuRegister value_false = locations->InAt(0).AsRegister<CpuRegister>();
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001930 Location value_true_loc = locations->InAt(1);
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001931 DCHECK(locations->InAt(0).Equals(locations->Out()));
1932
1933 HInstruction* select_condition = select->GetCondition();
1934 Condition cond = kNotEqual;
1935
1936 // Figure out how to test the 'condition'.
1937 if (select_condition->IsCondition()) {
1938 HCondition* condition = select_condition->AsCondition();
1939 if (!condition->IsEmittedAtUseSite()) {
1940 // This was a previously materialized condition.
1941 // Can we use the existing condition code?
1942 if (AreEflagsSetFrom(condition, select)) {
1943 // Materialization was the previous instruction. Condition codes are right.
1944 cond = X86_64IntegerCondition(condition->GetCondition());
1945 } else {
1946 // No, we have to recreate the condition code.
1947 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1948 __ testl(cond_reg, cond_reg);
1949 }
1950 } else {
1951 GenerateCompareTest(condition);
1952 cond = X86_64IntegerCondition(condition->GetCondition());
1953 }
1954 } else {
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001955 // Must be a Boolean condition, which needs to be compared to 0.
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001956 CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
1957 __ testl(cond_reg, cond_reg);
1958 }
1959
1960 // If the condition is true, overwrite the output, which already contains false.
1961 // Generate the correct sized CMOV.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001962 bool is_64_bit = DataType::Is64BitType(select->GetType());
Mark Mendelldee1b9a2016-02-12 14:36:51 -05001963 if (value_true_loc.IsRegister()) {
1964 __ cmov(cond, value_false, value_true_loc.AsRegister<CpuRegister>(), is_64_bit);
1965 } else {
1966 __ cmov(cond,
1967 value_false,
1968 Address(CpuRegister(RSP), value_true_loc.GetStackIndex()), is_64_bit);
1969 }
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001970 } else {
1971 NearLabel false_target;
1972 GenerateTestAndBranch<NearLabel>(select,
Andreas Gampe3db70682018-12-26 15:12:03 -08001973 /* condition_input_index= */ 2,
1974 /* true_target= */ nullptr,
Mark Mendell7c0b44f2016-02-01 10:08:35 -05001975 &false_target);
1976 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1977 __ Bind(&false_target);
1978 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001979}
1980
David Srbecky0cf44932015-12-09 14:09:59 +00001981void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001982 new (GetGraph()->GetAllocator()) LocationSummary(info);
David Srbecky0cf44932015-12-09 14:09:59 +00001983}
1984
David Srbeckyd28f4a02016-03-14 17:14:24 +00001985void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo*) {
1986 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001987}
1988
1989void CodeGeneratorX86_64::GenerateNop() {
1990 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001991}
1992
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001993void LocationsBuilderX86_64::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001994 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001995 new (GetGraph()->GetAllocator()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001996 // Handle the long/FP comparisons made in instruction simplification.
1997 switch (cond->InputAt(0)->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001998 case DataType::Type::kInt64:
Mark Mendellc4701932015-04-10 13:18:51 -04001999 locations->SetInAt(0, Location::RequiresRegister());
2000 locations->SetInAt(1, Location::Any());
2001 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002002 case DataType::Type::kFloat32:
2003 case DataType::Type::kFloat64:
Mark Mendellc4701932015-04-10 13:18:51 -04002004 locations->SetInAt(0, Location::RequiresFpuRegister());
2005 locations->SetInAt(1, Location::Any());
2006 break;
2007 default:
2008 locations->SetInAt(0, Location::RequiresRegister());
2009 locations->SetInAt(1, Location::Any());
2010 break;
2011 }
David Brazdilb3e773e2016-01-26 11:28:37 +00002012 if (!cond->IsEmittedAtUseSite()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002013 locations->SetOut(Location::RequiresRegister());
2014 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002015}
2016
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002017void InstructionCodeGeneratorX86_64::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002018 if (cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04002019 return;
Dave Allison20dfc792014-06-16 20:44:29 -07002020 }
Mark Mendellc4701932015-04-10 13:18:51 -04002021
2022 LocationSummary* locations = cond->GetLocations();
2023 Location lhs = locations->InAt(0);
2024 Location rhs = locations->InAt(1);
2025 CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
Mark Mendell152408f2015-12-31 12:28:50 -05002026 NearLabel true_label, false_label;
Mark Mendellc4701932015-04-10 13:18:51 -04002027
2028 switch (cond->InputAt(0)->GetType()) {
2029 default:
2030 // Integer case.
2031
2032 // Clear output register: setcc only sets the low byte.
2033 __ xorl(reg, reg);
2034
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002035 codegen_->GenerateIntCompare(lhs, rhs);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002036 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04002037 return;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002038 case DataType::Type::kInt64:
Mark Mendellc4701932015-04-10 13:18:51 -04002039 // Clear output register: setcc only sets the low byte.
2040 __ xorl(reg, reg);
2041
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002042 codegen_->GenerateLongCompare(lhs, rhs);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002043 __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04002044 return;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002045 case DataType::Type::kFloat32: {
Mark Mendellc4701932015-04-10 13:18:51 -04002046 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
2047 if (rhs.IsConstant()) {
2048 float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
2049 __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
2050 } else if (rhs.IsStackSlot()) {
2051 __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
2052 } else {
2053 __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
2054 }
2055 GenerateFPJumps(cond, &true_label, &false_label);
2056 break;
2057 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002058 case DataType::Type::kFloat64: {
Mark Mendellc4701932015-04-10 13:18:51 -04002059 XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
2060 if (rhs.IsConstant()) {
2061 double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
2062 __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
2063 } else if (rhs.IsDoubleStackSlot()) {
2064 __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
2065 } else {
2066 __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
2067 }
2068 GenerateFPJumps(cond, &true_label, &false_label);
2069 break;
2070 }
2071 }
2072
2073 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002074 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04002075
Roland Levillain4fa13f62015-07-06 18:11:54 +01002076 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04002077 __ Bind(&false_label);
2078 __ xorl(reg, reg);
2079 __ jmp(&done_label);
2080
Roland Levillain4fa13f62015-07-06 18:11:54 +01002081 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04002082 __ Bind(&true_label);
2083 __ movl(reg, Immediate(1));
2084 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07002085}
2086
2087void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002088 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002089}
2090
2091void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002092 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002093}
2094
2095void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002096 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002097}
2098
2099void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002100 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002101}
2102
2103void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002104 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002105}
2106
2107void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002108 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002109}
2110
2111void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002112 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002113}
2114
2115void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002116 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002117}
2118
2119void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002120 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002121}
2122
2123void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002124 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002125}
2126
2127void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002128 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002129}
2130
2131void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002132 HandleCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002133}
2134
Aart Bike9f37602015-10-09 11:15:55 -07002135void LocationsBuilderX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002136 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002137}
2138
2139void InstructionCodeGeneratorX86_64::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002140 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002141}
2142
2143void LocationsBuilderX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002144 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002145}
2146
2147void InstructionCodeGeneratorX86_64::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002148 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002149}
2150
2151void LocationsBuilderX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002152 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002153}
2154
2155void InstructionCodeGeneratorX86_64::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002156 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002157}
2158
2159void LocationsBuilderX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002160 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002161}
2162
2163void InstructionCodeGeneratorX86_64::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002164 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002165}
2166
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002167void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002168 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002169 new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002170 switch (compare->InputAt(0)->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002171 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002172 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002173 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002174 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002175 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002176 case DataType::Type::kInt32:
2177 case DataType::Type::kInt64: {
Calin Juravleddb7df22014-11-25 20:56:51 +00002178 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04002179 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00002180 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2181 break;
2182 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002183 case DataType::Type::kFloat32:
2184 case DataType::Type::kFloat64: {
Calin Juravleddb7df22014-11-25 20:56:51 +00002185 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04002186 locations->SetInAt(1, Location::Any());
Calin Juravleddb7df22014-11-25 20:56:51 +00002187 locations->SetOut(Location::RequiresRegister());
2188 break;
2189 }
2190 default:
2191 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2192 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002193}
2194
2195void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002196 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002197 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002198 Location left = locations->InAt(0);
2199 Location right = locations->InAt(1);
2200
Mark Mendell0c9497d2015-08-21 09:30:05 -04002201 NearLabel less, greater, done;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002202 DataType::Type type = compare->InputAt(0)->GetType();
Aart Bika19616e2016-02-01 18:57:58 -08002203 Condition less_cond = kLess;
2204
Calin Juravleddb7df22014-11-25 20:56:51 +00002205 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002206 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002207 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002208 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002209 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002210 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002211 case DataType::Type::kInt32: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002212 codegen_->GenerateIntCompare(left, right);
Aart Bika19616e2016-02-01 18:57:58 -08002213 break;
2214 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002215 case DataType::Type::kInt64: {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002216 codegen_->GenerateLongCompare(left, right);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002217 break;
Calin Juravleddb7df22014-11-25 20:56:51 +00002218 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002219 case DataType::Type::kFloat32: {
Mark Mendell40741f32015-04-20 22:10:34 -04002220 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2221 if (right.IsConstant()) {
2222 float value = right.GetConstant()->AsFloatConstant()->GetValue();
2223 __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
2224 } else if (right.IsStackSlot()) {
2225 __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2226 } else {
2227 __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
2228 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002229 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002230 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002231 break;
2232 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002233 case DataType::Type::kFloat64: {
Mark Mendell40741f32015-04-20 22:10:34 -04002234 XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
2235 if (right.IsConstant()) {
2236 double value = right.GetConstant()->AsDoubleConstant()->GetValue();
2237 __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
2238 } else if (right.IsDoubleStackSlot()) {
2239 __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
2240 } else {
2241 __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
2242 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002243 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08002244 less_cond = kBelow; // ucomis{s,d} sets CF
Calin Juravleddb7df22014-11-25 20:56:51 +00002245 break;
2246 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002247 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002248 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002249 }
Aart Bika19616e2016-02-01 18:57:58 -08002250
Calin Juravleddb7df22014-11-25 20:56:51 +00002251 __ movl(out, Immediate(0));
Calin Juravle91debbc2014-11-26 19:01:09 +00002252 __ j(kEqual, &done);
Aart Bika19616e2016-02-01 18:57:58 -08002253 __ j(less_cond, &less);
Calin Juravlefd861242014-11-25 20:56:51 +00002254
Calin Juravle91debbc2014-11-26 19:01:09 +00002255 __ Bind(&greater);
Calin Juravleddb7df22014-11-25 20:56:51 +00002256 __ movl(out, Immediate(1));
2257 __ jmp(&done);
2258
2259 __ Bind(&less);
2260 __ movl(out, Immediate(-1));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002261
2262 __ Bind(&done);
2263}
2264
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002265void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002266 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002267 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002268 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002269}
2270
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002271void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002272 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002273}
2274
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002275void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
2276 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002277 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002278 locations->SetOut(Location::ConstantLocation(constant));
2279}
2280
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002281void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002282 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002283}
2284
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002285void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002286 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002287 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002288 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002289}
2290
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002291void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002292 // Will be generated at use site.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002293}
2294
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002295void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
2296 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002297 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002298 locations->SetOut(Location::ConstantLocation(constant));
2299}
2300
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002301void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002302 // Will be generated at use site.
2303}
2304
2305void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
2306 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002307 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002308 locations->SetOut(Location::ConstantLocation(constant));
2309}
2310
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002311void InstructionCodeGeneratorX86_64::VisitDoubleConstant(
2312 HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002313 // Will be generated at use site.
2314}
2315
Igor Murashkind01745e2017-04-05 16:40:31 -07002316void LocationsBuilderX86_64::VisitConstructorFence(HConstructorFence* constructor_fence) {
2317 constructor_fence->SetLocations(nullptr);
2318}
2319
2320void InstructionCodeGeneratorX86_64::VisitConstructorFence(
2321 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
2322 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2323}
2324
Calin Juravle27df7582015-04-17 19:12:31 +01002325void LocationsBuilderX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2326 memory_barrier->SetLocations(nullptr);
2327}
2328
2329void InstructionCodeGeneratorX86_64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00002330 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01002331}
2332
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002333void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
2334 ret->SetLocations(nullptr);
2335}
2336
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002337void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002338 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002339}
2340
2341void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002342 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002343 new (GetGraph()->GetAllocator()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002344 switch (ret->InputAt(0)->GetType()) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002345 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002346 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002347 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002348 case DataType::Type::kInt8:
2349 case DataType::Type::kUint16:
2350 case DataType::Type::kInt16:
2351 case DataType::Type::kInt32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002352 case DataType::Type::kInt64:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002353 locations->SetInAt(0, Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002354 break;
2355
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002356 case DataType::Type::kFloat32:
2357 case DataType::Type::kFloat64:
Mark Mendell40741f32015-04-20 22:10:34 -04002358 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002359 break;
2360
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002361 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002362 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002363 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002364}
2365
2366void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
2367 if (kIsDebugBuild) {
2368 switch (ret->InputAt(0)->GetType()) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002369 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002370 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002371 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002372 case DataType::Type::kInt8:
2373 case DataType::Type::kUint16:
2374 case DataType::Type::kInt16:
2375 case DataType::Type::kInt32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002376 case DataType::Type::kInt64:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002377 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002378 break;
2379
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002380 case DataType::Type::kFloat32:
2381 case DataType::Type::kFloat64:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002382 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002383 XMM0);
2384 break;
2385
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002386 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002387 LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002388 }
2389 }
2390 codegen_->GenerateFrameExit();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002391}
2392
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002393Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(DataType::Type type) const {
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002394 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002395 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002396 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002397 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002398 case DataType::Type::kInt8:
2399 case DataType::Type::kUint16:
2400 case DataType::Type::kInt16:
Aart Bik66c158e2018-01-31 12:55:04 -08002401 case DataType::Type::kUint32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002402 case DataType::Type::kInt32:
Aart Bik66c158e2018-01-31 12:55:04 -08002403 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002404 case DataType::Type::kInt64:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002405 return Location::RegisterLocation(RAX);
2406
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002407 case DataType::Type::kVoid:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002408 return Location::NoLocation();
2409
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002410 case DataType::Type::kFloat64:
2411 case DataType::Type::kFloat32:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002412 return Location::FpuRegisterLocation(XMM0);
2413 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002414
2415 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002416}
2417
2418Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
2419 return Location::RegisterLocation(kMethodRegisterArgument);
2420}
2421
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002422Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(DataType::Type type) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002423 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002424 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002425 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002426 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002427 case DataType::Type::kInt8:
2428 case DataType::Type::kUint16:
2429 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002430 case DataType::Type::kInt32: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002431 uint32_t index = gp_index_++;
2432 stack_index_++;
2433 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002434 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002435 } else {
2436 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2437 }
2438 }
2439
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002440 case DataType::Type::kInt64: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002441 uint32_t index = gp_index_;
2442 stack_index_ += 2;
2443 if (index < calling_convention.GetNumberOfRegisters()) {
2444 gp_index_ += 1;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002445 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002446 } else {
2447 gp_index_ += 2;
2448 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2449 }
2450 }
2451
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002452 case DataType::Type::kFloat32: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002453 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002454 stack_index_++;
2455 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002456 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002457 } else {
2458 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
2459 }
2460 }
2461
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002462 case DataType::Type::kFloat64: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002463 uint32_t index = float_index_++;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002464 stack_index_ += 2;
2465 if (index < calling_convention.GetNumberOfFpuRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002466 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002467 } else {
2468 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
2469 }
2470 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002471
Aart Bik66c158e2018-01-31 12:55:04 -08002472 case DataType::Type::kUint32:
2473 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002474 case DataType::Type::kVoid:
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002475 LOG(FATAL) << "Unexpected parameter type " << type;
Elliott Hughesc1896c92018-11-29 11:33:18 -08002476 UNREACHABLE();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002477 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00002478 return Location::NoLocation();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002479}
2480
Calin Juravle175dc732015-08-25 15:42:32 +01002481void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2482 // The trampoline uses the same calling convention as dex calling conventions,
2483 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2484 // the method_idx.
2485 HandleInvoke(invoke);
2486}
2487
2488void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2489 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2490}
2491
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002492void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002493 // Explicit clinit checks triggered by static invokes must have been pruned by
2494 // art::PrepareForRegisterAllocation.
2495 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002496
Mark Mendellfb8d2792015-03-31 22:16:59 -04002497 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002498 if (intrinsic.TryDispatch(invoke)) {
2499 return;
2500 }
2501
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002502 HandleInvoke(invoke);
2503}
2504
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002505static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
2506 if (invoke->GetLocations()->Intrinsified()) {
2507 IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
2508 intrinsic.Dispatch(invoke);
2509 return true;
2510 }
2511 return false;
2512}
2513
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002514void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002515 // Explicit clinit checks triggered by static invokes must have been pruned by
2516 // art::PrepareForRegisterAllocation.
2517 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002518
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002519 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2520 return;
2521 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002522
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002523 LocationSummary* locations = invoke->GetLocations();
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002524 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray38207af2015-06-01 15:46:22 +01002525 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002526}
2527
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002528void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002529 InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002530 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002531}
2532
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002533void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04002534 IntrinsicLocationsBuilderX86_64 intrinsic(codegen_);
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002535 if (intrinsic.TryDispatch(invoke)) {
2536 return;
2537 }
2538
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002539 HandleInvoke(invoke);
2540}
2541
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002542void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -08002543 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2544 return;
2545 }
2546
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002547 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002548 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01002549}
2550
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002551void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2552 HandleInvoke(invoke);
2553 // Add the hidden argument.
2554 invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
2555}
2556
Nicolas Geoffray20036d82019-11-28 16:15:00 +00002557void CodeGeneratorX86_64::MaybeGenerateInlineCacheCheck(HInstruction* instruction,
2558 CpuRegister klass) {
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002559 DCHECK_EQ(RDI, klass.AsRegister());
Nicolas Geoffray20036d82019-11-28 16:15:00 +00002560 // We know the destination of an intrinsic, so no need to record inline
2561 // caches.
2562 if (!instruction->GetLocations()->Intrinsified() &&
Nicolas Geoffray9b5271e2019-12-04 14:39:46 +00002563 GetGraph()->IsCompilingBaseline() &&
Nicolas Geoffray20036d82019-11-28 16:15:00 +00002564 !Runtime::Current()->IsAotCompiler()) {
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002565 ScopedObjectAccess soa(Thread::Current());
2566 ProfilingInfo* info = GetGraph()->GetArtMethod()->GetProfilingInfo(kRuntimePointerSize);
Nicolas Geoffray20036d82019-11-28 16:15:00 +00002567 InlineCache* cache = info->GetInlineCache(instruction->GetDexPc());
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002568 uint64_t address = reinterpret_cast64<uint64_t>(cache);
2569 NearLabel done;
2570 __ movq(CpuRegister(TMP), Immediate(address));
2571 // Fast path for a monomorphic cache.
2572 __ cmpl(Address(CpuRegister(TMP), InlineCache::ClassesOffset().Int32Value()), klass);
2573 __ j(kEqual, &done);
2574 GenerateInvokeRuntime(
2575 GetThreadOffset<kX86_64PointerSize>(kQuickUpdateInlineCache).Int32Value());
2576 __ Bind(&done);
2577 }
2578}
2579
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002580void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
2581 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002582 LocationSummary* locations = invoke->GetLocations();
2583 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
2584 CpuRegister hidden_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002585 Location receiver = locations->InAt(0);
2586 size_t class_offset = mirror::Object::ClassOffset().SizeValue();
2587
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002588 if (receiver.IsStackSlot()) {
2589 __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002590 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002591 __ movl(temp, Address(temp, class_offset));
2592 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002593 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002594 __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002595 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002596 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002597 // Instead of simply (possibly) unpoisoning `temp` here, we should
2598 // emit a read barrier for the previous class reference load.
2599 // However this is not required in practice, as this is an
2600 // intermediate/temporary reference and because the current
2601 // concurrent copying collector keeps the from-space memory
2602 // intact/accessible until the end of the marking phase (the
2603 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002604 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002605
Nicolas Geoffray20036d82019-11-28 16:15:00 +00002606 codegen_->MaybeGenerateInlineCacheCheck(invoke, temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002607
2608 // Set the hidden argument. This is safe to do this here, as RAX
2609 // won't be modified thereafter, before the `call` instruction.
2610 // We also di it after MaybeGenerateInlineCache that may use RAX.
2611 DCHECK_EQ(RAX, hidden_reg.AsRegister());
2612 codegen_->Load64BitValue(hidden_reg, invoke->GetDexMethodIndex());
2613
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002614 // temp = temp->GetAddressOfIMT()
2615 __ movq(temp,
2616 Address(temp, mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
2617 // temp = temp->GetImtEntryAt(method_offset);
2618 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00002619 invoke->GetImtIndex(), kX86_64PointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002620 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002621 __ movq(temp, Address(temp, method_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002622 // call temp->GetEntryPoint();
Andreas Gampe542451c2016-07-26 09:02:02 -07002623 __ call(Address(
2624 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64PointerSize).SizeValue()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002625
2626 DCHECK(!codegen_->IsLeafMethod());
2627 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2628}
2629
Orion Hodsonac141392017-01-13 11:53:47 +00002630void LocationsBuilderX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2631 HandleInvoke(invoke);
2632}
2633
2634void InstructionCodeGeneratorX86_64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
2635 codegen_->GenerateInvokePolymorphicCall(invoke);
2636}
2637
Orion Hodson4c8e12e2018-05-18 08:33:20 +01002638void LocationsBuilderX86_64::VisitInvokeCustom(HInvokeCustom* invoke) {
2639 HandleInvoke(invoke);
2640}
2641
2642void InstructionCodeGeneratorX86_64::VisitInvokeCustom(HInvokeCustom* invoke) {
2643 codegen_->GenerateInvokeCustomCall(invoke);
2644}
2645
Roland Levillain88cb1752014-10-20 16:36:47 +01002646void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
2647 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002648 new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
Roland Levillain88cb1752014-10-20 16:36:47 +01002649 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002650 case DataType::Type::kInt32:
2651 case DataType::Type::kInt64:
Roland Levillain88cb1752014-10-20 16:36:47 +01002652 locations->SetInAt(0, Location::RequiresRegister());
2653 locations->SetOut(Location::SameAsFirstInput());
2654 break;
2655
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002656 case DataType::Type::kFloat32:
2657 case DataType::Type::kFloat64:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002658 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002659 locations->SetOut(Location::SameAsFirstInput());
Roland Levillain5368c212014-11-27 15:03:41 +00002660 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002661 break;
2662
2663 default:
2664 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2665 }
2666}
2667
2668void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
2669 LocationSummary* locations = neg->GetLocations();
2670 Location out = locations->Out();
2671 Location in = locations->InAt(0);
2672 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002673 case DataType::Type::kInt32:
Roland Levillain88cb1752014-10-20 16:36:47 +01002674 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002675 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002676 __ negl(out.AsRegister<CpuRegister>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002677 break;
2678
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002679 case DataType::Type::kInt64:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002680 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002681 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002682 __ negq(out.AsRegister<CpuRegister>());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002683 break;
2684
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002685 case DataType::Type::kFloat32: {
Roland Levillain5368c212014-11-27 15:03:41 +00002686 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002687 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002688 // Implement float negation with an exclusive or with value
2689 // 0x80000000 (mask for bit 31, representing the sign of a
2690 // single-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002691 __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002692 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002693 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002694 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002695
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002696 case DataType::Type::kFloat64: {
Roland Levillain5368c212014-11-27 15:03:41 +00002697 DCHECK(in.Equals(out));
Mark Mendell40741f32015-04-20 22:10:34 -04002698 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002699 // Implement double negation with an exclusive or with value
Roland Levillain3dbcb382014-10-28 17:30:07 +00002700 // 0x8000000000000000 (mask for bit 63, representing the sign of
Roland Levillain5368c212014-11-27 15:03:41 +00002701 // a double-precision floating-point number).
Mark Mendell40741f32015-04-20 22:10:34 -04002702 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002703 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002704 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002705 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002706
2707 default:
2708 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2709 }
2710}
2711
Roland Levillaindff1f282014-11-05 14:15:05 +00002712void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2713 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002714 new (GetGraph()->GetAllocator()) LocationSummary(conversion, LocationSummary::kNoCall);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002715 DataType::Type result_type = conversion->GetResultType();
2716 DataType::Type input_type = conversion->GetInputType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002717 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
2718 << input_type << " -> " << result_type;
David Brazdil46e2a392015-03-16 17:31:52 +00002719
Roland Levillaindff1f282014-11-05 14:15:05 +00002720 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002721 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002722 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002723 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002724 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002725 DCHECK(DataType::IsIntegralType(input_type)) << input_type;
2726 locations->SetInAt(0, Location::Any());
2727 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain01a8d712014-11-14 16:27:39 +00002728 break;
2729
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002730 case DataType::Type::kInt32:
Roland Levillain946e1432014-11-11 17:35:19 +00002731 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002732 case DataType::Type::kInt64:
Roland Levillain946e1432014-11-11 17:35:19 +00002733 locations->SetInAt(0, Location::Any());
2734 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2735 break;
2736
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002737 case DataType::Type::kFloat32:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002738 locations->SetInAt(0, Location::RequiresFpuRegister());
2739 locations->SetOut(Location::RequiresRegister());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002740 break;
2741
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002742 case DataType::Type::kFloat64:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002743 locations->SetInAt(0, Location::RequiresFpuRegister());
2744 locations->SetOut(Location::RequiresRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002745 break;
2746
2747 default:
2748 LOG(FATAL) << "Unexpected type conversion from " << input_type
2749 << " to " << result_type;
2750 }
2751 break;
2752
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002753 case DataType::Type::kInt64:
Roland Levillaindff1f282014-11-05 14:15:05 +00002754 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002755 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002756 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002757 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002758 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002759 case DataType::Type::kInt16:
2760 case DataType::Type::kInt32:
Roland Levillaindff1f282014-11-05 14:15:05 +00002761 // TODO: We would benefit from a (to-be-implemented)
2762 // Location::RegisterOrStackSlot requirement for this input.
2763 locations->SetInAt(0, Location::RequiresRegister());
2764 locations->SetOut(Location::RequiresRegister());
2765 break;
2766
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002767 case DataType::Type::kFloat32:
Roland Levillain624279f2014-12-04 11:54:28 +00002768 locations->SetInAt(0, Location::RequiresFpuRegister());
2769 locations->SetOut(Location::RequiresRegister());
Roland Levillain624279f2014-12-04 11:54:28 +00002770 break;
2771
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002772 case DataType::Type::kFloat64:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002773 locations->SetInAt(0, Location::RequiresFpuRegister());
2774 locations->SetOut(Location::RequiresRegister());
Roland Levillaindff1f282014-11-05 14:15:05 +00002775 break;
2776
2777 default:
2778 LOG(FATAL) << "Unexpected type conversion from " << input_type
2779 << " to " << result_type;
2780 }
2781 break;
2782
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002783 case DataType::Type::kFloat32:
Roland Levillaincff13742014-11-17 14:32:17 +00002784 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002785 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002786 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002787 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002788 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002789 case DataType::Type::kInt16:
2790 case DataType::Type::kInt32:
Mark Mendell40741f32015-04-20 22:10:34 -04002791 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002792 locations->SetOut(Location::RequiresFpuRegister());
2793 break;
2794
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002795 case DataType::Type::kInt64:
Mark Mendell40741f32015-04-20 22:10:34 -04002796 locations->SetInAt(0, Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002797 locations->SetOut(Location::RequiresFpuRegister());
2798 break;
2799
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002800 case DataType::Type::kFloat64:
Mark Mendell40741f32015-04-20 22:10:34 -04002801 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002802 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002803 break;
2804
2805 default:
2806 LOG(FATAL) << "Unexpected type conversion from " << input_type
2807 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08002808 }
Roland Levillaincff13742014-11-17 14:32:17 +00002809 break;
2810
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002811 case DataType::Type::kFloat64:
Roland Levillaincff13742014-11-17 14:32:17 +00002812 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002813 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002814 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002815 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002816 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002817 case DataType::Type::kInt16:
2818 case DataType::Type::kInt32:
Mark Mendell40741f32015-04-20 22:10:34 -04002819 locations->SetInAt(0, Location::Any());
Roland Levillaincff13742014-11-17 14:32:17 +00002820 locations->SetOut(Location::RequiresFpuRegister());
2821 break;
2822
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002823 case DataType::Type::kInt64:
Mark Mendell40741f32015-04-20 22:10:34 -04002824 locations->SetInAt(0, Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002825 locations->SetOut(Location::RequiresFpuRegister());
2826 break;
2827
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002828 case DataType::Type::kFloat32:
Mark Mendell40741f32015-04-20 22:10:34 -04002829 locations->SetInAt(0, Location::Any());
Roland Levillain8964e2b2014-12-04 12:10:50 +00002830 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002831 break;
2832
2833 default:
2834 LOG(FATAL) << "Unexpected type conversion from " << input_type
2835 << " to " << result_type;
2836 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002837 break;
2838
2839 default:
2840 LOG(FATAL) << "Unexpected type conversion from " << input_type
2841 << " to " << result_type;
2842 }
2843}
2844
2845void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
2846 LocationSummary* locations = conversion->GetLocations();
2847 Location out = locations->Out();
2848 Location in = locations->InAt(0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002849 DataType::Type result_type = conversion->GetResultType();
2850 DataType::Type input_type = conversion->GetInputType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002851 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
2852 << input_type << " -> " << result_type;
Roland Levillaindff1f282014-11-05 14:15:05 +00002853 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002854 case DataType::Type::kUint8:
Roland Levillain51d3fc42014-11-13 14:11:42 +00002855 switch (input_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002856 case DataType::Type::kInt8:
2857 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002858 case DataType::Type::kInt16:
2859 case DataType::Type::kInt32:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002860 case DataType::Type::kInt64:
2861 if (in.IsRegister()) {
2862 __ movzxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
2863 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
2864 __ movzxb(out.AsRegister<CpuRegister>(),
2865 Address(CpuRegister(RSP), in.GetStackIndex()));
2866 } else {
2867 __ movl(out.AsRegister<CpuRegister>(),
2868 Immediate(static_cast<uint8_t>(Int64FromConstant(in.GetConstant()))));
2869 }
2870 break;
2871
2872 default:
2873 LOG(FATAL) << "Unexpected type conversion from " << input_type
2874 << " to " << result_type;
2875 }
2876 break;
2877
2878 case DataType::Type::kInt8:
2879 switch (input_type) {
2880 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002881 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002882 case DataType::Type::kInt16:
2883 case DataType::Type::kInt32:
2884 case DataType::Type::kInt64:
Roland Levillain51d3fc42014-11-13 14:11:42 +00002885 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002886 __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002887 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002888 __ movsxb(out.AsRegister<CpuRegister>(),
Roland Levillain51d3fc42014-11-13 14:11:42 +00002889 Address(CpuRegister(RSP), in.GetStackIndex()));
2890 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002891 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002892 Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain51d3fc42014-11-13 14:11:42 +00002893 }
2894 break;
2895
2896 default:
2897 LOG(FATAL) << "Unexpected type conversion from " << input_type
2898 << " to " << result_type;
2899 }
2900 break;
2901
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002902 case DataType::Type::kUint16:
2903 switch (input_type) {
2904 case DataType::Type::kInt8:
2905 case DataType::Type::kInt16:
2906 case DataType::Type::kInt32:
2907 case DataType::Type::kInt64:
2908 if (in.IsRegister()) {
2909 __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
2910 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
2911 __ movzxw(out.AsRegister<CpuRegister>(),
2912 Address(CpuRegister(RSP), in.GetStackIndex()));
2913 } else {
2914 __ movl(out.AsRegister<CpuRegister>(),
2915 Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
2916 }
2917 break;
2918
2919 default:
2920 LOG(FATAL) << "Unexpected type conversion from " << input_type
2921 << " to " << result_type;
2922 }
2923 break;
2924
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002925 case DataType::Type::kInt16:
Roland Levillain01a8d712014-11-14 16:27:39 +00002926 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002927 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002928 case DataType::Type::kInt32:
2929 case DataType::Type::kInt64:
Roland Levillain01a8d712014-11-14 16:27:39 +00002930 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002931 __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Vladimir Markob52bbde2016-02-12 12:06:05 +00002932 } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002933 __ movsxw(out.AsRegister<CpuRegister>(),
Roland Levillain01a8d712014-11-14 16:27:39 +00002934 Address(CpuRegister(RSP), in.GetStackIndex()));
2935 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002936 __ movl(out.AsRegister<CpuRegister>(),
Vladimir Markob52bbde2016-02-12 12:06:05 +00002937 Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
Roland Levillain01a8d712014-11-14 16:27:39 +00002938 }
2939 break;
2940
2941 default:
2942 LOG(FATAL) << "Unexpected type conversion from " << input_type
2943 << " to " << result_type;
2944 }
2945 break;
2946
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002947 case DataType::Type::kInt32:
Roland Levillain946e1432014-11-11 17:35:19 +00002948 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002949 case DataType::Type::kInt64:
Roland Levillain946e1432014-11-11 17:35:19 +00002950 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002951 __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillain946e1432014-11-11 17:35:19 +00002952 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002953 __ movl(out.AsRegister<CpuRegister>(),
Roland Levillain946e1432014-11-11 17:35:19 +00002954 Address(CpuRegister(RSP), in.GetStackIndex()));
2955 } else {
2956 DCHECK(in.IsConstant());
2957 DCHECK(in.GetConstant()->IsLongConstant());
2958 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002959 __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002960 }
2961 break;
2962
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002963 case DataType::Type::kFloat32: {
Roland Levillain3f8f9362014-12-02 17:45:01 +00002964 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2965 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002966 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002967
2968 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002969 // if input >= (float)INT_MAX goto done
Nick Desaulniers98e97c62019-10-18 14:25:19 -07002970 __ comiss(input, codegen_->LiteralFloatAddress(static_cast<float>(kPrimIntMax)));
Roland Levillain3f8f9362014-12-02 17:45:01 +00002971 __ j(kAboveEqual, &done);
2972 // if input == NaN goto nan
2973 __ j(kUnordered, &nan);
2974 // output = float-to-int-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00002975 __ cvttss2si(output, input, false);
Roland Levillain3f8f9362014-12-02 17:45:01 +00002976 __ jmp(&done);
2977 __ Bind(&nan);
2978 // output = 0
2979 __ xorl(output, output);
2980 __ Bind(&done);
2981 break;
2982 }
2983
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002984 case DataType::Type::kFloat64: {
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002985 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2986 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002987 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002988
2989 __ movl(output, Immediate(kPrimIntMax));
Mark Mendellcfa410b2015-05-25 16:02:44 -04002990 // if input >= (double)INT_MAX goto done
2991 __ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002992 __ j(kAboveEqual, &done);
2993 // if input == NaN goto nan
2994 __ j(kUnordered, &nan);
2995 // output = double-to-int-truncate(input)
2996 __ cvttsd2si(output, input);
2997 __ jmp(&done);
2998 __ Bind(&nan);
2999 // output = 0
3000 __ xorl(output, output);
3001 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00003002 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003003 }
Roland Levillain946e1432014-11-11 17:35:19 +00003004
3005 default:
3006 LOG(FATAL) << "Unexpected type conversion from " << input_type
3007 << " to " << result_type;
3008 }
3009 break;
3010
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003011 case DataType::Type::kInt64:
Roland Levillaindff1f282014-11-05 14:15:05 +00003012 switch (input_type) {
3013 DCHECK(out.IsRegister());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003014 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003015 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003016 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003017 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003018 case DataType::Type::kInt16:
3019 case DataType::Type::kInt32:
Roland Levillaindff1f282014-11-05 14:15:05 +00003020 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003021 __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
Roland Levillaindff1f282014-11-05 14:15:05 +00003022 break;
3023
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003024 case DataType::Type::kFloat32: {
Roland Levillain624279f2014-12-04 11:54:28 +00003025 XmmRegister input = in.AsFpuRegister<XmmRegister>();
3026 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04003027 NearLabel done, nan;
Roland Levillain624279f2014-12-04 11:54:28 +00003028
Mark Mendell92e83bf2015-05-07 11:25:03 -04003029 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04003030 // if input >= (float)LONG_MAX goto done
Nick Desaulniers98e97c62019-10-18 14:25:19 -07003031 __ comiss(input, codegen_->LiteralFloatAddress(static_cast<float>(kPrimLongMax)));
Roland Levillain624279f2014-12-04 11:54:28 +00003032 __ j(kAboveEqual, &done);
3033 // if input == NaN goto nan
3034 __ j(kUnordered, &nan);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003035 // output = float-to-long-truncate(input)
Roland Levillain624279f2014-12-04 11:54:28 +00003036 __ cvttss2si(output, input, true);
3037 __ jmp(&done);
3038 __ Bind(&nan);
3039 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04003040 __ xorl(output, output);
Roland Levillain624279f2014-12-04 11:54:28 +00003041 __ Bind(&done);
3042 break;
3043 }
3044
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003045 case DataType::Type::kFloat64: {
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003046 XmmRegister input = in.AsFpuRegister<XmmRegister>();
3047 CpuRegister output = out.AsRegister<CpuRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04003048 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003049
Mark Mendell92e83bf2015-05-07 11:25:03 -04003050 codegen_->Load64BitValue(output, kPrimLongMax);
Mark Mendellcfa410b2015-05-25 16:02:44 -04003051 // if input >= (double)LONG_MAX goto done
Nick Desaulniers98e97c62019-10-18 14:25:19 -07003052 __ comisd(input, codegen_->LiteralDoubleAddress(
3053 static_cast<double>(kPrimLongMax)));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003054 __ j(kAboveEqual, &done);
3055 // if input == NaN goto nan
3056 __ j(kUnordered, &nan);
3057 // output = double-to-long-truncate(input)
3058 __ cvttsd2si(output, input, true);
3059 __ jmp(&done);
3060 __ Bind(&nan);
3061 // output = 0
Mark Mendell92e83bf2015-05-07 11:25:03 -04003062 __ xorl(output, output);
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003063 __ Bind(&done);
Roland Levillaindff1f282014-11-05 14:15:05 +00003064 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003065 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003066
3067 default:
3068 LOG(FATAL) << "Unexpected type conversion from " << input_type
3069 << " to " << result_type;
3070 }
3071 break;
3072
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003073 case DataType::Type::kFloat32:
Roland Levillaincff13742014-11-17 14:32:17 +00003074 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003075 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003076 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003077 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003078 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003079 case DataType::Type::kInt16:
3080 case DataType::Type::kInt32:
Mark Mendell40741f32015-04-20 22:10:34 -04003081 if (in.IsRegister()) {
3082 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
3083 } else if (in.IsConstant()) {
3084 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
3085 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003086 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003087 } else {
3088 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
3089 Address(CpuRegister(RSP), in.GetStackIndex()), false);
3090 }
Roland Levillaincff13742014-11-17 14:32:17 +00003091 break;
3092
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003093 case DataType::Type::kInt64:
Mark Mendell40741f32015-04-20 22:10:34 -04003094 if (in.IsRegister()) {
3095 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
3096 } else if (in.IsConstant()) {
3097 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
3098 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Pavel Vyssotski4c858cd2016-03-16 13:59:53 +06003099 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003100 } else {
3101 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
3102 Address(CpuRegister(RSP), in.GetStackIndex()), true);
3103 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003104 break;
3105
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003106 case DataType::Type::kFloat64:
Mark Mendell40741f32015-04-20 22:10:34 -04003107 if (in.IsFpuRegister()) {
3108 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3109 } else if (in.IsConstant()) {
3110 double v = in.GetConstant()->AsDoubleConstant()->GetValue();
3111 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003112 codegen_->Load32BitValue(dest, static_cast<float>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003113 } else {
3114 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
3115 Address(CpuRegister(RSP), in.GetStackIndex()));
3116 }
Roland Levillaincff13742014-11-17 14:32:17 +00003117 break;
3118
3119 default:
3120 LOG(FATAL) << "Unexpected type conversion from " << input_type
3121 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08003122 }
Roland Levillaincff13742014-11-17 14:32:17 +00003123 break;
3124
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003125 case DataType::Type::kFloat64:
Roland Levillaincff13742014-11-17 14:32:17 +00003126 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003127 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003128 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003129 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003130 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003131 case DataType::Type::kInt16:
3132 case DataType::Type::kInt32:
Mark Mendell40741f32015-04-20 22:10:34 -04003133 if (in.IsRegister()) {
3134 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
3135 } else if (in.IsConstant()) {
3136 int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
3137 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003138 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003139 } else {
3140 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
3141 Address(CpuRegister(RSP), in.GetStackIndex()), false);
3142 }
Roland Levillaincff13742014-11-17 14:32:17 +00003143 break;
3144
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003145 case DataType::Type::kInt64:
Mark Mendell40741f32015-04-20 22:10:34 -04003146 if (in.IsRegister()) {
3147 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
3148 } else if (in.IsConstant()) {
3149 int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
3150 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003151 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003152 } else {
3153 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
3154 Address(CpuRegister(RSP), in.GetStackIndex()), true);
3155 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00003156 break;
3157
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003158 case DataType::Type::kFloat32:
Mark Mendell40741f32015-04-20 22:10:34 -04003159 if (in.IsFpuRegister()) {
3160 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
3161 } else if (in.IsConstant()) {
3162 float v = in.GetConstant()->AsFloatConstant()->GetValue();
3163 XmmRegister dest = out.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05003164 codegen_->Load64BitValue(dest, static_cast<double>(v));
Mark Mendell40741f32015-04-20 22:10:34 -04003165 } else {
3166 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
3167 Address(CpuRegister(RSP), in.GetStackIndex()));
3168 }
Roland Levillaincff13742014-11-17 14:32:17 +00003169 break;
3170
3171 default:
3172 LOG(FATAL) << "Unexpected type conversion from " << input_type
3173 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08003174 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003175 break;
3176
3177 default:
3178 LOG(FATAL) << "Unexpected type conversion from " << input_type
3179 << " to " << result_type;
3180 }
3181}
3182
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003183void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003184 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003185 new (GetGraph()->GetAllocator()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003186 switch (add->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003187 case DataType::Type::kInt32: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003188 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003189 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3190 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003191 break;
3192 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003193
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003194 case DataType::Type::kInt64: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003195 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell09b84632015-02-13 17:48:38 -05003196 // We can use a leaq or addq if the constant can fit in an immediate.
Mark Mendellea5af682015-10-22 17:35:49 -04003197 locations->SetInAt(1, Location::RegisterOrInt32Constant(add->InputAt(1)));
Mark Mendell09b84632015-02-13 17:48:38 -05003198 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003199 break;
3200 }
3201
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003202 case DataType::Type::kFloat64:
3203 case DataType::Type::kFloat32: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003204 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003205 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003206 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003207 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003208 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003209
3210 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003211 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003212 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003213}
3214
3215void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
3216 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003217 Location first = locations->InAt(0);
3218 Location second = locations->InAt(1);
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003219 Location out = locations->Out();
Calin Juravle11351682014-10-23 15:38:15 +01003220
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003221 switch (add->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003222 case DataType::Type::kInt32: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003223 if (second.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003224 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3225 __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003226 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3227 __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003228 } else {
3229 __ leal(out.AsRegister<CpuRegister>(), Address(
3230 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3231 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003232 } else if (second.IsConstant()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003233 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3234 __ addl(out.AsRegister<CpuRegister>(),
3235 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
3236 } else {
3237 __ leal(out.AsRegister<CpuRegister>(), Address(
3238 first.AsRegister<CpuRegister>(), second.GetConstant()->AsIntConstant()->GetValue()));
3239 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003240 } else {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00003241 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003242 __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003243 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003244 break;
3245 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003246
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003247 case DataType::Type::kInt64: {
Mark Mendell09b84632015-02-13 17:48:38 -05003248 if (second.IsRegister()) {
3249 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3250 __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003251 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3252 __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
Mark Mendell09b84632015-02-13 17:48:38 -05003253 } else {
3254 __ leaq(out.AsRegister<CpuRegister>(), Address(
3255 first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
3256 }
3257 } else {
3258 DCHECK(second.IsConstant());
3259 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3260 int32_t int32_value = Low32Bits(value);
3261 DCHECK_EQ(int32_value, value);
3262 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3263 __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value));
3264 } else {
3265 __ leaq(out.AsRegister<CpuRegister>(), Address(
3266 first.AsRegister<CpuRegister>(), int32_value));
3267 }
3268 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003269 break;
3270 }
3271
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003272 case DataType::Type::kFloat32: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003273 if (second.IsFpuRegister()) {
3274 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3275 } else if (second.IsConstant()) {
3276 __ addss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003277 codegen_->LiteralFloatAddress(
3278 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003279 } else {
3280 DCHECK(second.IsStackSlot());
3281 __ addss(first.AsFpuRegister<XmmRegister>(),
3282 Address(CpuRegister(RSP), second.GetStackIndex()));
3283 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003284 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003285 }
3286
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003287 case DataType::Type::kFloat64: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003288 if (second.IsFpuRegister()) {
3289 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3290 } else if (second.IsConstant()) {
3291 __ addsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003292 codegen_->LiteralDoubleAddress(
3293 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003294 } else {
3295 DCHECK(second.IsDoubleStackSlot());
3296 __ addsd(first.AsFpuRegister<XmmRegister>(),
3297 Address(CpuRegister(RSP), second.GetStackIndex()));
3298 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003299 break;
3300 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003301
3302 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003303 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003304 }
3305}
3306
3307void LocationsBuilderX86_64::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003308 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003309 new (GetGraph()->GetAllocator()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003310 switch (sub->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003311 case DataType::Type::kInt32: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003312 locations->SetInAt(0, Location::RequiresRegister());
3313 locations->SetInAt(1, Location::Any());
3314 locations->SetOut(Location::SameAsFirstInput());
3315 break;
3316 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003317 case DataType::Type::kInt64: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003318 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04003319 locations->SetInAt(1, Location::RegisterOrInt32Constant(sub->InputAt(1)));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003320 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003321 break;
3322 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003323 case DataType::Type::kFloat32:
3324 case DataType::Type::kFloat64: {
Calin Juravle11351682014-10-23 15:38:15 +01003325 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003326 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01003327 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003328 break;
Calin Juravle11351682014-10-23 15:38:15 +01003329 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003330 default:
Calin Juravle11351682014-10-23 15:38:15 +01003331 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003332 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003333}
3334
3335void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
3336 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003337 Location first = locations->InAt(0);
3338 Location second = locations->InAt(1);
3339 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003340 switch (sub->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003341 case DataType::Type::kInt32: {
Calin Juravle11351682014-10-23 15:38:15 +01003342 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003343 __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01003344 } else if (second.IsConstant()) {
3345 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003346 __ subl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003347 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003348 __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003349 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00003350 break;
3351 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003352 case DataType::Type::kInt64: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003353 if (second.IsConstant()) {
3354 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3355 DCHECK(IsInt<32>(value));
3356 __ subq(first.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
3357 } else {
3358 __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
3359 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003360 break;
3361 }
3362
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003363 case DataType::Type::kFloat32: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003364 if (second.IsFpuRegister()) {
3365 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3366 } else if (second.IsConstant()) {
3367 __ subss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003368 codegen_->LiteralFloatAddress(
3369 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003370 } else {
3371 DCHECK(second.IsStackSlot());
3372 __ subss(first.AsFpuRegister<XmmRegister>(),
3373 Address(CpuRegister(RSP), second.GetStackIndex()));
3374 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003375 break;
Calin Juravle11351682014-10-23 15:38:15 +01003376 }
3377
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003378 case DataType::Type::kFloat64: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003379 if (second.IsFpuRegister()) {
3380 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3381 } else if (second.IsConstant()) {
3382 __ subsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003383 codegen_->LiteralDoubleAddress(
3384 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003385 } else {
3386 DCHECK(second.IsDoubleStackSlot());
3387 __ subsd(first.AsFpuRegister<XmmRegister>(),
3388 Address(CpuRegister(RSP), second.GetStackIndex()));
3389 }
Calin Juravle11351682014-10-23 15:38:15 +01003390 break;
3391 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003392
3393 default:
Calin Juravle11351682014-10-23 15:38:15 +01003394 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01003395 }
3396}
3397
Calin Juravle34bacdf2014-10-07 20:23:36 +01003398void LocationsBuilderX86_64::VisitMul(HMul* mul) {
3399 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003400 new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003401 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003402 case DataType::Type::kInt32: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01003403 locations->SetInAt(0, Location::RequiresRegister());
3404 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003405 if (mul->InputAt(1)->IsIntConstant()) {
3406 // Can use 3 operand multiply.
3407 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3408 } else {
3409 locations->SetOut(Location::SameAsFirstInput());
3410 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003411 break;
3412 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003413 case DataType::Type::kInt64: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01003414 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003415 locations->SetInAt(1, Location::Any());
3416 if (mul->InputAt(1)->IsLongConstant() &&
3417 IsInt<32>(mul->InputAt(1)->AsLongConstant()->GetValue())) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003418 // Can use 3 operand multiply.
3419 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3420 } else {
3421 locations->SetOut(Location::SameAsFirstInput());
3422 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003423 break;
3424 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003425 case DataType::Type::kFloat32:
3426 case DataType::Type::kFloat64: {
Calin Juravleb5bfa962014-10-21 18:02:24 +01003427 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003428 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01003429 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003430 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003431 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003432
3433 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003434 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003435 }
3436}
3437
3438void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
3439 LocationSummary* locations = mul->GetLocations();
3440 Location first = locations->InAt(0);
3441 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003442 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003443 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003444 case DataType::Type::kInt32:
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003445 // The constant may have ended up in a register, so test explicitly to avoid
3446 // problems where the output may not be the same as the first operand.
3447 if (mul->InputAt(1)->IsIntConstant()) {
3448 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3449 __ imull(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), imm);
3450 } else if (second.IsRegister()) {
3451 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003452 __ imull(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003453 } else {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003454 DCHECK(first.Equals(out));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003455 DCHECK(second.IsStackSlot());
Roland Levillain199f3362014-11-27 17:15:16 +00003456 __ imull(first.AsRegister<CpuRegister>(),
3457 Address(CpuRegister(RSP), second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003458 }
3459 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003460 case DataType::Type::kInt64: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003461 // The constant may have ended up in a register, so test explicitly to avoid
3462 // problems where the output may not be the same as the first operand.
3463 if (mul->InputAt(1)->IsLongConstant()) {
3464 int64_t value = mul->InputAt(1)->AsLongConstant()->GetValue();
3465 if (IsInt<32>(value)) {
3466 __ imulq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(),
3467 Immediate(static_cast<int32_t>(value)));
3468 } else {
3469 // Have to use the constant area.
3470 DCHECK(first.Equals(out));
3471 __ imulq(first.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
3472 }
3473 } else if (second.IsRegister()) {
3474 DCHECK(first.Equals(out));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003475 __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003476 } else {
3477 DCHECK(second.IsDoubleStackSlot());
3478 DCHECK(first.Equals(out));
3479 __ imulq(first.AsRegister<CpuRegister>(),
3480 Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003481 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003482 break;
3483 }
3484
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003485 case DataType::Type::kFloat32: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003486 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003487 if (second.IsFpuRegister()) {
3488 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3489 } else if (second.IsConstant()) {
3490 __ mulss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003491 codegen_->LiteralFloatAddress(
3492 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003493 } else {
3494 DCHECK(second.IsStackSlot());
3495 __ mulss(first.AsFpuRegister<XmmRegister>(),
3496 Address(CpuRegister(RSP), second.GetStackIndex()));
3497 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003498 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003499 }
3500
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003501 case DataType::Type::kFloat64: {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003502 DCHECK(first.Equals(out));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003503 if (second.IsFpuRegister()) {
3504 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3505 } else if (second.IsConstant()) {
3506 __ mulsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003507 codegen_->LiteralDoubleAddress(
3508 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003509 } else {
3510 DCHECK(second.IsDoubleStackSlot());
3511 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3512 Address(CpuRegister(RSP), second.GetStackIndex()));
3513 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003514 break;
3515 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003516
3517 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003518 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003519 }
3520}
3521
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003522void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
3523 uint32_t stack_adjustment, bool is_float) {
3524 if (source.IsStackSlot()) {
3525 DCHECK(is_float);
3526 __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3527 } else if (source.IsDoubleStackSlot()) {
3528 DCHECK(!is_float);
3529 __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
3530 } else {
3531 // Write the value to the temporary location on the stack and load to FP stack.
3532 if (is_float) {
3533 Location stack_temp = Location::StackSlot(temp_offset);
3534 codegen_->Move(stack_temp, source);
3535 __ flds(Address(CpuRegister(RSP), temp_offset));
3536 } else {
3537 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3538 codegen_->Move(stack_temp, source);
3539 __ fldl(Address(CpuRegister(RSP), temp_offset));
3540 }
3541 }
3542}
3543
3544void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003545 DataType::Type type = rem->GetResultType();
3546 bool is_float = type == DataType::Type::kFloat32;
3547 size_t elem_size = DataType::Size(type);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003548 LocationSummary* locations = rem->GetLocations();
3549 Location first = locations->InAt(0);
3550 Location second = locations->InAt(1);
3551 Location out = locations->Out();
3552
3553 // Create stack space for 2 elements.
3554 // TODO: enhance register allocator to ask for stack temporaries.
3555 __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
3556
3557 // Load the values to the FP stack in reverse order, using temporaries if needed.
3558 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
3559 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
3560
3561 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003562 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003563 __ Bind(&retry);
3564 __ fprem();
3565
3566 // Move FP status to AX.
3567 __ fstsw();
3568
3569 // And see if the argument reduction is complete. This is signaled by the
3570 // C2 FPU flag bit set to 0.
3571 __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
3572 __ j(kNotEqual, &retry);
3573
3574 // We have settled on the final value. Retrieve it into an XMM register.
3575 // Store FP top of stack to real stack.
3576 if (is_float) {
3577 __ fsts(Address(CpuRegister(RSP), 0));
3578 } else {
3579 __ fstl(Address(CpuRegister(RSP), 0));
3580 }
3581
3582 // Pop the 2 items from the FP stack.
3583 __ fucompp();
3584
3585 // Load the value from the stack into an XMM register.
3586 DCHECK(out.IsFpuRegister()) << out;
3587 if (is_float) {
3588 __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3589 } else {
3590 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
3591 }
3592
3593 // And remove the temporary stack space we allocated.
3594 __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
3595}
3596
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003597void InstructionCodeGeneratorX86_64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3598 DCHECK(instruction->IsDiv() || instruction->IsRem());
3599
3600 LocationSummary* locations = instruction->GetLocations();
3601 Location second = locations->InAt(1);
3602 DCHECK(second.IsConstant());
3603
3604 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3605 CpuRegister input_register = locations->InAt(0).AsRegister<CpuRegister>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003606 int64_t imm = Int64FromConstant(second.GetConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003607
3608 DCHECK(imm == 1 || imm == -1);
3609
3610 switch (instruction->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003611 case DataType::Type::kInt32: {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003612 if (instruction->IsRem()) {
3613 __ xorl(output_register, output_register);
3614 } else {
3615 __ movl(output_register, input_register);
3616 if (imm == -1) {
3617 __ negl(output_register);
3618 }
3619 }
3620 break;
3621 }
3622
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003623 case DataType::Type::kInt64: {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003624 if (instruction->IsRem()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003625 __ xorl(output_register, output_register);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003626 } else {
3627 __ movq(output_register, input_register);
3628 if (imm == -1) {
3629 __ negq(output_register);
3630 }
3631 }
3632 break;
3633 }
3634
3635 default:
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003636 LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003637 }
3638}
Shalini Salomi Bodapatia66784b2018-11-06 13:05:44 +05303639void InstructionCodeGeneratorX86_64::RemByPowerOfTwo(HRem* instruction) {
3640 LocationSummary* locations = instruction->GetLocations();
3641 Location second = locations->InAt(1);
3642 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3643 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3644 int64_t imm = Int64FromConstant(second.GetConstant());
3645 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3646 uint64_t abs_imm = AbsOrMin(imm);
3647 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3648 if (instruction->GetResultType() == DataType::Type::kInt32) {
3649 NearLabel done;
3650 __ movl(out, numerator);
3651 __ andl(out, Immediate(abs_imm-1));
3652 __ j(Condition::kZero, &done);
3653 __ leal(tmp, Address(out, static_cast<int32_t>(~(abs_imm-1))));
3654 __ testl(numerator, numerator);
3655 __ cmov(Condition::kLess, out, tmp, false);
3656 __ Bind(&done);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003657
Shalini Salomi Bodapatia66784b2018-11-06 13:05:44 +05303658 } else {
3659 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
3660 codegen_->Load64BitValue(tmp, abs_imm - 1);
3661 NearLabel done;
3662
3663 __ movq(out, numerator);
3664 __ andq(out, tmp);
3665 __ j(Condition::kZero, &done);
3666 __ movq(tmp, numerator);
3667 __ sarq(tmp, Immediate(63));
3668 __ shlq(tmp, Immediate(WhichPowerOf2(abs_imm)));
3669 __ orq(out, tmp);
3670 __ Bind(&done);
3671 }
3672}
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003673void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003674 LocationSummary* locations = instruction->GetLocations();
3675 Location second = locations->InAt(1);
3676
3677 CpuRegister output_register = locations->Out().AsRegister<CpuRegister>();
3678 CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
3679
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003680 int64_t imm = Int64FromConstant(second.GetConstant());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003681 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3682 uint64_t abs_imm = AbsOrMin(imm);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003683
3684 CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
3685
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003686 if (instruction->GetResultType() == DataType::Type::kInt32) {
Atul Bajaj1cc73292018-11-15 11:36:53 +05303687 // When denominator is equal to 2, we can add signed bit and numerator to tmp.
3688 // Below we are using addl instruction instead of cmov which give us 1 cycle benefit.
3689 if (abs_imm == 2) {
3690 __ leal(tmp, Address(numerator, 0));
3691 __ shrl(tmp, Immediate(31));
3692 __ addl(tmp, numerator);
3693 } else {
3694 __ leal(tmp, Address(numerator, abs_imm - 1));
3695 __ testl(numerator, numerator);
3696 __ cmov(kGreaterEqual, tmp, numerator);
3697 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003698 int shift = CTZ(imm);
3699 __ sarl(tmp, Immediate(shift));
3700
3701 if (imm < 0) {
3702 __ negl(tmp);
3703 }
3704
3705 __ movl(output_register, tmp);
3706 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003707 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003708 CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>();
Atul Bajaj1cc73292018-11-15 11:36:53 +05303709 if (abs_imm == 2) {
3710 __ movq(rdx, numerator);
3711 __ shrq(rdx, Immediate(63));
3712 __ addq(rdx, numerator);
3713 } else {
3714 codegen_->Load64BitValue(rdx, abs_imm - 1);
3715 __ addq(rdx, numerator);
3716 __ testq(numerator, numerator);
3717 __ cmov(kGreaterEqual, rdx, numerator);
3718 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003719 int shift = CTZ(imm);
3720 __ sarq(rdx, Immediate(shift));
3721
3722 if (imm < 0) {
3723 __ negq(rdx);
3724 }
3725
3726 __ movq(output_register, rdx);
3727 }
3728}
3729
3730void InstructionCodeGeneratorX86_64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3731 DCHECK(instruction->IsDiv() || instruction->IsRem());
3732
3733 LocationSummary* locations = instruction->GetLocations();
3734 Location second = locations->InAt(1);
3735
3736 CpuRegister numerator = instruction->IsDiv() ? locations->GetTemp(1).AsRegister<CpuRegister>()
3737 : locations->GetTemp(0).AsRegister<CpuRegister>();
3738 CpuRegister eax = locations->InAt(0).AsRegister<CpuRegister>();
3739 CpuRegister edx = instruction->IsDiv() ? locations->GetTemp(0).AsRegister<CpuRegister>()
3740 : locations->Out().AsRegister<CpuRegister>();
3741 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3742
3743 DCHECK_EQ(RAX, eax.AsRegister());
3744 DCHECK_EQ(RDX, edx.AsRegister());
3745 if (instruction->IsDiv()) {
3746 DCHECK_EQ(RAX, out.AsRegister());
3747 } else {
3748 DCHECK_EQ(RDX, out.AsRegister());
3749 }
3750
3751 int64_t magic;
3752 int shift;
3753
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003754 // TODO: can these branches be written as one?
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003755 if (instruction->GetResultType() == DataType::Type::kInt32) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003756 int imm = second.GetConstant()->AsIntConstant()->GetValue();
3757
Andreas Gampe3db70682018-12-26 15:12:03 -08003758 CalculateMagicAndShiftForDivRem(imm, false /* is_long= */, &magic, &shift);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003759
3760 __ movl(numerator, eax);
3761
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003762 __ movl(eax, Immediate(magic));
3763 __ imull(numerator);
3764
3765 if (imm > 0 && magic < 0) {
3766 __ addl(edx, numerator);
3767 } else if (imm < 0 && magic > 0) {
3768 __ subl(edx, numerator);
3769 }
3770
3771 if (shift != 0) {
3772 __ sarl(edx, Immediate(shift));
3773 }
3774
3775 __ movl(eax, edx);
3776 __ shrl(edx, Immediate(31));
3777 __ addl(edx, eax);
3778
3779 if (instruction->IsRem()) {
3780 __ movl(eax, numerator);
3781 __ imull(edx, Immediate(imm));
3782 __ subl(eax, edx);
3783 __ movl(edx, eax);
3784 } else {
3785 __ movl(eax, edx);
3786 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003787 } else {
3788 int64_t imm = second.GetConstant()->AsLongConstant()->GetValue();
3789
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003790 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003791
3792 CpuRegister rax = eax;
3793 CpuRegister rdx = edx;
3794
Andreas Gampe3db70682018-12-26 15:12:03 -08003795 CalculateMagicAndShiftForDivRem(imm, true /* is_long= */, &magic, &shift);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003796
3797 // Save the numerator.
3798 __ movq(numerator, rax);
3799
3800 // RAX = magic
Mark Mendell92e83bf2015-05-07 11:25:03 -04003801 codegen_->Load64BitValue(rax, magic);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003802
3803 // RDX:RAX = magic * numerator
3804 __ imulq(numerator);
3805
3806 if (imm > 0 && magic < 0) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003807 // RDX += numerator
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003808 __ addq(rdx, numerator);
3809 } else if (imm < 0 && magic > 0) {
3810 // RDX -= numerator
3811 __ subq(rdx, numerator);
3812 }
3813
3814 // Shift if needed.
3815 if (shift != 0) {
3816 __ sarq(rdx, Immediate(shift));
3817 }
3818
3819 // RDX += 1 if RDX < 0
3820 __ movq(rax, rdx);
3821 __ shrq(rdx, Immediate(63));
3822 __ addq(rdx, rax);
3823
3824 if (instruction->IsRem()) {
3825 __ movq(rax, numerator);
3826
3827 if (IsInt<32>(imm)) {
3828 __ imulq(rdx, Immediate(static_cast<int32_t>(imm)));
3829 } else {
Mark Mendell92e83bf2015-05-07 11:25:03 -04003830 __ imulq(rdx, codegen_->LiteralInt64Address(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003831 }
3832
3833 __ subq(rax, rdx);
3834 __ movq(rdx, rax);
3835 } else {
3836 __ movq(rax, rdx);
3837 }
3838 }
3839}
3840
Calin Juravlebacfec32014-11-14 15:54:36 +00003841void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3842 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003843 DataType::Type type = instruction->GetResultType();
3844 DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
Calin Juravlebacfec32014-11-14 15:54:36 +00003845
3846 bool is_div = instruction->IsDiv();
3847 LocationSummary* locations = instruction->GetLocations();
3848
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003849 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
3850 Location second = locations->InAt(1);
Calin Juravlebacfec32014-11-14 15:54:36 +00003851
Roland Levillain271ab9c2014-11-27 15:23:57 +00003852 DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003853 DCHECK_EQ(is_div ? RAX : RDX, out.AsRegister());
Calin Juravlebacfec32014-11-14 15:54:36 +00003854
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003855 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003856 int64_t imm = Int64FromConstant(second.GetConstant());
Calin Juravlebacfec32014-11-14 15:54:36 +00003857
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003858 if (imm == 0) {
3859 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3860 } else if (imm == 1 || imm == -1) {
3861 DivRemOneOrMinusOne(instruction);
Shalini Salomi Bodapatia66784b2018-11-06 13:05:44 +05303862 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
3863 if (is_div) {
3864 DivByPowerOfTwo(instruction->AsDiv());
3865 } else {
3866 RemByPowerOfTwo(instruction->AsRem());
3867 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003868 } else {
3869 DCHECK(imm <= -2 || imm >= 2);
3870 GenerateDivRemWithAnyConstant(instruction);
3871 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003872 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003873 SlowPathCode* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01003874 new (codegen_->GetScopedAllocator()) DivRemMinusOneSlowPathX86_64(
David Srbecky9cd6d372016-02-09 15:24:47 +00003875 instruction, out.AsRegister(), type, is_div);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003876 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003877
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003878 CpuRegister second_reg = second.AsRegister<CpuRegister>();
3879 // 0x80000000(00000000)/-1 triggers an arithmetic exception!
3880 // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
3881 // so it's safe to just use negl instead of more complex comparisons.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003882 if (type == DataType::Type::kInt32) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003883 __ cmpl(second_reg, Immediate(-1));
3884 __ j(kEqual, slow_path->GetEntryLabel());
3885 // edx:eax <- sign-extended of eax
3886 __ cdq();
3887 // eax = quotient, edx = remainder
3888 __ idivl(second_reg);
3889 } else {
3890 __ cmpq(second_reg, Immediate(-1));
3891 __ j(kEqual, slow_path->GetEntryLabel());
3892 // rdx:rax <- sign-extended of rax
3893 __ cqo();
3894 // rax = quotient, rdx = remainder
3895 __ idivq(second_reg);
3896 }
3897 __ Bind(slow_path->GetExitLabel());
3898 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003899}
3900
Calin Juravle7c4954d2014-10-28 16:57:40 +00003901void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
3902 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003903 new (GetGraph()->GetAllocator()) LocationSummary(div, LocationSummary::kNoCall);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003904 switch (div->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003905 case DataType::Type::kInt32:
3906 case DataType::Type::kInt64: {
Calin Juravled0d48522014-11-04 16:40:20 +00003907 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003908 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003909 locations->SetOut(Location::SameAsFirstInput());
3910 // Intel uses edx:eax as the dividend.
3911 locations->AddTemp(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003912 // We need to save the numerator while we tweak rax and rdx. As we are using imul in a way
3913 // which enforces results to be in RAX and RDX, things are simpler if we use RDX also as
3914 // output and request another temp.
3915 if (div->InputAt(1)->IsConstant()) {
3916 locations->AddTemp(Location::RequiresRegister());
3917 }
Calin Juravled0d48522014-11-04 16:40:20 +00003918 break;
3919 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003920
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003921 case DataType::Type::kFloat32:
3922 case DataType::Type::kFloat64: {
Calin Juravle7c4954d2014-10-28 16:57:40 +00003923 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendellf55c3e02015-03-26 21:07:46 -04003924 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003925 locations->SetOut(Location::SameAsFirstInput());
3926 break;
3927 }
3928
3929 default:
3930 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3931 }
3932}
3933
3934void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
3935 LocationSummary* locations = div->GetLocations();
3936 Location first = locations->InAt(0);
3937 Location second = locations->InAt(1);
3938 DCHECK(first.Equals(locations->Out()));
3939
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003940 DataType::Type type = div->GetResultType();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003941 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003942 case DataType::Type::kInt32:
3943 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003944 GenerateDivRemIntegral(div);
Calin Juravled0d48522014-11-04 16:40:20 +00003945 break;
3946 }
3947
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003948 case DataType::Type::kFloat32: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003949 if (second.IsFpuRegister()) {
3950 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3951 } else if (second.IsConstant()) {
3952 __ divss(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003953 codegen_->LiteralFloatAddress(
3954 second.GetConstant()->AsFloatConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003955 } else {
3956 DCHECK(second.IsStackSlot());
3957 __ divss(first.AsFpuRegister<XmmRegister>(),
3958 Address(CpuRegister(RSP), second.GetStackIndex()));
3959 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003960 break;
3961 }
3962
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003963 case DataType::Type::kFloat64: {
Mark Mendellf55c3e02015-03-26 21:07:46 -04003964 if (second.IsFpuRegister()) {
3965 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3966 } else if (second.IsConstant()) {
3967 __ divsd(first.AsFpuRegister<XmmRegister>(),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00003968 codegen_->LiteralDoubleAddress(
3969 second.GetConstant()->AsDoubleConstant()->GetValue()));
Mark Mendellf55c3e02015-03-26 21:07:46 -04003970 } else {
3971 DCHECK(second.IsDoubleStackSlot());
3972 __ divsd(first.AsFpuRegister<XmmRegister>(),
3973 Address(CpuRegister(RSP), second.GetStackIndex()));
3974 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003975 break;
3976 }
3977
3978 default:
3979 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3980 }
3981}
3982
Calin Juravlebacfec32014-11-14 15:54:36 +00003983void LocationsBuilderX86_64::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003984 DataType::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003985 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003986 new (GetGraph()->GetAllocator()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravled2ec87d2014-12-08 14:24:46 +00003987
3988 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003989 case DataType::Type::kInt32:
3990 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003991 locations->SetInAt(0, Location::RegisterLocation(RAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003992 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003993 // Intel uses rdx:rax as the dividend and puts the remainder in rdx
3994 locations->SetOut(Location::RegisterLocation(RDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003995 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3996 // which enforces results to be in RAX and RDX, things are simpler if we use EAX also as
3997 // output and request another temp.
3998 if (rem->InputAt(1)->IsConstant()) {
3999 locations->AddTemp(Location::RequiresRegister());
4000 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004001 break;
4002 }
4003
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004004 case DataType::Type::kFloat32:
4005 case DataType::Type::kFloat64: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05004006 locations->SetInAt(0, Location::Any());
4007 locations->SetInAt(1, Location::Any());
4008 locations->SetOut(Location::RequiresFpuRegister());
4009 locations->AddTemp(Location::RegisterLocation(RAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00004010 break;
4011 }
4012
4013 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004014 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004015 }
4016}
4017
4018void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004019 DataType::Type type = rem->GetResultType();
Calin Juravlebacfec32014-11-14 15:54:36 +00004020 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004021 case DataType::Type::kInt32:
4022 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004023 GenerateDivRemIntegral(rem);
4024 break;
4025 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004026 case DataType::Type::kFloat32:
4027 case DataType::Type::kFloat64: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05004028 GenerateRemFP(rem);
Calin Juravled2ec87d2014-12-08 14:24:46 +00004029 break;
4030 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004031 default:
4032 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
4033 }
4034}
4035
Aart Bik1f8d51b2018-02-15 10:42:37 -08004036static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) {
4037 LocationSummary* locations = new (allocator) LocationSummary(minmax);
4038 switch (minmax->GetResultType()) {
4039 case DataType::Type::kInt32:
4040 case DataType::Type::kInt64:
4041 locations->SetInAt(0, Location::RequiresRegister());
4042 locations->SetInAt(1, Location::RequiresRegister());
4043 locations->SetOut(Location::SameAsFirstInput());
4044 break;
4045 case DataType::Type::kFloat32:
4046 case DataType::Type::kFloat64:
4047 locations->SetInAt(0, Location::RequiresFpuRegister());
4048 locations->SetInAt(1, Location::RequiresFpuRegister());
4049 // The following is sub-optimal, but all we can do for now. It would be fine to also accept
4050 // the second input to be the output (we can simply swap inputs).
4051 locations->SetOut(Location::SameAsFirstInput());
4052 break;
4053 default:
4054 LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType();
4055 }
4056}
4057
Aart Bik351df3e2018-03-07 11:54:57 -08004058void InstructionCodeGeneratorX86_64::GenerateMinMaxInt(LocationSummary* locations,
4059 bool is_min,
4060 DataType::Type type) {
Aart Bik1f8d51b2018-02-15 10:42:37 -08004061 Location op1_loc = locations->InAt(0);
4062 Location op2_loc = locations->InAt(1);
4063
4064 // Shortcut for same input locations.
4065 if (op1_loc.Equals(op2_loc)) {
4066 // Can return immediately, as op1_loc == out_loc.
4067 // Note: if we ever support separate registers, e.g., output into memory, we need to check for
4068 // a copy here.
4069 DCHECK(locations->Out().Equals(op1_loc));
4070 return;
4071 }
4072
4073 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4074 CpuRegister op2 = op2_loc.AsRegister<CpuRegister>();
4075
4076 // (out := op1)
4077 // out <=? op2
4078 // if out is min jmp done
4079 // out := op2
4080 // done:
4081
4082 if (type == DataType::Type::kInt64) {
4083 __ cmpq(out, op2);
4084 __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, /*is64bit*/ true);
4085 } else {
4086 DCHECK_EQ(type, DataType::Type::kInt32);
4087 __ cmpl(out, op2);
4088 __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, /*is64bit*/ false);
4089 }
4090}
4091
4092void InstructionCodeGeneratorX86_64::GenerateMinMaxFP(LocationSummary* locations,
4093 bool is_min,
4094 DataType::Type type) {
4095 Location op1_loc = locations->InAt(0);
4096 Location op2_loc = locations->InAt(1);
4097 Location out_loc = locations->Out();
4098 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
4099
4100 // Shortcut for same input locations.
4101 if (op1_loc.Equals(op2_loc)) {
4102 DCHECK(out_loc.Equals(op1_loc));
4103 return;
4104 }
4105
4106 // (out := op1)
4107 // out <=? op2
4108 // if Nan jmp Nan_label
4109 // if out is min jmp done
4110 // if op2 is min jmp op2_label
4111 // handle -0/+0
4112 // jmp done
4113 // Nan_label:
4114 // out := NaN
4115 // op2_label:
4116 // out := op2
4117 // done:
4118 //
4119 // This removes one jmp, but needs to copy one input (op1) to out.
4120 //
4121 // TODO: This is straight from Quick. Make NaN an out-of-line slowpath?
4122
4123 XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
4124
4125 NearLabel nan, done, op2_label;
4126 if (type == DataType::Type::kFloat64) {
4127 __ ucomisd(out, op2);
4128 } else {
4129 DCHECK_EQ(type, DataType::Type::kFloat32);
4130 __ ucomiss(out, op2);
4131 }
4132
4133 __ j(Condition::kParityEven, &nan);
4134
4135 __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
4136 __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
4137
4138 // Handle 0.0/-0.0.
4139 if (is_min) {
4140 if (type == DataType::Type::kFloat64) {
4141 __ orpd(out, op2);
4142 } else {
4143 __ orps(out, op2);
4144 }
4145 } else {
4146 if (type == DataType::Type::kFloat64) {
4147 __ andpd(out, op2);
4148 } else {
4149 __ andps(out, op2);
4150 }
4151 }
4152 __ jmp(&done);
4153
4154 // NaN handling.
4155 __ Bind(&nan);
4156 if (type == DataType::Type::kFloat64) {
4157 __ movsd(out, codegen_->LiteralInt64Address(INT64_C(0x7FF8000000000000)));
4158 } else {
4159 __ movss(out, codegen_->LiteralInt32Address(INT32_C(0x7FC00000)));
4160 }
4161 __ jmp(&done);
4162
4163 // out := op2;
4164 __ Bind(&op2_label);
4165 if (type == DataType::Type::kFloat64) {
4166 __ movsd(out, op2);
4167 } else {
4168 __ movss(out, op2);
4169 }
4170
4171 // Done.
4172 __ Bind(&done);
4173}
4174
Aart Bik351df3e2018-03-07 11:54:57 -08004175void InstructionCodeGeneratorX86_64::GenerateMinMax(HBinaryOperation* minmax, bool is_min) {
4176 DataType::Type type = minmax->GetResultType();
4177 switch (type) {
4178 case DataType::Type::kInt32:
4179 case DataType::Type::kInt64:
4180 GenerateMinMaxInt(minmax->GetLocations(), is_min, type);
4181 break;
4182 case DataType::Type::kFloat32:
4183 case DataType::Type::kFloat64:
4184 GenerateMinMaxFP(minmax->GetLocations(), is_min, type);
4185 break;
4186 default:
4187 LOG(FATAL) << "Unexpected type for HMinMax " << type;
4188 }
4189}
4190
Aart Bik1f8d51b2018-02-15 10:42:37 -08004191void LocationsBuilderX86_64::VisitMin(HMin* min) {
4192 CreateMinMaxLocations(GetGraph()->GetAllocator(), min);
4193}
4194
4195void InstructionCodeGeneratorX86_64::VisitMin(HMin* min) {
Aart Bik351df3e2018-03-07 11:54:57 -08004196 GenerateMinMax(min, /*is_min*/ true);
Aart Bik1f8d51b2018-02-15 10:42:37 -08004197}
4198
4199void LocationsBuilderX86_64::VisitMax(HMax* max) {
4200 CreateMinMaxLocations(GetGraph()->GetAllocator(), max);
4201}
4202
4203void InstructionCodeGeneratorX86_64::VisitMax(HMax* max) {
Aart Bik351df3e2018-03-07 11:54:57 -08004204 GenerateMinMax(max, /*is_min*/ false);
Aart Bik1f8d51b2018-02-15 10:42:37 -08004205}
4206
Aart Bik3dad3412018-02-28 12:01:46 -08004207void LocationsBuilderX86_64::VisitAbs(HAbs* abs) {
4208 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs);
4209 switch (abs->GetResultType()) {
4210 case DataType::Type::kInt32:
4211 case DataType::Type::kInt64:
4212 locations->SetInAt(0, Location::RequiresRegister());
4213 locations->SetOut(Location::SameAsFirstInput());
4214 locations->AddTemp(Location::RequiresRegister());
4215 break;
4216 case DataType::Type::kFloat32:
4217 case DataType::Type::kFloat64:
4218 locations->SetInAt(0, Location::RequiresFpuRegister());
4219 locations->SetOut(Location::SameAsFirstInput());
4220 locations->AddTemp(Location::RequiresFpuRegister());
4221 break;
4222 default:
4223 LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4224 }
4225}
4226
4227void InstructionCodeGeneratorX86_64::VisitAbs(HAbs* abs) {
4228 LocationSummary* locations = abs->GetLocations();
4229 switch (abs->GetResultType()) {
4230 case DataType::Type::kInt32: {
4231 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4232 CpuRegister mask = locations->GetTemp(0).AsRegister<CpuRegister>();
4233 // Create mask.
4234 __ movl(mask, out);
4235 __ sarl(mask, Immediate(31));
4236 // Add mask.
4237 __ addl(out, mask);
4238 __ xorl(out, mask);
4239 break;
4240 }
4241 case DataType::Type::kInt64: {
4242 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
4243 CpuRegister mask = locations->GetTemp(0).AsRegister<CpuRegister>();
4244 // Create mask.
4245 __ movq(mask, out);
4246 __ sarq(mask, Immediate(63));
4247 // Add mask.
4248 __ addq(out, mask);
4249 __ xorq(out, mask);
4250 break;
4251 }
4252 case DataType::Type::kFloat32: {
4253 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4254 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4255 __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x7FFFFFFF)));
4256 __ andps(out, mask);
4257 break;
4258 }
4259 case DataType::Type::kFloat64: {
4260 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4261 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4262 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x7FFFFFFFFFFFFFFF)));
4263 __ andpd(out, mask);
4264 break;
4265 }
4266 default:
4267 LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4268 }
4269}
4270
Calin Juravled0d48522014-11-04 16:40:20 +00004271void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004272 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004273 locations->SetInAt(0, Location::Any());
Calin Juravled0d48522014-11-04 16:40:20 +00004274}
4275
4276void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004277 SlowPathCode* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01004278 new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathX86_64(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004279 codegen_->AddSlowPath(slow_path);
4280
4281 LocationSummary* locations = instruction->GetLocations();
4282 Location value = locations->InAt(0);
4283
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004284 switch (instruction->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004285 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004286 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004287 case DataType::Type::kInt8:
4288 case DataType::Type::kUint16:
4289 case DataType::Type::kInt16:
4290 case DataType::Type::kInt32: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004291 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004292 __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004293 __ j(kEqual, slow_path->GetEntryLabel());
4294 } else if (value.IsStackSlot()) {
4295 __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
4296 __ j(kEqual, slow_path->GetEntryLabel());
4297 } else {
4298 DCHECK(value.IsConstant()) << value;
4299 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004300 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004301 }
4302 }
4303 break;
Calin Juravled0d48522014-11-04 16:40:20 +00004304 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004305 case DataType::Type::kInt64: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004306 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004307 __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004308 __ j(kEqual, slow_path->GetEntryLabel());
4309 } else if (value.IsDoubleStackSlot()) {
4310 __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
4311 __ j(kEqual, slow_path->GetEntryLabel());
4312 } else {
4313 DCHECK(value.IsConstant()) << value;
4314 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004315 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004316 }
4317 }
4318 break;
4319 }
4320 default:
4321 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00004322 }
Calin Juravled0d48522014-11-04 16:40:20 +00004323}
4324
Calin Juravle9aec02f2014-11-18 23:06:35 +00004325void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
4326 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4327
4328 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004329 new (GetGraph()->GetAllocator()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004330
4331 switch (op->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004332 case DataType::Type::kInt32:
4333 case DataType::Type::kInt64: {
Calin Juravle9aec02f2014-11-18 23:06:35 +00004334 locations->SetInAt(0, Location::RequiresRegister());
4335 // The shift count needs to be in CL.
4336 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
4337 locations->SetOut(Location::SameAsFirstInput());
4338 break;
4339 }
4340 default:
4341 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
4342 }
4343}
4344
4345void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
4346 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4347
4348 LocationSummary* locations = op->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004349 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004350 Location second = locations->InAt(1);
4351
4352 switch (op->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004353 case DataType::Type::kInt32: {
Calin Juravle9aec02f2014-11-18 23:06:35 +00004354 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004355 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004356 if (op->IsShl()) {
4357 __ shll(first_reg, second_reg);
4358 } else if (op->IsShr()) {
4359 __ sarl(first_reg, second_reg);
4360 } else {
4361 __ shrl(first_reg, second_reg);
4362 }
4363 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004364 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004365 if (op->IsShl()) {
4366 __ shll(first_reg, imm);
4367 } else if (op->IsShr()) {
4368 __ sarl(first_reg, imm);
4369 } else {
4370 __ shrl(first_reg, imm);
4371 }
4372 }
4373 break;
4374 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004375 case DataType::Type::kInt64: {
Calin Juravle9aec02f2014-11-18 23:06:35 +00004376 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004377 CpuRegister second_reg = second.AsRegister<CpuRegister>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004378 if (op->IsShl()) {
4379 __ shlq(first_reg, second_reg);
4380 } else if (op->IsShr()) {
4381 __ sarq(first_reg, second_reg);
4382 } else {
4383 __ shrq(first_reg, second_reg);
4384 }
4385 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004386 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004387 if (op->IsShl()) {
4388 __ shlq(first_reg, imm);
4389 } else if (op->IsShr()) {
4390 __ sarq(first_reg, imm);
4391 } else {
4392 __ shrq(first_reg, imm);
4393 }
4394 }
4395 break;
4396 }
4397 default:
4398 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
Vladimir Marko351dddf2015-12-11 16:34:46 +00004399 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004400 }
4401}
4402
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004403void LocationsBuilderX86_64::VisitRor(HRor* ror) {
4404 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004405 new (GetGraph()->GetAllocator()) LocationSummary(ror, LocationSummary::kNoCall);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004406
4407 switch (ror->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004408 case DataType::Type::kInt32:
4409 case DataType::Type::kInt64: {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004410 locations->SetInAt(0, Location::RequiresRegister());
4411 // The shift count needs to be in CL (unless it is a constant).
4412 locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, ror->InputAt(1)));
4413 locations->SetOut(Location::SameAsFirstInput());
4414 break;
4415 }
4416 default:
4417 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4418 UNREACHABLE();
4419 }
4420}
4421
4422void InstructionCodeGeneratorX86_64::VisitRor(HRor* ror) {
4423 LocationSummary* locations = ror->GetLocations();
4424 CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
4425 Location second = locations->InAt(1);
4426
4427 switch (ror->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004428 case DataType::Type::kInt32:
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004429 if (second.IsRegister()) {
4430 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4431 __ rorl(first_reg, second_reg);
4432 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004433 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004434 __ rorl(first_reg, imm);
4435 }
4436 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004437 case DataType::Type::kInt64:
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004438 if (second.IsRegister()) {
4439 CpuRegister second_reg = second.AsRegister<CpuRegister>();
4440 __ rorq(first_reg, second_reg);
4441 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004442 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004443 __ rorq(first_reg, imm);
4444 }
4445 break;
4446 default:
4447 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4448 UNREACHABLE();
4449 }
4450}
4451
Calin Juravle9aec02f2014-11-18 23:06:35 +00004452void LocationsBuilderX86_64::VisitShl(HShl* shl) {
4453 HandleShift(shl);
4454}
4455
4456void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
4457 HandleShift(shl);
4458}
4459
4460void LocationsBuilderX86_64::VisitShr(HShr* shr) {
4461 HandleShift(shr);
4462}
4463
4464void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
4465 HandleShift(shr);
4466}
4467
4468void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
4469 HandleShift(ushr);
4470}
4471
4472void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
4473 HandleShift(ushr);
4474}
4475
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004476void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01004477 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
4478 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004479 InvokeRuntimeCallingConvention calling_convention;
Alex Lightd109e302018-06-27 10:25:41 -07004480 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004481 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004482}
4483
4484void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
Alex Lightd109e302018-06-27 10:25:41 -07004485 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
4486 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
4487 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004488}
4489
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004490void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01004491 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
4492 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004493 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004494 locations->SetOut(Location::RegisterLocation(RAX));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004495 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4496 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004497}
4498
4499void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
Vladimir Markob5461632018-10-15 14:24:21 +01004500 // Note: if heap poisoning is enabled, the entry point takes care of poisoning the reference.
4501 QuickEntrypointEnum entrypoint = CodeGenerator::GetArrayAllocationEntrypoint(instruction);
Nicolas Geoffrayb048cb72017-01-23 22:50:24 +00004502 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004503 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004504 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004505}
4506
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004507void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004508 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004509 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004510 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4511 if (location.IsStackSlot()) {
4512 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4513 } else if (location.IsDoubleStackSlot()) {
4514 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4515 }
4516 locations->SetOut(location);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004517}
4518
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004519void InstructionCodeGeneratorX86_64::VisitParameterValue(
4520 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004521 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004522}
4523
4524void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
4525 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004526 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004527 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4528}
4529
4530void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
4531 HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4532 // Nothing to do, the method is already at its location.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004533}
4534
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004535void LocationsBuilderX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4536 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004537 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004538 locations->SetInAt(0, Location::RequiresRegister());
4539 locations->SetOut(Location::RequiresRegister());
4540}
4541
4542void InstructionCodeGeneratorX86_64::VisitClassTableGet(HClassTableGet* instruction) {
4543 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00004544 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004545 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004546 instruction->GetIndex(), kX86_64PointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004547 __ movq(locations->Out().AsRegister<CpuRegister>(),
4548 Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004549 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004550 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00004551 instruction->GetIndex(), kX86_64PointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00004552 __ movq(locations->Out().AsRegister<CpuRegister>(),
4553 Address(locations->InAt(0).AsRegister<CpuRegister>(),
4554 mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01004555 __ movq(locations->Out().AsRegister<CpuRegister>(),
4556 Address(locations->Out().AsRegister<CpuRegister>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004557 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00004558}
4559
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004560void LocationsBuilderX86_64::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004561 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004562 new (GetGraph()->GetAllocator()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00004563 locations->SetInAt(0, Location::RequiresRegister());
4564 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004565}
4566
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004567void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
4568 LocationSummary* locations = not_->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004569 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4570 locations->Out().AsRegister<CpuRegister>().AsRegister());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004571 Location out = locations->Out();
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004572 switch (not_->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004573 case DataType::Type::kInt32:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004574 __ notl(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004575 break;
4576
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004577 case DataType::Type::kInt64:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004578 __ notq(out.AsRegister<CpuRegister>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004579 break;
4580
4581 default:
4582 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4583 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004584}
4585
David Brazdil66d126e2015-04-03 16:02:44 +01004586void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
4587 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004588 new (GetGraph()->GetAllocator()) LocationSummary(bool_not, LocationSummary::kNoCall);
David Brazdil66d126e2015-04-03 16:02:44 +01004589 locations->SetInAt(0, Location::RequiresRegister());
4590 locations->SetOut(Location::SameAsFirstInput());
4591}
4592
4593void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004594 LocationSummary* locations = bool_not->GetLocations();
4595 DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
4596 locations->Out().AsRegister<CpuRegister>().AsRegister());
4597 Location out = locations->Out();
4598 __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
4599}
4600
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004601void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004602 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004603 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01004604 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004605 locations->SetInAt(i, Location::Any());
4606 }
4607 locations->SetOut(Location::Any());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004608}
4609
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004610void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01004611 LOG(FATAL) << "Unimplemented";
4612}
4613
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004614void CodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
Calin Juravle52c48962014-12-16 17:02:57 +00004615 /*
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004616 * According to the JSR-133 Cookbook, for x86-64 only StoreLoad/AnyAny barriers need memory fence.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004617 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86-64 memory model.
Calin Juravle52c48962014-12-16 17:02:57 +00004618 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
4619 */
4620 switch (kind) {
4621 case MemBarrierKind::kAnyAny: {
Mark P Mendell17077d82015-12-16 19:15:59 +00004622 MemoryFence();
Calin Juravle52c48962014-12-16 17:02:57 +00004623 break;
4624 }
4625 case MemBarrierKind::kAnyStore:
4626 case MemBarrierKind::kLoadAny:
4627 case MemBarrierKind::kStoreStore: {
4628 // nop
4629 break;
4630 }
Mark Mendell7aa04a12016-01-27 22:39:07 -05004631 case MemBarrierKind::kNTStoreStore:
4632 // Non-Temporal Store/Store needs an explicit fence.
Andreas Gampe3db70682018-12-26 15:12:03 -08004633 MemoryFence(/* non-temporal= */ true);
Mark Mendell7aa04a12016-01-27 22:39:07 -05004634 break;
Calin Juravle52c48962014-12-16 17:02:57 +00004635 }
4636}
4637
4638void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
4639 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4640
Roland Levillain0d5a2812015-11-13 10:07:31 +00004641 bool object_field_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004642 kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004643 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004644 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
4645 object_field_get_with_read_barrier
4646 ? LocationSummary::kCallOnSlowPath
4647 : LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01004648 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004649 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01004650 }
Calin Juravle52c48962014-12-16 17:02:57 +00004651 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004652 if (DataType::IsFloatingPointType(instruction->GetType())) {
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004653 locations->SetOut(Location::RequiresFpuRegister());
4654 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00004655 // The output overlaps for an object field get when read barriers
4656 // are enabled: we do not want the move to overwrite the object's
4657 // location, as we need it to emit the read barrier.
4658 locations->SetOut(
4659 Location::RequiresRegister(),
4660 object_field_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004661 }
Calin Juravle52c48962014-12-16 17:02:57 +00004662}
4663
4664void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
4665 const FieldInfo& field_info) {
4666 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4667
4668 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00004669 Location base_loc = locations->InAt(0);
4670 CpuRegister base = base_loc.AsRegister<CpuRegister>();
Calin Juravle52c48962014-12-16 17:02:57 +00004671 Location out = locations->Out();
4672 bool is_volatile = field_info.IsVolatile();
Vladimir Marko61b92282017-10-11 13:23:17 +01004673 DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
4674 DataType::Type load_type = instruction->GetType();
Calin Juravle52c48962014-12-16 17:02:57 +00004675 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4676
Vladimir Marko61b92282017-10-11 13:23:17 +01004677 switch (load_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004678 case DataType::Type::kBool:
4679 case DataType::Type::kUint8: {
Calin Juravle52c48962014-12-16 17:02:57 +00004680 __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4681 break;
4682 }
4683
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004684 case DataType::Type::kInt8: {
Calin Juravle52c48962014-12-16 17:02:57 +00004685 __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
4686 break;
4687 }
4688
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004689 case DataType::Type::kUint16: {
4690 __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
Calin Juravle52c48962014-12-16 17:02:57 +00004691 break;
4692 }
4693
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004694 case DataType::Type::kInt16: {
4695 __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
Calin Juravle52c48962014-12-16 17:02:57 +00004696 break;
4697 }
4698
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004699 case DataType::Type::kInt32: {
Calin Juravle52c48962014-12-16 17:02:57 +00004700 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4701 break;
4702 }
4703
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004704 case DataType::Type::kReference: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004705 // /* HeapReference<Object> */ out = *(base + offset)
4706 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004707 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01004708 // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004709 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08004710 instruction, out, base, offset, /* needs_null_check= */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004711 if (is_volatile) {
4712 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4713 }
4714 } else {
4715 __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
4716 codegen_->MaybeRecordImplicitNullCheck(instruction);
4717 if (is_volatile) {
4718 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4719 }
4720 // If read barriers are enabled, emit read barriers other than
4721 // Baker's using a slow path (and also unpoison the loaded
4722 // reference, if heap poisoning is enabled).
4723 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4724 }
4725 break;
4726 }
4727
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004728 case DataType::Type::kInt64: {
Calin Juravle52c48962014-12-16 17:02:57 +00004729 __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
4730 break;
4731 }
4732
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004733 case DataType::Type::kFloat32: {
Calin Juravle52c48962014-12-16 17:02:57 +00004734 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4735 break;
4736 }
4737
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004738 case DataType::Type::kFloat64: {
Calin Juravle52c48962014-12-16 17:02:57 +00004739 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
4740 break;
4741 }
4742
Aart Bik66c158e2018-01-31 12:55:04 -08004743 case DataType::Type::kUint32:
4744 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004745 case DataType::Type::kVoid:
Vladimir Marko61b92282017-10-11 13:23:17 +01004746 LOG(FATAL) << "Unreachable type " << load_type;
Calin Juravle52c48962014-12-16 17:02:57 +00004747 UNREACHABLE();
4748 }
4749
Vladimir Marko61b92282017-10-11 13:23:17 +01004750 if (load_type == DataType::Type::kReference) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004751 // Potential implicit null checks, in the case of reference
4752 // fields, are handled in the previous switch statement.
4753 } else {
4754 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004755 }
Roland Levillain4d027112015-07-01 15:41:14 +01004756
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004757 if (is_volatile) {
Vladimir Marko61b92282017-10-11 13:23:17 +01004758 if (load_type == DataType::Type::kReference) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004759 // Memory barriers, in the case of references, are also handled
4760 // in the previous switch statement.
4761 } else {
4762 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4763 }
Roland Levillain4d027112015-07-01 15:41:14 +01004764 }
Calin Juravle52c48962014-12-16 17:02:57 +00004765}
4766
4767void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
4768 const FieldInfo& field_info) {
4769 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4770
4771 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004772 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004773 DataType::Type field_type = field_info.GetFieldType();
Mark Mendellea5af682015-10-22 17:35:49 -04004774 bool is_volatile = field_info.IsVolatile();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004775 bool needs_write_barrier =
Roland Levillain4d027112015-07-01 15:41:14 +01004776 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004777
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004778 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004779 if (DataType::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
Mark Mendellea5af682015-10-22 17:35:49 -04004780 if (is_volatile) {
4781 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4782 locations->SetInAt(1, Location::FpuRegisterOrInt32Constant(instruction->InputAt(1)));
4783 } else {
4784 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
4785 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004786 } else {
Mark Mendellea5af682015-10-22 17:35:49 -04004787 if (is_volatile) {
4788 // In order to satisfy the semantics of volatile, this must be a single instruction store.
4789 locations->SetInAt(1, Location::RegisterOrInt32Constant(instruction->InputAt(1)));
4790 } else {
4791 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4792 }
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004793 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004794 if (needs_write_barrier) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004795 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01004796 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004797 locations->AddTemp(Location::RequiresRegister());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004798 } else if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
Roland Levillain4d027112015-07-01 15:41:14 +01004799 // Temporary register for the reference poisoning.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01004800 locations->AddTemp(Location::RequiresRegister());
4801 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004802}
4803
Calin Juravle52c48962014-12-16 17:02:57 +00004804void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004805 const FieldInfo& field_info,
4806 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004807 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4808
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004809 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00004810 CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
4811 Location value = locations->InAt(1);
4812 bool is_volatile = field_info.IsVolatile();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004813 DataType::Type field_type = field_info.GetFieldType();
Calin Juravle52c48962014-12-16 17:02:57 +00004814 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4815
4816 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004817 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00004818 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004819
Mark Mendellea5af682015-10-22 17:35:49 -04004820 bool maybe_record_implicit_null_check_done = false;
4821
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004822 switch (field_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004823 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004824 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004825 case DataType::Type::kInt8: {
Mark Mendell40741f32015-04-20 22:10:34 -04004826 if (value.IsConstant()) {
Nicolas Geoffray78612082017-07-24 14:18:53 +01004827 __ movb(Address(base, offset),
4828 Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
Mark Mendell40741f32015-04-20 22:10:34 -04004829 } else {
4830 __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
4831 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004832 break;
4833 }
4834
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004835 case DataType::Type::kUint16:
4836 case DataType::Type::kInt16: {
Mark Mendell40741f32015-04-20 22:10:34 -04004837 if (value.IsConstant()) {
Nicolas Geoffray78612082017-07-24 14:18:53 +01004838 __ movw(Address(base, offset),
4839 Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Mark Mendell40741f32015-04-20 22:10:34 -04004840 } else {
4841 __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
4842 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004843 break;
4844 }
4845
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004846 case DataType::Type::kInt32:
4847 case DataType::Type::kReference: {
Mark Mendell40741f32015-04-20 22:10:34 -04004848 if (value.IsConstant()) {
4849 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004850 // `field_type == DataType::Type::kReference` implies `v == 0`.
4851 DCHECK((field_type != DataType::Type::kReference) || (v == 0));
Roland Levillain4d027112015-07-01 15:41:14 +01004852 // Note: if heap poisoning is enabled, no need to poison
4853 // (negate) `v` if it is a reference, as it would be null.
Roland Levillain06b66d02015-07-01 12:47:25 +01004854 __ movl(Address(base, offset), Immediate(v));
Mark Mendell40741f32015-04-20 22:10:34 -04004855 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004856 if (kPoisonHeapReferences && field_type == DataType::Type::kReference) {
Roland Levillain4d027112015-07-01 15:41:14 +01004857 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4858 __ movl(temp, value.AsRegister<CpuRegister>());
4859 __ PoisonHeapReference(temp);
4860 __ movl(Address(base, offset), temp);
4861 } else {
4862 __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
4863 }
Mark Mendell40741f32015-04-20 22:10:34 -04004864 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004865 break;
4866 }
4867
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004868 case DataType::Type::kInt64: {
Mark Mendell40741f32015-04-20 22:10:34 -04004869 if (value.IsConstant()) {
4870 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellea5af682015-10-22 17:35:49 -04004871 codegen_->MoveInt64ToAddress(Address(base, offset),
4872 Address(base, offset + sizeof(int32_t)),
4873 v,
4874 instruction);
4875 maybe_record_implicit_null_check_done = true;
Mark Mendell40741f32015-04-20 22:10:34 -04004876 } else {
4877 __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
4878 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004879 break;
4880 }
4881
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004882 case DataType::Type::kFloat32: {
Mark Mendellea5af682015-10-22 17:35:49 -04004883 if (value.IsConstant()) {
4884 int32_t v =
4885 bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
4886 __ movl(Address(base, offset), Immediate(v));
4887 } else {
4888 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4889 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004890 break;
4891 }
4892
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004893 case DataType::Type::kFloat64: {
Mark Mendellea5af682015-10-22 17:35:49 -04004894 if (value.IsConstant()) {
4895 int64_t v =
4896 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
4897 codegen_->MoveInt64ToAddress(Address(base, offset),
4898 Address(base, offset + sizeof(int32_t)),
4899 v,
4900 instruction);
4901 maybe_record_implicit_null_check_done = true;
4902 } else {
4903 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4904 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004905 break;
4906 }
4907
Aart Bik66c158e2018-01-31 12:55:04 -08004908 case DataType::Type::kUint32:
4909 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004910 case DataType::Type::kVoid:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004911 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004912 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004913 }
Calin Juravle52c48962014-12-16 17:02:57 +00004914
Mark Mendellea5af682015-10-22 17:35:49 -04004915 if (!maybe_record_implicit_null_check_done) {
4916 codegen_->MaybeRecordImplicitNullCheck(instruction);
4917 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004918
4919 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4920 CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
4921 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004922 codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004923 }
4924
Calin Juravle52c48962014-12-16 17:02:57 +00004925 if (is_volatile) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00004926 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00004927 }
4928}
4929
4930void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4931 HandleFieldSet(instruction, instruction->GetFieldInfo());
4932}
4933
4934void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004935 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004936}
4937
4938void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004939 HandleFieldGet(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004940}
4941
4942void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00004943 HandleFieldGet(instruction, instruction->GetFieldInfo());
4944}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004945
Calin Juravle52c48962014-12-16 17:02:57 +00004946void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4947 HandleFieldGet(instruction);
4948}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004949
Calin Juravle52c48962014-12-16 17:02:57 +00004950void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4951 HandleFieldGet(instruction, instruction->GetFieldInfo());
4952}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004953
Calin Juravle52c48962014-12-16 17:02:57 +00004954void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4955 HandleFieldSet(instruction, instruction->GetFieldInfo());
4956}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004957
Calin Juravle52c48962014-12-16 17:02:57 +00004958void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004959 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004960}
4961
Vladimir Marko552a1342017-10-31 10:56:47 +00004962void LocationsBuilderX86_64::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
4963 codegen_->CreateStringBuilderAppendLocations(instruction, Location::RegisterLocation(RAX));
4964}
4965
4966void InstructionCodeGeneratorX86_64::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
4967 __ movl(CpuRegister(RDI), Immediate(instruction->GetFormat()->GetValue()));
4968 codegen_->InvokeRuntime(kQuickStringBuilderAppend, instruction, instruction->GetDexPc());
4969}
4970
Calin Juravlee460d1d2015-09-29 04:52:17 +01004971void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldGet(
4972 HUnresolvedInstanceFieldGet* instruction) {
4973 FieldAccessCallingConventionX86_64 calling_convention;
4974 codegen_->CreateUnresolvedFieldLocationSummary(
4975 instruction, instruction->GetFieldType(), calling_convention);
4976}
4977
4978void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldGet(
4979 HUnresolvedInstanceFieldGet* instruction) {
4980 FieldAccessCallingConventionX86_64 calling_convention;
4981 codegen_->GenerateUnresolvedFieldAccess(instruction,
4982 instruction->GetFieldType(),
4983 instruction->GetFieldIndex(),
4984 instruction->GetDexPc(),
4985 calling_convention);
4986}
4987
4988void LocationsBuilderX86_64::VisitUnresolvedInstanceFieldSet(
4989 HUnresolvedInstanceFieldSet* instruction) {
4990 FieldAccessCallingConventionX86_64 calling_convention;
4991 codegen_->CreateUnresolvedFieldLocationSummary(
4992 instruction, instruction->GetFieldType(), calling_convention);
4993}
4994
4995void InstructionCodeGeneratorX86_64::VisitUnresolvedInstanceFieldSet(
4996 HUnresolvedInstanceFieldSet* instruction) {
4997 FieldAccessCallingConventionX86_64 calling_convention;
4998 codegen_->GenerateUnresolvedFieldAccess(instruction,
4999 instruction->GetFieldType(),
5000 instruction->GetFieldIndex(),
5001 instruction->GetDexPc(),
5002 calling_convention);
5003}
5004
5005void LocationsBuilderX86_64::VisitUnresolvedStaticFieldGet(
5006 HUnresolvedStaticFieldGet* instruction) {
5007 FieldAccessCallingConventionX86_64 calling_convention;
5008 codegen_->CreateUnresolvedFieldLocationSummary(
5009 instruction, instruction->GetFieldType(), calling_convention);
5010}
5011
5012void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldGet(
5013 HUnresolvedStaticFieldGet* instruction) {
5014 FieldAccessCallingConventionX86_64 calling_convention;
5015 codegen_->GenerateUnresolvedFieldAccess(instruction,
5016 instruction->GetFieldType(),
5017 instruction->GetFieldIndex(),
5018 instruction->GetDexPc(),
5019 calling_convention);
5020}
5021
5022void LocationsBuilderX86_64::VisitUnresolvedStaticFieldSet(
5023 HUnresolvedStaticFieldSet* instruction) {
5024 FieldAccessCallingConventionX86_64 calling_convention;
5025 codegen_->CreateUnresolvedFieldLocationSummary(
5026 instruction, instruction->GetFieldType(), calling_convention);
5027}
5028
5029void InstructionCodeGeneratorX86_64::VisitUnresolvedStaticFieldSet(
5030 HUnresolvedStaticFieldSet* instruction) {
5031 FieldAccessCallingConventionX86_64 calling_convention;
5032 codegen_->GenerateUnresolvedFieldAccess(instruction,
5033 instruction->GetFieldType(),
5034 instruction->GetFieldIndex(),
5035 instruction->GetDexPc(),
5036 calling_convention);
5037}
5038
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005039void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005040 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5041 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
5042 ? Location::RequiresRegister()
5043 : Location::Any();
5044 locations->SetInAt(0, loc);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005045}
5046
Calin Juravle2ae48182016-03-16 14:05:09 +00005047void CodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
5048 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005049 return;
5050 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005051 LocationSummary* locations = instruction->GetLocations();
5052 Location obj = locations->InAt(0);
5053
5054 __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
Calin Juravle2ae48182016-03-16 14:05:09 +00005055 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005056}
5057
Calin Juravle2ae48182016-03-16 14:05:09 +00005058void CodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01005059 SlowPathCode* slow_path = new (GetScopedAllocator()) NullCheckSlowPathX86_64(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00005060 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005061
5062 LocationSummary* locations = instruction->GetLocations();
5063 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005064
5065 if (obj.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005066 __ testl(obj.AsRegister<CpuRegister>(), obj.AsRegister<CpuRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01005067 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005068 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01005069 } else {
5070 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00005071 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01005072 __ jmp(slow_path->GetEntryLabel());
5073 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005074 }
5075 __ j(kEqual, slow_path->GetEntryLabel());
5076}
5077
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005078void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00005079 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005080}
5081
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005082void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005083 bool object_array_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005084 kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005085 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005086 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
5087 object_array_get_with_read_barrier
5088 ? LocationSummary::kCallOnSlowPath
5089 : LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005090 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005091 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005092 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005093 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04005094 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005095 if (DataType::IsFloatingPointType(instruction->GetType())) {
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005096 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5097 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005098 // The output overlaps for an object array get when read barriers
5099 // are enabled: we do not want the move to overwrite the array's
5100 // location, as we need it to emit the read barrier.
5101 locations->SetOut(
5102 Location::RequiresRegister(),
5103 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005104 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005105}
5106
5107void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
5108 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005109 Location obj_loc = locations->InAt(0);
5110 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005111 Location index = locations->InAt(1);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005112 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01005113 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005114
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005115 DataType::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01005116 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005117 case DataType::Type::kBool:
5118 case DataType::Type::kUint8: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005119 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005120 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005121 break;
5122 }
5123
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005124 case DataType::Type::kInt8: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005125 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005126 __ movsxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005127 break;
5128 }
5129
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005130 case DataType::Type::kUint16: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005131 CpuRegister out = out_loc.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07005132 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
5133 // Branch cases into compressed and uncompressed for each index's type.
5134 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
5135 NearLabel done, not_compressed;
Vladimir Marko3c89d422017-02-17 11:30:23 +00005136 __ testb(Address(obj, count_offset), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005137 codegen_->MaybeRecordImplicitNullCheck(instruction);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005138 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5139 "Expecting 0=compressed, 1=uncompressed");
5140 __ j(kNotZero, &not_compressed);
jessicahandojo4877b792016-09-08 19:49:13 -07005141 __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
5142 __ jmp(&done);
5143 __ Bind(&not_compressed);
5144 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
5145 __ Bind(&done);
5146 } else {
5147 __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
5148 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005149 break;
5150 }
5151
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005152 case DataType::Type::kInt16: {
5153 CpuRegister out = out_loc.AsRegister<CpuRegister>();
5154 __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
5155 break;
5156 }
5157
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005158 case DataType::Type::kInt32: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005159 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005160 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005161 break;
5162 }
5163
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005164 case DataType::Type::kReference: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005165 static_assert(
5166 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
5167 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005168 // /* HeapReference<Object> */ out =
5169 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
5170 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005171 // Note that a potential implicit null check is handled in this
Roland Levillaina1aa3b12016-10-26 13:03:38 +01005172 // CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier call.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005173 codegen_->GenerateArrayLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08005174 instruction, out_loc, obj, data_offset, index, /* needs_null_check= */ true);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005175 } else {
5176 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005177 __ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
5178 codegen_->MaybeRecordImplicitNullCheck(instruction);
5179 // If read barriers are enabled, emit read barriers other than
5180 // Baker's using a slow path (and also unpoison the loaded
5181 // reference, if heap poisoning is enabled).
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005182 if (index.IsConstant()) {
5183 uint32_t offset =
5184 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005185 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5186 } else {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005187 codegen_->MaybeGenerateReadBarrierSlow(
5188 instruction, out_loc, out_loc, obj_loc, data_offset, index);
5189 }
5190 }
5191 break;
5192 }
5193
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005194 case DataType::Type::kInt64: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005195 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005196 __ movq(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005197 break;
5198 }
5199
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005200 case DataType::Type::kFloat32: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005201 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005202 __ movss(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005203 break;
5204 }
5205
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005206 case DataType::Type::kFloat64: {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005207 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005208 __ movsd(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_8, data_offset));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005209 break;
5210 }
5211
Aart Bik66c158e2018-01-31 12:55:04 -08005212 case DataType::Type::kUint32:
5213 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005214 case DataType::Type::kVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01005215 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005216 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005217 }
Roland Levillain4d027112015-07-01 15:41:14 +01005218
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005219 if (type == DataType::Type::kReference) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005220 // Potential implicit null checks, in the case of reference
5221 // arrays, are handled in the previous switch statement.
5222 } else {
5223 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01005224 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005225}
5226
5227void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005228 DataType::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005229
5230 bool needs_write_barrier =
5231 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005232 bool needs_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005233
Vladimir Markoca6fff82017-10-03 14:49:14 +01005234 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005235 instruction,
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005236 needs_type_check ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005237
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005238 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellea5af682015-10-22 17:35:49 -04005239 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005240 if (DataType::IsFloatingPointType(value_type)) {
Mark Mendellea5af682015-10-22 17:35:49 -04005241 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005242 } else {
5243 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
5244 }
5245
5246 if (needs_write_barrier) {
5247 // Temporary registers for the write barrier.
Roland Levillain16d9f942016-08-25 17:27:56 +01005248 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005249 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005250 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005251}
5252
5253void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
5254 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005255 Location array_loc = locations->InAt(0);
5256 CpuRegister array = array_loc.AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005257 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01005258 Location value = locations->InAt(2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005259 DataType::Type value_type = instruction->GetComponentType();
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005260 bool needs_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005261 bool needs_write_barrier =
5262 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005263
5264 switch (value_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005265 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005266 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005267 case DataType::Type::kInt8: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005268 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005269 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_1, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005270 if (value.IsRegister()) {
5271 __ movb(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005272 } else {
Nicolas Geoffray78612082017-07-24 14:18:53 +01005273 __ movb(address, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005274 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005275 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005276 break;
5277 }
5278
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005279 case DataType::Type::kUint16:
5280 case DataType::Type::kInt16: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005281 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005282 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_2, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005283 if (value.IsRegister()) {
5284 __ movw(address, value.AsRegister<CpuRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005285 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005286 DCHECK(value.IsConstant()) << value;
Nicolas Geoffray78612082017-07-24 14:18:53 +01005287 __ movw(address, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005288 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005289 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005290 break;
5291 }
5292
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005293 case DataType::Type::kReference: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005294 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005295 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005296
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005297 if (!value.IsRegister()) {
5298 // Just setting null.
5299 DCHECK(instruction->InputAt(2)->IsNullConstant());
5300 DCHECK(value.IsConstant()) << value;
5301 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00005302 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005303 DCHECK(!needs_write_barrier);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005304 DCHECK(!needs_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005305 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005306 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005307
5308 DCHECK(needs_write_barrier);
5309 CpuRegister register_value = value.AsRegister<CpuRegister>();
Roland Levillain16d9f942016-08-25 17:27:56 +01005310 Location temp_loc = locations->GetTemp(0);
5311 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005312
5313 bool can_value_be_null = instruction->GetValueCanBeNull();
5314 NearLabel do_store;
5315 if (can_value_be_null) {
5316 __ testl(register_value, register_value);
5317 __ j(kEqual, &do_store);
5318 }
5319
5320 SlowPathCode* slow_path = nullptr;
5321 if (needs_type_check) {
Vladimir Marko0dda8c82019-05-16 12:47:40 +00005322 slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathX86_64(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005323 codegen_->AddSlowPath(slow_path);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005324
5325 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5326 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5327 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005328
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005329 // Note that when Baker read barriers are enabled, the type
5330 // checks are performed without read barriers. This is fine,
5331 // even in the case where a class object is in the from-space
5332 // after the flip, as a comparison involving such a type would
5333 // not produce a false positive; it may of course produce a
5334 // false negative, in which case we would take the ArraySet
5335 // slow path.
Roland Levillain16d9f942016-08-25 17:27:56 +01005336
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005337 // /* HeapReference<Class> */ temp = array->klass_
5338 __ movl(temp, Address(array, class_offset));
5339 codegen_->MaybeRecordImplicitNullCheck(instruction);
5340 __ MaybeUnpoisonHeapReference(temp);
Roland Levillain16d9f942016-08-25 17:27:56 +01005341
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005342 // /* HeapReference<Class> */ temp = temp->component_type_
5343 __ movl(temp, Address(temp, component_offset));
5344 // If heap poisoning is enabled, no need to unpoison `temp`
5345 // nor the object reference in `register_value->klass`, as
5346 // we are comparing two poisoned references.
5347 __ cmpl(temp, Address(register_value, class_offset));
Roland Levillain16d9f942016-08-25 17:27:56 +01005348
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005349 if (instruction->StaticTypeOfArrayIsObjectArray()) {
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005350 NearLabel do_put;
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005351 __ j(kEqual, &do_put);
5352 // If heap poisoning is enabled, the `temp` reference has
5353 // not been unpoisoned yet; unpoison it now.
Roland Levillain0d5a2812015-11-13 10:07:31 +00005354 __ MaybeUnpoisonHeapReference(temp);
5355
Roland Levillain9d6e1f82016-09-05 15:57:33 +01005356 // If heap poisoning is enabled, no need to unpoison the
5357 // heap reference loaded below, as it is only used for a
5358 // comparison with null.
5359 __ cmpl(Address(temp, super_offset), Immediate(0));
5360 __ j(kNotEqual, slow_path->GetEntryLabel());
5361 __ Bind(&do_put);
5362 } else {
5363 __ j(kNotEqual, slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005364 }
Vladimir Marko0dda8c82019-05-16 12:47:40 +00005365 }
5366
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005367 CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
5368 codegen_->MarkGCCard(
5369 temp, card, array, value.AsRegister<CpuRegister>(), /* value_can_be_null= */ false);
5370
5371 if (can_value_be_null) {
5372 DCHECK(do_store.IsLinked());
5373 __ Bind(&do_store);
5374 }
5375
5376 Location source = value;
Vladimir Marko0dda8c82019-05-16 12:47:40 +00005377 if (kPoisonHeapReferences) {
5378 __ movl(temp, register_value);
5379 __ PoisonHeapReference(temp);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005380 source = temp_loc;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005381 }
5382
Vladimir Marko8fa839c2019-05-16 12:50:47 +00005383 __ movl(address, source.AsRegister<CpuRegister>());
5384
5385 if (can_value_be_null || !needs_type_check) {
5386 codegen_->MaybeRecordImplicitNullCheck(instruction);
5387 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005388
Vladimir Marko0dda8c82019-05-16 12:47:40 +00005389 if (slow_path != nullptr) {
5390 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005391 }
5392
5393 break;
5394 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00005395
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005396 case DataType::Type::kInt32: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005397 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005398 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005399 if (value.IsRegister()) {
5400 __ movl(address, value.AsRegister<CpuRegister>());
5401 } else {
5402 DCHECK(value.IsConstant()) << value;
5403 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
5404 __ movl(address, Immediate(v));
5405 }
5406 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005407 break;
5408 }
5409
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005410 case DataType::Type::kInt64: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005411 uint32_t offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005412 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005413 if (value.IsRegister()) {
5414 __ movq(address, value.AsRegister<CpuRegister>());
Mark Mendellea5af682015-10-22 17:35:49 -04005415 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005416 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005417 int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005418 Address address_high =
5419 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04005420 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005421 }
5422 break;
5423 }
5424
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005425 case DataType::Type::kFloat32: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005426 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005427 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_4, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005428 if (value.IsFpuRegister()) {
5429 __ movss(address, value.AsFpuRegister<XmmRegister>());
5430 } else {
5431 DCHECK(value.IsConstant());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005432 int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
Mark Mendellea5af682015-10-22 17:35:49 -04005433 __ movl(address, Immediate(v));
5434 }
Calin Juravle77520bc2015-01-12 18:45:46 +00005435 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005436 break;
5437 }
5438
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005439 case DataType::Type::kFloat64: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005440 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005441 Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset);
Mark Mendellea5af682015-10-22 17:35:49 -04005442 if (value.IsFpuRegister()) {
5443 __ movsd(address, value.AsFpuRegister<XmmRegister>());
5444 codegen_->MaybeRecordImplicitNullCheck(instruction);
5445 } else {
5446 int64_t v =
5447 bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005448 Address address_high =
5449 CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_8, offset + sizeof(int32_t));
Mark Mendellea5af682015-10-22 17:35:49 -04005450 codegen_->MoveInt64ToAddress(address, address_high, v, instruction);
5451 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005452 break;
5453 }
5454
Aart Bik66c158e2018-01-31 12:55:04 -08005455 case DataType::Type::kUint32:
5456 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005457 case DataType::Type::kVoid:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005458 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07005459 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005460 }
5461}
5462
5463void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005464 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005465 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005466 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellee8d9712016-07-12 11:13:15 -04005467 if (!instruction->IsEmittedAtUseSite()) {
5468 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5469 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005470}
5471
5472void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
Mark Mendellee8d9712016-07-12 11:13:15 -04005473 if (instruction->IsEmittedAtUseSite()) {
5474 return;
5475 }
5476
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005477 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01005478 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005479 CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
5480 CpuRegister out = locations->Out().AsRegister<CpuRegister>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005481 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00005482 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo4877b792016-09-08 19:49:13 -07005483 // Mask out most significant bit in case the array is String's array of char.
5484 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005485 __ shrl(out, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005486 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005487}
5488
5489void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005490 RegisterSet caller_saves = RegisterSet::Empty();
5491 InvokeRuntimeCallingConvention calling_convention;
5492 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5493 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5494 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Mark Mendellf60c90b2015-03-04 15:12:59 -05005495 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendellee8d9712016-07-12 11:13:15 -04005496 HInstruction* length = instruction->InputAt(1);
5497 if (!length->IsEmittedAtUseSite()) {
5498 locations->SetInAt(1, Location::RegisterOrConstant(length));
5499 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005500}
5501
5502void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
5503 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05005504 Location index_loc = locations->InAt(0);
5505 Location length_loc = locations->InAt(1);
Vladimir Marko174b2e22017-10-12 13:34:49 +01005506 SlowPathCode* slow_path =
5507 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathX86_64(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005508
Mark Mendell99dbd682015-04-22 16:18:52 -04005509 if (length_loc.IsConstant()) {
5510 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
5511 if (index_loc.IsConstant()) {
5512 // BCE will remove the bounds check if we are guarenteed to pass.
5513 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5514 if (index < 0 || index >= length) {
5515 codegen_->AddSlowPath(slow_path);
5516 __ jmp(slow_path->GetEntryLabel());
5517 } else {
5518 // Some optimization after BCE may have generated this, and we should not
5519 // generate a bounds check if it is a valid range.
5520 }
5521 return;
5522 }
5523
5524 // We have to reverse the jump condition because the length is the constant.
5525 CpuRegister index_reg = index_loc.AsRegister<CpuRegister>();
5526 __ cmpl(index_reg, Immediate(length));
5527 codegen_->AddSlowPath(slow_path);
5528 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005529 } else {
Mark Mendellee8d9712016-07-12 11:13:15 -04005530 HInstruction* array_length = instruction->InputAt(1);
5531 if (array_length->IsEmittedAtUseSite()) {
5532 // Address the length field in the array.
5533 DCHECK(array_length->IsArrayLength());
5534 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
5535 Location array_loc = array_length->GetLocations()->InAt(0);
5536 Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
jessicahandojo4877b792016-09-08 19:49:13 -07005537 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005538 // TODO: if index_loc.IsConstant(), compare twice the index (to compensate for
5539 // the string compression flag) with the in-memory length and avoid the temporary.
jessicahandojo4877b792016-09-08 19:49:13 -07005540 CpuRegister length_reg = CpuRegister(TMP);
5541 __ movl(length_reg, array_len);
5542 codegen_->MaybeRecordImplicitNullCheck(array_length);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005543 __ shrl(length_reg, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07005544 codegen_->GenerateIntCompare(length_reg, index_loc);
Mark Mendellee8d9712016-07-12 11:13:15 -04005545 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07005546 // Checking the bound for general case:
5547 // Array of char or String's array when the compression feature off.
5548 if (index_loc.IsConstant()) {
5549 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
5550 __ cmpl(array_len, Immediate(value));
5551 } else {
5552 __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
5553 }
5554 codegen_->MaybeRecordImplicitNullCheck(array_length);
Mark Mendellee8d9712016-07-12 11:13:15 -04005555 }
Mark Mendell99dbd682015-04-22 16:18:52 -04005556 } else {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01005557 codegen_->GenerateIntCompare(length_loc, index_loc);
Mark Mendell99dbd682015-04-22 16:18:52 -04005558 }
5559 codegen_->AddSlowPath(slow_path);
5560 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05005561 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005562}
5563
5564void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
5565 CpuRegister card,
5566 CpuRegister object,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005567 CpuRegister value,
5568 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04005569 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005570 if (value_can_be_null) {
5571 __ testl(value, value);
5572 __ j(kEqual, &is_null);
5573 }
Roland Levillainc73f0522018-08-14 15:16:50 +01005574 // Load the address of the card table into `card`.
Andreas Gampe542451c2016-07-26 09:02:02 -07005575 __ gs()->movq(card, Address::Absolute(Thread::CardTableOffset<kX86_64PointerSize>().Int32Value(),
Andreas Gampe3db70682018-12-26 15:12:03 -08005576 /* no_rip= */ true));
Roland Levillainc73f0522018-08-14 15:16:50 +01005577 // Calculate the offset (in the card table) of the card corresponding to
5578 // `object`.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005579 __ movq(temp, object);
5580 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillainc73f0522018-08-14 15:16:50 +01005581 // Write the `art::gc::accounting::CardTable::kCardDirty` value into the
5582 // `object`'s card.
5583 //
5584 // Register `card` contains the address of the card table. Note that the card
5585 // table's base is biased during its creation so that it always starts at an
5586 // address whose least-significant byte is equal to `kCardDirty` (see
5587 // art::gc::accounting::CardTable::Create). Therefore the MOVB instruction
5588 // below writes the `kCardDirty` (byte) value into the `object`'s card
5589 // (located at `card + object >> kCardShift`).
5590 //
5591 // This dual use of the value in register `card` (1. to calculate the location
5592 // of the card to mark; and 2. to load the `kCardDirty` value) saves a load
5593 // (no need to explicitly load `kCardDirty` as an immediate value).
Roland Levillain4d027112015-07-01 15:41:14 +01005594 __ movb(Address(temp, card, TIMES_1, 0), card);
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005595 if (value_can_be_null) {
5596 __ Bind(&is_null);
5597 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005598}
5599
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005600void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005601 LOG(FATAL) << "Unimplemented";
5602}
5603
5604void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Vladimir Markobea75ff2017-10-11 20:39:54 +01005605 if (instruction->GetNext()->IsSuspendCheck() &&
5606 instruction->GetBlock()->GetLoopInformation() != nullptr) {
5607 HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
5608 // The back edge will generate the suspend check.
5609 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
5610 }
5611
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005612 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5613}
5614
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005615void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01005616 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
5617 instruction, LocationSummary::kCallOnSlowPath);
Aart Bikb13c65b2017-03-21 20:14:07 -07005618 // In suspend check slow path, usually there are no caller-save registers at all.
5619 // If SIMD instructions are present, however, we force spilling all live SIMD
5620 // registers in full width (since the runtime only saves/restores lower part).
Aart Bik5576f372017-03-23 16:17:37 -07005621 locations->SetCustomSlowPathCallerSaves(
5622 GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005623}
5624
5625void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005626 HBasicBlock* block = instruction->GetBlock();
5627 if (block->GetLoopInformation() != nullptr) {
5628 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5629 // The back edge will generate the suspend check.
5630 return;
5631 }
5632 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5633 // The goto will generate the suspend check.
5634 return;
5635 }
5636 GenerateSuspendCheck(instruction, nullptr);
5637}
5638
5639void InstructionCodeGeneratorX86_64::GenerateSuspendCheck(HSuspendCheck* instruction,
5640 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005641 SuspendCheckSlowPathX86_64* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005642 down_cast<SuspendCheckSlowPathX86_64*>(instruction->GetSlowPath());
5643 if (slow_path == nullptr) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01005644 slow_path =
5645 new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathX86_64(instruction, successor);
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005646 instruction->SetSlowPath(slow_path);
5647 codegen_->AddSlowPath(slow_path);
5648 if (successor != nullptr) {
5649 DCHECK(successor->IsLoopHeader());
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005650 }
5651 } else {
5652 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5653 }
5654
Andreas Gampe542451c2016-07-26 09:02:02 -07005655 __ gs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>().Int32Value(),
Andreas Gampe3db70682018-12-26 15:12:03 -08005656 /* no_rip= */ true),
Roland Levillain1e7f8db2015-12-15 10:54:19 +00005657 Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005658 if (successor == nullptr) {
5659 __ j(kNotEqual, slow_path->GetEntryLabel());
5660 __ Bind(slow_path->GetReturnLabel());
5661 } else {
5662 __ j(kEqual, codegen_->GetLabelOf(successor));
5663 __ jmp(slow_path->GetEntryLabel());
5664 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005665}
5666
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005667X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
5668 return codegen_->GetAssembler();
5669}
5670
5671void ParallelMoveResolverX86_64::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005672 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005673 Location source = move->GetSource();
5674 Location destination = move->GetDestination();
5675
5676 if (source.IsRegister()) {
5677 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005678 __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005679 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005680 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005681 source.AsRegister<CpuRegister>());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005682 } else {
5683 DCHECK(destination.IsDoubleStackSlot());
5684 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005685 source.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005686 }
5687 } else if (source.IsStackSlot()) {
5688 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005689 __ movl(destination.AsRegister<CpuRegister>(),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005690 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005691 } else if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005692 __ movss(destination.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005693 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005694 } else {
5695 DCHECK(destination.IsStackSlot());
5696 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5697 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5698 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005699 } else if (source.IsDoubleStackSlot()) {
5700 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005701 __ movq(destination.AsRegister<CpuRegister>(),
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005702 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005703 } else if (destination.IsFpuRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005704 __ movsd(destination.AsFpuRegister<XmmRegister>(),
5705 Address(CpuRegister(RSP), source.GetStackIndex()));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005706 } else {
Nicolas Geoffrayc8147a72014-10-21 16:06:20 +01005707 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005708 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5709 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5710 }
Aart Bik5576f372017-03-23 16:17:37 -07005711 } else if (source.IsSIMDStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08005712 if (destination.IsFpuRegister()) {
5713 __ movups(destination.AsFpuRegister<XmmRegister>(),
5714 Address(CpuRegister(RSP), source.GetStackIndex()));
5715 } else {
5716 DCHECK(destination.IsSIMDStackSlot());
5717 size_t high = kX86_64WordSize;
5718 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
5719 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
5720 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex() + high));
5721 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex() + high), CpuRegister(TMP));
5722 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005723 } else if (source.IsConstant()) {
5724 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005725 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5726 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005727 if (destination.IsRegister()) {
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005728 if (value == 0) {
5729 __ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
5730 } else {
5731 __ movl(destination.AsRegister<CpuRegister>(), Immediate(value));
5732 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005733 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005734 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray748f1402015-01-27 08:17:54 +00005735 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005736 }
5737 } else if (constant->IsLongConstant()) {
5738 int64_t value = constant->AsLongConstant()->GetValue();
5739 if (destination.IsRegister()) {
Mark Mendell92e83bf2015-05-07 11:25:03 -04005740 codegen_->Load64BitValue(destination.AsRegister<CpuRegister>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005741 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005742 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005743 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005744 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005745 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005746 float fp_value = constant->AsFloatConstant()->GetValue();
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005747 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005748 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005749 codegen_->Load32BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005750 } else {
5751 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005752 Immediate imm(bit_cast<int32_t, float>(fp_value));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005753 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
5754 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005755 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005756 DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005757 double fp_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00005758 int64_t value = bit_cast<int64_t, double>(fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005759 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005760 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
Mark Mendell7c0b44f2016-02-01 10:08:35 -05005761 codegen_->Load64BitValue(dest, fp_value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005762 } else {
5763 DCHECK(destination.IsDoubleStackSlot()) << destination;
Mark Mendellcfa410b2015-05-25 16:02:44 -04005764 codegen_->Store64BitValueToStack(destination, value);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005765 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005766 }
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005767 } else if (source.IsFpuRegister()) {
5768 if (destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005769 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005770 } else if (destination.IsStackSlot()) {
5771 __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005772 source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07005773 } else if (destination.IsDoubleStackSlot()) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005774 __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
Roland Levillain271ab9c2014-11-27 15:23:57 +00005775 source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07005776 } else {
5777 DCHECK(destination.IsSIMDStackSlot());
5778 __ movups(Address(CpuRegister(RSP), destination.GetStackIndex()),
5779 source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005780 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005781 }
5782}
5783
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005784void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005785 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005786 __ movl(Address(CpuRegister(RSP), mem), reg);
5787 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005788}
5789
Mark Mendell8a1c7282015-06-29 15:41:28 -04005790void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg1, CpuRegister reg2) {
5791 __ movq(CpuRegister(TMP), reg1);
5792 __ movq(reg1, reg2);
5793 __ movq(reg2, CpuRegister(TMP));
5794}
5795
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005796void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
5797 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5798 __ movq(Address(CpuRegister(RSP), mem), reg);
5799 __ movq(reg, CpuRegister(TMP));
5800}
5801
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005802void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
5803 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5804 __ movss(Address(CpuRegister(RSP), mem), reg);
5805 __ movd(reg, CpuRegister(TMP));
5806}
5807
5808void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
5809 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
5810 __ movsd(Address(CpuRegister(RSP), mem), reg);
5811 __ movd(reg, CpuRegister(TMP));
5812}
5813
Aart Bikcfe50bb2017-12-12 14:54:12 -08005814void ParallelMoveResolverX86_64::Exchange128(XmmRegister reg, int mem) {
5815 size_t extra_slot = 2 * kX86_64WordSize;
5816 __ subq(CpuRegister(RSP), Immediate(extra_slot));
5817 __ movups(Address(CpuRegister(RSP), 0), XmmRegister(reg));
5818 ExchangeMemory64(0, mem + extra_slot, 2);
5819 __ movups(XmmRegister(reg), Address(CpuRegister(RSP), 0));
5820 __ addq(CpuRegister(RSP), Immediate(extra_slot));
5821}
5822
5823void ParallelMoveResolverX86_64::ExchangeMemory32(int mem1, int mem2) {
5824 ScratchRegisterScope ensure_scratch(
5825 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5826
5827 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5828 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
5829 __ movl(CpuRegister(ensure_scratch.GetRegister()),
5830 Address(CpuRegister(RSP), mem2 + stack_offset));
5831 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
5832 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
5833 CpuRegister(ensure_scratch.GetRegister()));
5834}
5835
5836void ParallelMoveResolverX86_64::ExchangeMemory64(int mem1, int mem2, int num_of_qwords) {
5837 ScratchRegisterScope ensure_scratch(
5838 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
5839
5840 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
5841
5842 // Now that temp registers are available (possibly spilled), exchange blocks of memory.
5843 for (int i = 0; i < num_of_qwords; i++) {
5844 __ movq(CpuRegister(TMP),
5845 Address(CpuRegister(RSP), mem1 + stack_offset));
5846 __ movq(CpuRegister(ensure_scratch.GetRegister()),
5847 Address(CpuRegister(RSP), mem2 + stack_offset));
5848 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset),
5849 CpuRegister(TMP));
5850 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
5851 CpuRegister(ensure_scratch.GetRegister()));
5852 stack_offset += kX86_64WordSize;
5853 }
5854}
5855
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005856void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005857 MoveOperands* move = moves_[index];
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005858 Location source = move->GetSource();
5859 Location destination = move->GetDestination();
5860
5861 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell8a1c7282015-06-29 15:41:28 -04005862 Exchange64(source.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005863 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005864 Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005865 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005866 Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005867 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08005868 ExchangeMemory32(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005869 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005870 Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005871 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005872 Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005873 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08005874 ExchangeMemory64(destination.GetStackIndex(), source.GetStackIndex(), 1);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005875 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005876 __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
5877 __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5878 __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005879 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005880 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005881 } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005882 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005883 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005884 Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005885 } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005886 Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Aart Bikcfe50bb2017-12-12 14:54:12 -08005887 } else if (source.IsSIMDStackSlot() && destination.IsSIMDStackSlot()) {
5888 ExchangeMemory64(destination.GetStackIndex(), source.GetStackIndex(), 2);
5889 } else if (source.IsFpuRegister() && destination.IsSIMDStackSlot()) {
5890 Exchange128(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
5891 } else if (destination.IsFpuRegister() && source.IsSIMDStackSlot()) {
5892 Exchange128(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005893 } else {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01005894 LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00005895 }
5896}
5897
5898
5899void ParallelMoveResolverX86_64::SpillScratch(int reg) {
5900 __ pushq(CpuRegister(reg));
5901}
5902
5903
5904void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
5905 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01005906}
5907
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005908void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005909 SlowPathCode* slow_path, CpuRegister class_reg) {
Vladimir Markodc682aa2018-01-04 18:42:57 +00005910 constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
5911 const size_t status_byte_offset =
5912 mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
Vladimir Markobf121912019-06-04 13:49:05 +01005913 constexpr uint32_t shifted_visibly_initialized_value =
5914 enum_cast<uint32_t>(ClassStatus::kVisiblyInitialized) << (status_lsb_position % kBitsPerByte);
Vladimir Markodc682aa2018-01-04 18:42:57 +00005915
Vladimir Markobf121912019-06-04 13:49:05 +01005916 __ cmpb(Address(class_reg, status_byte_offset), Immediate(shifted_visibly_initialized_value));
Vladimir Marko2c64a832018-01-04 11:31:56 +00005917 __ j(kBelow, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005918 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005919}
5920
Vladimir Marko175e7862018-03-27 09:03:13 +00005921void InstructionCodeGeneratorX86_64::GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
5922 CpuRegister temp) {
5923 uint32_t path_to_root = check->GetBitstringPathToRoot();
5924 uint32_t mask = check->GetBitstringMask();
5925 DCHECK(IsPowerOfTwo(mask + 1));
5926 size_t mask_bits = WhichPowerOf2(mask + 1);
5927
5928 if (mask_bits == 16u) {
5929 // Compare the bitstring in memory.
5930 __ cmpw(Address(temp, mirror::Class::StatusOffset()), Immediate(path_to_root));
5931 } else {
5932 // /* uint32_t */ temp = temp->status_
5933 __ movl(temp, Address(temp, mirror::Class::StatusOffset()));
5934 // Compare the bitstring bits using SUB.
5935 __ subl(temp, Immediate(path_to_root));
5936 // Shift out bits that do not contribute to the comparison.
5937 __ shll(temp, Immediate(32u - mask_bits));
5938 }
5939}
5940
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005941HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
5942 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005943 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00005944 case HLoadClass::LoadKind::kInvalid:
5945 LOG(FATAL) << "UNREACHABLE";
5946 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005947 case HLoadClass::LoadKind::kReferrersClass:
5948 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005949 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00005950 case HLoadClass::LoadKind::kBootImageRelRo:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005951 case HLoadClass::LoadKind::kBssEntry:
5952 DCHECK(!Runtime::Current()->UseJitCompilation());
5953 break;
Vladimir Marko8e524ad2018-07-13 10:27:43 +01005954 case HLoadClass::LoadKind::kJitBootImageAddress:
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005955 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005956 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005957 break;
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005958 case HLoadClass::LoadKind::kRuntimeCall:
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005959 break;
5960 }
5961 return desired_class_load_kind;
5962}
5963
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005964void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005965 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01005966 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00005967 // Custom calling convention: RAX serves as both input and output.
Vladimir Marko41559982017-01-06 14:04:23 +00005968 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005969 cls,
Vladimir Markoea4c1262017-02-06 19:59:33 +00005970 Location::RegisterLocation(RAX),
Vladimir Marko41559982017-01-06 14:04:23 +00005971 Location::RegisterLocation(RAX));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005972 return;
5973 }
Vladimir Marko41559982017-01-06 14:04:23 +00005974 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005975
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005976 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5977 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005978 ? LocationSummary::kCallOnSlowPath
5979 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01005980 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07005981 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005982 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005983 }
5984
Vladimir Marko41559982017-01-06 14:04:23 +00005985 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005986 locations->SetInAt(0, Location::RequiresRegister());
5987 }
5988 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00005989 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
5990 if (!kUseReadBarrier || kUseBakerReadBarrier) {
5991 // Rely on the type resolution and/or initialization to save everything.
Vladimir Marko3232dbb2018-07-25 15:42:46 +01005992 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Vladimir Markoea4c1262017-02-06 19:59:33 +00005993 } else {
5994 // For non-Baker read barrier we have a temp-clobbering call.
5995 }
5996 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005997}
5998
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005999Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01006000 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006001 Handle<mirror::Class> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01006002 ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006003 // Add a patch entry and return the label.
Vladimir Marko59eb30f2018-02-20 11:52:34 +00006004 jit_class_patches_.emplace_back(&dex_file, type_index.index_);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006005 PatchInfo<Label>* info = &jit_class_patches_.back();
6006 return &info->label;
6007}
6008
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006009// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6010// move.
6011void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00006012 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01006013 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00006014 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01006015 return;
6016 }
Vladimir Marko41559982017-01-06 14:04:23 +00006017 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01006018
Vladimir Marko41559982017-01-06 14:04:23 +00006019 LocationSummary* locations = cls->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006020 Location out_loc = locations->Out();
6021 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006022
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006023 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
6024 ? kWithoutReadBarrier
6025 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006026 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00006027 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006028 case HLoadClass::LoadKind::kReferrersClass: {
6029 DCHECK(!cls->CanCallRuntime());
6030 DCHECK(!cls->MustGenerateClinitCheck());
6031 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
6032 CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
6033 GenerateGcRootFieldLoad(
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006034 cls,
6035 out_loc,
6036 Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
Andreas Gampe3db70682018-12-26 15:12:03 -08006037 /* fixup_label= */ nullptr,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006038 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006039 break;
6040 }
6041 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko44ca0752019-07-29 10:18:25 +01006042 DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
6043 codegen_->GetCompilerOptions().IsBootImageExtension());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006044 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Andreas Gampe3db70682018-12-26 15:12:03 -08006045 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00006046 codegen_->RecordBootImageTypePatch(cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006047 break;
Vladimir Markoe47f60c2018-02-21 13:43:28 +00006048 case HLoadClass::LoadKind::kBootImageRelRo: {
Vladimir Marko94ec2db2017-09-06 17:21:03 +01006049 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Andreas Gampe3db70682018-12-26 15:12:03 -08006050 __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Markoe47f60c2018-02-21 13:43:28 +00006051 codegen_->RecordBootImageRelRoPatch(codegen_->GetBootImageOffset(cls));
Vladimir Marko94ec2db2017-09-06 17:21:03 +01006052 break;
6053 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006054 case HLoadClass::LoadKind::kBssEntry: {
6055 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
Andreas Gampe3db70682018-12-26 15:12:03 -08006056 /* no_rip= */ false);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006057 Label* fixup_label = codegen_->NewTypeBssEntryPatch(cls);
6058 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
6059 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
Vladimir Markod5fd5c32019-07-02 14:46:32 +01006060 // No need for memory fence, thanks to the x86-64 memory model.
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006061 generate_null_check = true;
6062 break;
6063 }
Vladimir Marko8e524ad2018-07-13 10:27:43 +01006064 case HLoadClass::LoadKind::kJitBootImageAddress: {
6065 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
6066 uint32_t address = reinterpret_cast32<uint32_t>(cls->GetClass().Get());
6067 DCHECK_NE(address, 0u);
6068 __ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended.
6069 break;
6070 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006071 case HLoadClass::LoadKind::kJitTableAddress: {
6072 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
Andreas Gampe3db70682018-12-26 15:12:03 -08006073 /* no_rip= */ true);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006074 Label* fixup_label =
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006075 codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006076 // /* GcRoot<mirror::Class> */ out = *address
Vladimir Markoea4c1262017-02-06 19:59:33 +00006077 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006078 break;
6079 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006080 default:
6081 LOG(FATAL) << "Unexpected load kind: " << cls->GetLoadKind();
6082 UNREACHABLE();
6083 }
6084
6085 if (generate_null_check || cls->MustGenerateClinitCheck()) {
6086 DCHECK(cls->CanCallRuntime());
Vladimir Markoa9f303c2018-07-20 16:43:56 +01006087 SlowPathCode* slow_path =
6088 new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64(cls, cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006089 codegen_->AddSlowPath(slow_path);
6090 if (generate_null_check) {
6091 __ testl(out, out);
6092 __ j(kEqual, slow_path->GetEntryLabel());
6093 }
6094 if (cls->MustGenerateClinitCheck()) {
6095 GenerateClassInitializationCheck(slow_path, out);
6096 } else {
6097 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006098 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006099 }
6100}
6101
6102void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
6103 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01006104 new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006105 locations->SetInAt(0, Location::RequiresRegister());
6106 if (check->HasUses()) {
6107 locations->SetOut(Location::SameAsFirstInput());
6108 }
Vladimir Marko3232dbb2018-07-25 15:42:46 +01006109 // Rely on the type initialization to save everything we need.
6110 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006111}
6112
Orion Hodsondbaa5c72018-05-10 08:22:46 +01006113void LocationsBuilderX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
6114 // Custom calling convention: RAX serves as both input and output.
6115 Location location = Location::RegisterLocation(RAX);
6116 CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
6117}
6118
6119void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
6120 codegen_->GenerateLoadMethodHandleRuntimeCall(load);
6121}
6122
Orion Hodson18259d72018-04-12 11:18:23 +01006123void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
6124 // Custom calling convention: RAX serves as both input and output.
6125 Location location = Location::RegisterLocation(RAX);
6126 CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
6127}
6128
6129void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) {
6130 codegen_->GenerateLoadMethodTypeRuntimeCall(load);
6131}
6132
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006133void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006134 // We assume the class to not be null.
Vladimir Markoa9f303c2018-07-20 16:43:56 +01006135 SlowPathCode* slow_path =
6136 new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64(check->GetLoadClass(), check);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006137 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00006138 GenerateClassInitializationCheck(slow_path,
6139 check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006140}
6141
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006142HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
6143 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006144 switch (desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006145 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00006146 case HLoadString::LoadKind::kBootImageRelRo:
Vladimir Markoaad75c62016-10-03 08:46:48 +00006147 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01006148 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006149 break;
Vladimir Marko8e524ad2018-07-13 10:27:43 +01006150 case HLoadString::LoadKind::kJitBootImageAddress:
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006151 case HLoadString::LoadKind::kJitTableAddress:
6152 DCHECK(Runtime::Current()->UseJitCompilation());
6153 break;
Vladimir Marko847e6ce2017-06-02 13:55:07 +01006154 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006155 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006156 }
6157 return desired_string_load_kind;
6158}
6159
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006160void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006161 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Vladimir Markoca6fff82017-10-03 14:49:14 +01006162 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
Vladimir Marko847e6ce2017-06-02 13:55:07 +01006163 if (load->GetLoadKind() == HLoadString::LoadKind::kRuntimeCall) {
Christina Wadsworthabb341b2016-08-31 16:29:44 -07006164 locations->SetOut(Location::RegisterLocation(RAX));
6165 } else {
6166 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006167 if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) {
6168 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00006169 // Rely on the pResolveString to save everything.
Vladimir Marko3232dbb2018-07-25 15:42:46 +01006170 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006171 } else {
6172 // For non-Baker read barrier we have a temp-clobbering call.
6173 }
6174 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006175 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006176}
6177
Andreas Gampe8a0128a2016-11-28 07:38:35 -08006178Label* CodeGeneratorX86_64::NewJitRootStringPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01006179 dex::StringIndex string_index,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006180 Handle<mirror::String> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01006181 ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006182 // Add a patch entry and return the label.
Vladimir Marko59eb30f2018-02-20 11:52:34 +00006183 jit_string_patches_.emplace_back(&dex_file, string_index.index_);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006184 PatchInfo<Label>* info = &jit_string_patches_.back();
6185 return &info->label;
6186}
6187
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006188// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6189// move.
6190void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01006191 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006192 Location out_loc = locations->Out();
6193 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006194
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006195 switch (load->GetLoadKind()) {
6196 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko44ca0752019-07-29 10:18:25 +01006197 DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
6198 codegen_->GetCompilerOptions().IsBootImageExtension());
Andreas Gampe3db70682018-12-26 15:12:03 -08006199 __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00006200 codegen_->RecordBootImageStringPatch(load);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01006201 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006202 }
Vladimir Markoe47f60c2018-02-21 13:43:28 +00006203 case HLoadString::LoadKind::kBootImageRelRo: {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01006204 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Andreas Gampe3db70682018-12-26 15:12:03 -08006205 __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip= */ false));
Vladimir Markoe47f60c2018-02-21 13:43:28 +00006206 codegen_->RecordBootImageRelRoPatch(codegen_->GetBootImageOffset(load));
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01006207 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006208 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00006209 case HLoadString::LoadKind::kBssEntry: {
6210 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
Andreas Gampe3db70682018-12-26 15:12:03 -08006211 /* no_rip= */ false);
Vladimir Markoaad75c62016-10-03 08:46:48 +00006212 Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
6213 // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006214 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
Vladimir Markod5fd5c32019-07-02 14:46:32 +01006215 // No need for memory fence, thanks to the x86-64 memory model.
Vladimir Marko174b2e22017-10-12 13:34:49 +01006216 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadStringSlowPathX86_64(load);
Vladimir Markoaad75c62016-10-03 08:46:48 +00006217 codegen_->AddSlowPath(slow_path);
6218 __ testl(out, out);
6219 __ j(kEqual, slow_path->GetEntryLabel());
6220 __ Bind(slow_path->GetExitLabel());
6221 return;
6222 }
Vladimir Marko8e524ad2018-07-13 10:27:43 +01006223 case HLoadString::LoadKind::kJitBootImageAddress: {
6224 uint32_t address = reinterpret_cast32<uint32_t>(load->GetString().Get());
6225 DCHECK_NE(address, 0u);
6226 __ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended.
6227 return;
6228 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006229 case HLoadString::LoadKind::kJitTableAddress: {
6230 Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
Andreas Gampe3db70682018-12-26 15:12:03 -08006231 /* no_rip= */ true);
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006232 Label* fixup_label = codegen_->NewJitRootStringPatch(
6233 load->GetDexFile(), load->GetStringIndex(), load->GetString());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006234 // /* GcRoot<mirror::String> */ out = *address
6235 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
6236 return;
6237 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006238 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07006239 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006240 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006241
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07006242 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006243 // Custom calling convention: RAX serves as both input and output.
Andreas Gampe8a0128a2016-11-28 07:38:35 -08006244 __ movl(CpuRegister(RAX), Immediate(load->GetStringIndex().index_));
Christina Wadsworthabb341b2016-08-31 16:29:44 -07006245 codegen_->InvokeRuntime(kQuickResolveString,
6246 load,
6247 load->GetDexPc());
6248 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006249}
6250
David Brazdilcb1c0552015-08-04 16:22:25 +01006251static Address GetExceptionTlsAddress() {
Andreas Gampe542451c2016-07-26 09:02:02 -07006252 return Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>().Int32Value(),
Andreas Gampe3db70682018-12-26 15:12:03 -08006253 /* no_rip= */ true);
David Brazdilcb1c0552015-08-04 16:22:25 +01006254}
6255
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006256void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
6257 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01006258 new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006259 locations->SetOut(Location::RequiresRegister());
6260}
6261
6262void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01006263 __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
6264}
6265
6266void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006267 new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
David Brazdilcb1c0552015-08-04 16:22:25 +01006268}
6269
6270void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
6271 __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006272}
6273
6274void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006275 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6276 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006277 InvokeRuntimeCallingConvention calling_convention;
6278 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6279}
6280
6281void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01006282 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006283 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006284}
6285
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006286// Temp is used for read barrier.
6287static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
6288 if (kEmitCompilerReadBarrier &&
Vladimir Marko953437b2016-08-24 08:30:46 +00006289 !kUseBakerReadBarrier &&
6290 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006291 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006292 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
6293 return 1;
6294 }
6295 return 0;
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006296}
6297
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006298// Interface case has 2 temps, one for holding the number of interfaces, one for the current
6299// interface pointer, the current interface is compared in memory.
6300// The other checks have one temp for loading the object's class.
6301static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
6302 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6303 return 2;
6304 }
6305 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Nicolas Geoffray53b07bd2016-11-05 15:09:19 +00006306}
6307
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006308void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006309 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00006310 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01006311 bool baker_read_barrier_slow_path = false;
Roland Levillain0d5a2812015-11-13 10:07:31 +00006312 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006313 case TypeCheckKind::kExactCheck:
6314 case TypeCheckKind::kAbstractClassCheck:
6315 case TypeCheckKind::kClassHierarchyCheck:
Vladimir Marko87584542017-12-12 17:47:52 +00006316 case TypeCheckKind::kArrayObjectCheck: {
6317 bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
6318 call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
6319 baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006320 break;
Vladimir Marko87584542017-12-12 17:47:52 +00006321 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006322 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00006323 case TypeCheckKind::kUnresolvedCheck:
6324 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006325 call_kind = LocationSummary::kCallOnSlowPath;
6326 break;
Vladimir Marko175e7862018-03-27 09:03:13 +00006327 case TypeCheckKind::kBitstringCheck:
6328 break;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006329 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006330
Vladimir Markoca6fff82017-10-03 14:49:14 +01006331 LocationSummary* locations =
6332 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01006333 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006334 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006335 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006336 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00006337 if (type_check_kind == TypeCheckKind::kBitstringCheck) {
6338 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
6339 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
6340 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
6341 } else {
6342 locations->SetInAt(1, Location::Any());
6343 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006344 // Note that TypeCheckSlowPathX86_64 uses this "out" register too.
6345 locations->SetOut(Location::RequiresRegister());
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006346 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006347}
6348
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006349void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006350 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006351 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006352 Location obj_loc = locations->InAt(0);
6353 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006354 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006355 Location out_loc = locations->Out();
6356 CpuRegister out = out_loc.AsRegister<CpuRegister>();
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006357 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
6358 DCHECK_LE(num_temps, 1u);
6359 Location maybe_temp_loc = (num_temps >= 1u) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006360 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006361 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6362 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6363 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07006364 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006365 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006366
6367 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006368 // Avoid null check if we know obj is not null.
6369 if (instruction->MustDoNullCheck()) {
6370 __ testl(obj, obj);
6371 __ j(kEqual, &zero);
6372 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006373
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006374 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006375 case TypeCheckKind::kExactCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00006376 ReadBarrierOption read_barrier_option =
6377 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006378 // /* HeapReference<Class> */ out = obj->klass_
6379 GenerateReferenceLoadTwoRegisters(instruction,
6380 out_loc,
6381 obj_loc,
6382 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00006383 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006384 if (cls.IsRegister()) {
6385 __ cmpl(out, cls.AsRegister<CpuRegister>());
6386 } else {
6387 DCHECK(cls.IsStackSlot()) << cls;
6388 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6389 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006390 if (zero.IsLinked()) {
6391 // Classes must be equal for the instanceof to succeed.
6392 __ j(kNotEqual, &zero);
6393 __ movl(out, Immediate(1));
6394 __ jmp(&done);
6395 } else {
6396 __ setcc(kEqual, out);
6397 // setcc only sets the low byte.
6398 __ andl(out, Immediate(1));
6399 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006400 break;
6401 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006402
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006403 case TypeCheckKind::kAbstractClassCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00006404 ReadBarrierOption read_barrier_option =
6405 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006406 // /* HeapReference<Class> */ out = obj->klass_
6407 GenerateReferenceLoadTwoRegisters(instruction,
6408 out_loc,
6409 obj_loc,
6410 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00006411 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006412 // If the class is abstract, we eagerly fetch the super class of the
6413 // object to avoid doing a comparison we know will fail.
6414 NearLabel loop, success;
6415 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006416 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006417 GenerateReferenceLoadOneRegister(instruction,
6418 out_loc,
6419 super_offset,
6420 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00006421 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006422 __ testl(out, out);
6423 // If `out` is null, we use it for the result, and jump to `done`.
6424 __ j(kEqual, &done);
6425 if (cls.IsRegister()) {
6426 __ cmpl(out, cls.AsRegister<CpuRegister>());
6427 } else {
6428 DCHECK(cls.IsStackSlot()) << cls;
6429 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6430 }
6431 __ j(kNotEqual, &loop);
6432 __ movl(out, Immediate(1));
6433 if (zero.IsLinked()) {
6434 __ jmp(&done);
6435 }
6436 break;
6437 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006438
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006439 case TypeCheckKind::kClassHierarchyCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00006440 ReadBarrierOption read_barrier_option =
6441 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006442 // /* HeapReference<Class> */ out = obj->klass_
6443 GenerateReferenceLoadTwoRegisters(instruction,
6444 out_loc,
6445 obj_loc,
6446 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00006447 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006448 // Walk over the class hierarchy to find a match.
6449 NearLabel loop, success;
6450 __ Bind(&loop);
6451 if (cls.IsRegister()) {
6452 __ cmpl(out, cls.AsRegister<CpuRegister>());
6453 } else {
6454 DCHECK(cls.IsStackSlot()) << cls;
6455 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6456 }
6457 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006458 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006459 GenerateReferenceLoadOneRegister(instruction,
6460 out_loc,
6461 super_offset,
6462 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00006463 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006464 __ testl(out, out);
6465 __ j(kNotEqual, &loop);
6466 // If `out` is null, we use it for the result, and jump to `done`.
6467 __ jmp(&done);
6468 __ Bind(&success);
6469 __ movl(out, Immediate(1));
6470 if (zero.IsLinked()) {
6471 __ jmp(&done);
6472 }
6473 break;
6474 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006475
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006476 case TypeCheckKind::kArrayObjectCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00006477 ReadBarrierOption read_barrier_option =
6478 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006479 // /* HeapReference<Class> */ out = obj->klass_
6480 GenerateReferenceLoadTwoRegisters(instruction,
6481 out_loc,
6482 obj_loc,
6483 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00006484 read_barrier_option);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006485 // Do an exact check.
6486 NearLabel exact_check;
6487 if (cls.IsRegister()) {
6488 __ cmpl(out, cls.AsRegister<CpuRegister>());
6489 } else {
6490 DCHECK(cls.IsStackSlot()) << cls;
6491 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6492 }
6493 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006494 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006495 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006496 GenerateReferenceLoadOneRegister(instruction,
6497 out_loc,
6498 component_offset,
6499 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00006500 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006501 __ testl(out, out);
6502 // If `out` is null, we use it for the result, and jump to `done`.
6503 __ j(kEqual, &done);
6504 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
6505 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006506 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006507 __ movl(out, Immediate(1));
6508 __ jmp(&done);
6509 break;
6510 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006511
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006512 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08006513 // No read barrier since the slow path will retry upon failure.
6514 // /* HeapReference<Class> */ out = obj->klass_
6515 GenerateReferenceLoadTwoRegisters(instruction,
6516 out_loc,
6517 obj_loc,
6518 class_offset,
6519 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006520 if (cls.IsRegister()) {
6521 __ cmpl(out, cls.AsRegister<CpuRegister>());
6522 } else {
6523 DCHECK(cls.IsStackSlot()) << cls;
6524 __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
6525 }
6526 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01006527 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86_64(
Andreas Gampe3db70682018-12-26 15:12:03 -08006528 instruction, /* is_fatal= */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006529 codegen_->AddSlowPath(slow_path);
6530 __ j(kNotEqual, slow_path->GetEntryLabel());
6531 __ movl(out, Immediate(1));
6532 if (zero.IsLinked()) {
6533 __ jmp(&done);
6534 }
6535 break;
6536 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006537
Calin Juravle98893e12015-10-02 21:05:03 +01006538 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00006539 case TypeCheckKind::kInterfaceCheck: {
6540 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006541 // into the slow path for the unresolved and interface check
Roland Levillain0d5a2812015-11-13 10:07:31 +00006542 // cases.
6543 //
6544 // We cannot directly call the InstanceofNonTrivial runtime
6545 // entry point without resorting to a type checking slow path
6546 // here (i.e. by calling InvokeRuntime directly), as it would
6547 // require to assign fixed registers for the inputs of this
6548 // HInstanceOf instruction (following the runtime calling
6549 // convention), which might be cluttered by the potential first
6550 // read barrier emission at the beginning of this method.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006551 //
6552 // TODO: Introduce a new runtime entry point taking the object
6553 // to test (instead of its class) as argument, and let it deal
6554 // with the read barrier issues. This will let us refactor this
6555 // case of the `switch` code as it was previously (with a direct
6556 // call to the runtime not using a type checking slow path).
6557 // This should also be beneficial for the other cases above.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006558 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01006559 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86_64(
Andreas Gampe3db70682018-12-26 15:12:03 -08006560 instruction, /* is_fatal= */ false);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006561 codegen_->AddSlowPath(slow_path);
6562 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006563 if (zero.IsLinked()) {
6564 __ jmp(&done);
6565 }
6566 break;
6567 }
Vladimir Marko175e7862018-03-27 09:03:13 +00006568
6569 case TypeCheckKind::kBitstringCheck: {
6570 // /* HeapReference<Class> */ temp = obj->klass_
6571 GenerateReferenceLoadTwoRegisters(instruction,
6572 out_loc,
6573 obj_loc,
6574 class_offset,
6575 kWithoutReadBarrier);
6576
6577 GenerateBitstringTypeCheckCompare(instruction, out);
6578 if (zero.IsLinked()) {
6579 __ j(kNotEqual, &zero);
6580 __ movl(out, Immediate(1));
6581 __ jmp(&done);
6582 } else {
6583 __ setcc(kEqual, out);
6584 // setcc only sets the low byte.
6585 __ andl(out, Immediate(1));
6586 }
6587 break;
6588 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006589 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006590
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006591 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006592 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006593 __ xorl(out, out);
6594 }
6595
6596 if (done.IsLinked()) {
6597 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01006598 }
6599
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006600 if (slow_path != nullptr) {
6601 __ Bind(slow_path->GetExitLabel());
6602 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00006603}
6604
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006605void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
Andreas Gampeb5f3d812016-11-04 19:25:20 -07006606 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko87584542017-12-12 17:47:52 +00006607 LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
Vladimir Markoca6fff82017-10-03 14:49:14 +01006608 LocationSummary* locations =
6609 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006610 locations->SetInAt(0, Location::RequiresRegister());
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006611 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6612 // Require a register for the interface check since there is a loop that compares the class to
6613 // a memory address.
6614 locations->SetInAt(1, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00006615 } else if (type_check_kind == TypeCheckKind::kBitstringCheck) {
6616 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
6617 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
6618 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006619 } else {
6620 locations->SetInAt(1, Location::Any());
6621 }
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006622 // Add temps for read barriers and other uses. One is used by TypeCheckSlowPathX86.
6623 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006624}
6625
6626void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00006627 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006628 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006629 Location obj_loc = locations->InAt(0);
6630 CpuRegister obj = obj_loc.AsRegister<CpuRegister>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006631 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006632 Location temp_loc = locations->GetTemp(0);
6633 CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
Vladimir Marko9f8d3122018-04-06 13:47:59 +01006634 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
6635 DCHECK_GE(num_temps, 1u);
6636 DCHECK_LE(num_temps, 2u);
6637 Location maybe_temp2_loc = (num_temps >= 2u) ? locations->GetTemp(1) : Location::NoLocation();
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006638 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6639 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6640 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6641 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6642 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6643 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006644 const uint32_t object_array_data_offset =
6645 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006646
Vladimir Marko87584542017-12-12 17:47:52 +00006647 bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006648 SlowPathCode* type_check_slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01006649 new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86_64(
6650 instruction, is_type_check_slow_path_fatal);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006651 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006652
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006653
6654 NearLabel done;
6655 // Avoid null check if we know obj is not null.
6656 if (instruction->MustDoNullCheck()) {
6657 __ testl(obj, obj);
6658 __ j(kEqual, &done);
6659 }
6660
Roland Levillain0d5a2812015-11-13 10:07:31 +00006661 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006662 case TypeCheckKind::kExactCheck:
6663 case TypeCheckKind::kArrayCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006664 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006665 GenerateReferenceLoadTwoRegisters(instruction,
6666 temp_loc,
6667 obj_loc,
6668 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006669 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006670 if (cls.IsRegister()) {
6671 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6672 } else {
6673 DCHECK(cls.IsStackSlot()) << cls;
6674 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6675 }
6676 // Jump to slow path for throwing the exception or doing a
6677 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006678 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006679 break;
6680 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006681
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006682 case TypeCheckKind::kAbstractClassCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006683 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006684 GenerateReferenceLoadTwoRegisters(instruction,
6685 temp_loc,
6686 obj_loc,
6687 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006688 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006689 // If the class is abstract, we eagerly fetch the super class of the
6690 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006691 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006692 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006693 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006694 GenerateReferenceLoadOneRegister(instruction,
6695 temp_loc,
6696 super_offset,
6697 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006698 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006699
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006700 // If the class reference currently in `temp` is null, jump to the slow path to throw the
6701 // exception.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006702 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006703 // Otherwise, compare the classes.
6704 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006705 if (cls.IsRegister()) {
6706 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6707 } else {
6708 DCHECK(cls.IsStackSlot()) << cls;
6709 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6710 }
6711 __ j(kNotEqual, &loop);
6712 break;
6713 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006714
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006715 case TypeCheckKind::kClassHierarchyCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006716 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006717 GenerateReferenceLoadTwoRegisters(instruction,
6718 temp_loc,
6719 obj_loc,
6720 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006721 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006722 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006723 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006724 __ Bind(&loop);
6725 if (cls.IsRegister()) {
6726 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6727 } else {
6728 DCHECK(cls.IsStackSlot()) << cls;
6729 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6730 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006731 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006732
Roland Levillain0d5a2812015-11-13 10:07:31 +00006733 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006734 GenerateReferenceLoadOneRegister(instruction,
6735 temp_loc,
6736 super_offset,
6737 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006738 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006739
6740 // If the class reference currently in `temp` is not null, jump
6741 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006742 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006743 __ j(kNotZero, &loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006744 // Otherwise, jump to the slow path to throw the exception.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006745 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006746 break;
6747 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006748
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006749 case TypeCheckKind::kArrayObjectCheck: {
Roland Levillain86503782016-02-11 19:07:30 +00006750 // /* HeapReference<Class> */ temp = obj->klass_
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006751 GenerateReferenceLoadTwoRegisters(instruction,
6752 temp_loc,
6753 obj_loc,
6754 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006755 kWithoutReadBarrier);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006756 // Do an exact check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006757 NearLabel check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01006758 if (cls.IsRegister()) {
6759 __ cmpl(temp, cls.AsRegister<CpuRegister>());
6760 } else {
6761 DCHECK(cls.IsStackSlot()) << cls;
6762 __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
6763 }
6764 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006765
6766 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006767 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006768 GenerateReferenceLoadOneRegister(instruction,
6769 temp_loc,
6770 component_offset,
6771 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006772 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006773
6774 // If the component type is not null (i.e. the object is indeed
6775 // an array), jump to label `check_non_primitive_component_type`
6776 // to further check that this component type is not a primitive
6777 // type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006778 __ testl(temp, temp);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006779 // Otherwise, jump to the slow path to throw the exception.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006780 __ j(kZero, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006781 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08006782 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006783 break;
6784 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006785
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006786 case TypeCheckKind::kUnresolvedCheck: {
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006787 // We always go into the type check slow path for the unresolved case.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006788 //
6789 // We cannot directly call the CheckCast runtime entry point
6790 // without resorting to a type checking slow path here (i.e. by
6791 // calling InvokeRuntime directly), as it would require to
6792 // assign fixed registers for the inputs of this HInstanceOf
6793 // instruction (following the runtime calling convention), which
6794 // might be cluttered by the potential first read barrier
6795 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006796 __ jmp(type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07006797 break;
6798 }
6799
Vladimir Marko175e7862018-03-27 09:03:13 +00006800 case TypeCheckKind::kInterfaceCheck: {
Vladimir Markoe619f6c2017-12-12 16:00:01 +00006801 // Fast path for the interface check. Try to avoid read barriers to improve the fast path.
6802 // We can not get false positives by doing this.
6803 // /* HeapReference<Class> */ temp = obj->klass_
6804 GenerateReferenceLoadTwoRegisters(instruction,
6805 temp_loc,
6806 obj_loc,
6807 class_offset,
6808 kWithoutReadBarrier);
Mathieu Chartiercdba73b2016-11-03 19:23:06 -07006809
Vladimir Markoe619f6c2017-12-12 16:00:01 +00006810 // /* HeapReference<Class> */ temp = temp->iftable_
6811 GenerateReferenceLoadTwoRegisters(instruction,
6812 temp_loc,
6813 temp_loc,
6814 iftable_offset,
6815 kWithoutReadBarrier);
6816 // Iftable is never null.
6817 __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
6818 // Maybe poison the `cls` for direct comparison with memory.
6819 __ MaybePoisonHeapReference(cls.AsRegister<CpuRegister>());
6820 // Loop through the iftable and check if any class matches.
6821 NearLabel start_loop;
6822 __ Bind(&start_loop);
6823 // Need to subtract first to handle the empty array case.
6824 __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
6825 __ j(kNegative, type_check_slow_path->GetEntryLabel());
6826 // Go to next interface if the classes do not match.
6827 __ cmpl(cls.AsRegister<CpuRegister>(),
6828 CodeGeneratorX86_64::ArrayAddress(temp,
6829 maybe_temp2_loc,
6830 TIMES_4,
6831 object_array_data_offset));
6832 __ j(kNotEqual, &start_loop); // Return if same class.
6833 // If `cls` was poisoned above, unpoison it.
6834 __ MaybeUnpoisonHeapReference(cls.AsRegister<CpuRegister>());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006835 break;
Vladimir Marko175e7862018-03-27 09:03:13 +00006836 }
6837
6838 case TypeCheckKind::kBitstringCheck: {
6839 // /* HeapReference<Class> */ temp = obj->klass_
6840 GenerateReferenceLoadTwoRegisters(instruction,
6841 temp_loc,
6842 obj_loc,
6843 class_offset,
6844 kWithoutReadBarrier);
6845
6846 GenerateBitstringTypeCheckCompare(instruction, temp);
6847 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
6848 break;
6849 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006850 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006851
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08006852 if (done.IsLinked()) {
6853 __ Bind(&done);
6854 }
6855
Roland Levillain0d5a2812015-11-13 10:07:31 +00006856 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006857}
6858
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006859void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006860 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6861 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006862 InvokeRuntimeCallingConvention calling_convention;
6863 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6864}
6865
6866void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01006867 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
Alexandre Rames8158f282015-08-07 10:26:17 +01006868 instruction,
Serban Constantinescuba45db02016-07-12 22:53:02 +01006869 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006870 if (instruction->IsEnter()) {
6871 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6872 } else {
6873 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6874 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006875}
6876
Shalini Salomi Bodapatidd121f62018-10-26 15:03:53 +05306877void LocationsBuilderX86_64::VisitX86AndNot(HX86AndNot* instruction) {
6878 DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
6879 DCHECK(DataType::IsIntOrLongType(instruction->GetType())) << instruction->GetType();
6880 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6881 locations->SetInAt(0, Location::RequiresRegister());
6882 // There is no immediate variant of negated bitwise and in X86.
6883 locations->SetInAt(1, Location::RequiresRegister());
6884 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6885}
6886
6887void LocationsBuilderX86_64::VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit* instruction) {
6888 DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
6889 DCHECK(DataType::IsIntOrLongType(instruction->GetType())) << instruction->GetType();
6890 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
6891 locations->SetInAt(0, Location::RequiresRegister());
6892 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6893}
6894
6895void InstructionCodeGeneratorX86_64::VisitX86AndNot(HX86AndNot* instruction) {
6896 LocationSummary* locations = instruction->GetLocations();
6897 Location first = locations->InAt(0);
6898 Location second = locations->InAt(1);
6899 Location dest = locations->Out();
6900 __ andn(dest.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
6901}
6902
6903void InstructionCodeGeneratorX86_64::VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit* instruction) {
6904 LocationSummary* locations = instruction->GetLocations();
6905 Location src = locations->InAt(0);
6906 Location dest = locations->Out();
6907 switch (instruction->GetOpKind()) {
6908 case HInstruction::kAnd:
6909 __ blsr(dest.AsRegister<CpuRegister>(), src.AsRegister<CpuRegister>());
6910 break;
6911 case HInstruction::kXor:
6912 __ blsmsk(dest.AsRegister<CpuRegister>(), src.AsRegister<CpuRegister>());
6913 break;
6914 default:
6915 LOG(FATAL) << "Unreachable";
6916 }
6917}
6918
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006919void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
6920void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
6921void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
6922
6923void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6924 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01006925 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006926 DCHECK(instruction->GetResultType() == DataType::Type::kInt32
6927 || instruction->GetResultType() == DataType::Type::kInt64);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006928 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell40741f32015-04-20 22:10:34 -04006929 locations->SetInAt(1, Location::Any());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006930 locations->SetOut(Location::SameAsFirstInput());
6931}
6932
6933void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
6934 HandleBitwiseOperation(instruction);
6935}
6936
6937void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
6938 HandleBitwiseOperation(instruction);
6939}
6940
6941void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
6942 HandleBitwiseOperation(instruction);
6943}
6944
6945void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
6946 LocationSummary* locations = instruction->GetLocations();
6947 Location first = locations->InAt(0);
6948 Location second = locations->InAt(1);
6949 DCHECK(first.Equals(locations->Out()));
6950
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006951 if (instruction->GetResultType() == DataType::Type::kInt32) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006952 if (second.IsRegister()) {
6953 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006954 __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006955 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006956 __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006957 } else {
6958 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006959 __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006960 }
6961 } else if (second.IsConstant()) {
6962 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
6963 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006964 __ andl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006965 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006966 __ orl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006967 } else {
6968 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006969 __ xorl(first.AsRegister<CpuRegister>(), imm);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006970 }
6971 } else {
6972 Address address(CpuRegister(RSP), second.GetStackIndex());
6973 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006974 __ andl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006975 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006976 __ orl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006977 } else {
6978 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006979 __ xorl(first.AsRegister<CpuRegister>(), address);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006980 }
6981 }
6982 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006983 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006984 CpuRegister first_reg = first.AsRegister<CpuRegister>();
6985 bool second_is_constant = false;
6986 int64_t value = 0;
6987 if (second.IsConstant()) {
6988 second_is_constant = true;
6989 value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006990 }
Mark Mendell40741f32015-04-20 22:10:34 -04006991 bool is_int32_value = IsInt<32>(value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006992
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006993 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006994 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04006995 if (is_int32_value) {
6996 __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
6997 } else {
6998 __ andq(first_reg, codegen_->LiteralInt64Address(value));
6999 }
7000 } else if (second.IsDoubleStackSlot()) {
7001 __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04007002 } else {
7003 __ andq(first_reg, second.AsRegister<CpuRegister>());
7004 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007005 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04007006 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04007007 if (is_int32_value) {
7008 __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
7009 } else {
7010 __ orq(first_reg, codegen_->LiteralInt64Address(value));
7011 }
7012 } else if (second.IsDoubleStackSlot()) {
7013 __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04007014 } else {
7015 __ orq(first_reg, second.AsRegister<CpuRegister>());
7016 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007017 } else {
7018 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04007019 if (second_is_constant) {
Mark Mendell40741f32015-04-20 22:10:34 -04007020 if (is_int32_value) {
7021 __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
7022 } else {
7023 __ xorq(first_reg, codegen_->LiteralInt64Address(value));
7024 }
7025 } else if (second.IsDoubleStackSlot()) {
7026 __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
Mark Mendell3f6c7f62015-03-13 13:47:53 -04007027 } else {
7028 __ xorq(first_reg, second.AsRegister<CpuRegister>());
7029 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007030 }
7031 }
7032}
7033
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007034void InstructionCodeGeneratorX86_64::GenerateReferenceLoadOneRegister(
7035 HInstruction* instruction,
7036 Location out,
7037 uint32_t offset,
7038 Location maybe_temp,
7039 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007040 CpuRegister out_reg = out.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007041 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007042 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007043 if (kUseBakerReadBarrier) {
7044 // Load with fast path based Baker's read barrier.
7045 // /* HeapReference<Object> */ out = *(out + offset)
7046 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08007047 instruction, out, out_reg, offset, /* needs_null_check= */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007048 } else {
7049 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007050 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007051 // in the following move operation, as we will need it for the
7052 // read barrier below.
Vladimir Marko953437b2016-08-24 08:30:46 +00007053 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007054 __ movl(maybe_temp.AsRegister<CpuRegister>(), out_reg);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007055 // /* HeapReference<Object> */ out = *(out + offset)
7056 __ movl(out_reg, Address(out_reg, offset));
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007057 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007058 }
7059 } else {
7060 // Plain load with no read barrier.
7061 // /* HeapReference<Object> */ out = *(out + offset)
7062 __ movl(out_reg, Address(out_reg, offset));
7063 __ MaybeUnpoisonHeapReference(out_reg);
7064 }
7065}
7066
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007067void InstructionCodeGeneratorX86_64::GenerateReferenceLoadTwoRegisters(
7068 HInstruction* instruction,
7069 Location out,
7070 Location obj,
7071 uint32_t offset,
7072 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007073 CpuRegister out_reg = out.AsRegister<CpuRegister>();
7074 CpuRegister obj_reg = obj.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007075 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007076 CHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007077 if (kUseBakerReadBarrier) {
7078 // Load with fast path based Baker's read barrier.
7079 // /* HeapReference<Object> */ out = *(obj + offset)
7080 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08007081 instruction, out, obj_reg, offset, /* needs_null_check= */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007082 } else {
7083 // Load with slow path based read barrier.
7084 // /* HeapReference<Object> */ out = *(obj + offset)
7085 __ movl(out_reg, Address(obj_reg, offset));
7086 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
7087 }
7088 } else {
7089 // Plain load with no read barrier.
7090 // /* HeapReference<Object> */ out = *(obj + offset)
7091 __ movl(out_reg, Address(obj_reg, offset));
7092 __ MaybeUnpoisonHeapReference(out_reg);
7093 }
7094}
7095
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007096void InstructionCodeGeneratorX86_64::GenerateGcRootFieldLoad(
7097 HInstruction* instruction,
7098 Location root,
7099 const Address& address,
7100 Label* fixup_label,
7101 ReadBarrierOption read_barrier_option) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007102 CpuRegister root_reg = root.AsRegister<CpuRegister>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007103 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007104 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007105 if (kUseBakerReadBarrier) {
7106 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
7107 // Baker's read barrier are used:
7108 //
Roland Levillaind966ce72017-02-09 16:20:14 +00007109 // root = obj.field;
7110 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
7111 // if (temp != null) {
7112 // root = temp(root)
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007113 // }
7114
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007115 // /* GcRoot<mirror::Object> */ root = *address
7116 __ movl(root_reg, address);
7117 if (fixup_label != nullptr) {
7118 __ Bind(fixup_label);
7119 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007120 static_assert(
7121 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
7122 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
7123 "have different sizes.");
7124 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
7125 "art::mirror::CompressedReference<mirror::Object> and int32_t "
7126 "have different sizes.");
7127
Vladimir Marko953437b2016-08-24 08:30:46 +00007128 // Slow path marking the GC root `root`.
Vladimir Marko174b2e22017-10-12 13:34:49 +01007129 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) ReadBarrierMarkSlowPathX86_64(
Andreas Gampe3db70682018-12-26 15:12:03 -08007130 instruction, root, /* unpoison_ref_before_marking= */ false);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007131 codegen_->AddSlowPath(slow_path);
7132
Roland Levillaind966ce72017-02-09 16:20:14 +00007133 // Test the `Thread::Current()->pReadBarrierMarkReg ## root.reg()` entrypoint.
7134 const int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +01007135 Thread::ReadBarrierMarkEntryPointsOffset<kX86_64PointerSize>(root.reg());
Andreas Gampe3db70682018-12-26 15:12:03 -08007136 __ gs()->cmpl(Address::Absolute(entry_point_offset, /* no_rip= */ true), Immediate(0));
Roland Levillaind966ce72017-02-09 16:20:14 +00007137 // The entrypoint is null when the GC is not marking.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007138 __ j(kNotEqual, slow_path->GetEntryLabel());
7139 __ Bind(slow_path->GetExitLabel());
7140 } else {
7141 // GC root loaded through a slow path for read barriers other
7142 // than Baker's.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007143 // /* GcRoot<mirror::Object>* */ root = address
7144 __ leaq(root_reg, address);
7145 if (fixup_label != nullptr) {
7146 __ Bind(fixup_label);
7147 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007148 // /* mirror::Object* */ root = root->Read()
7149 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
7150 }
7151 } else {
7152 // Plain GC root load with no read barrier.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007153 // /* GcRoot<mirror::Object> */ root = *address
7154 __ movl(root_reg, address);
7155 if (fixup_label != nullptr) {
7156 __ Bind(fixup_label);
7157 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007158 // Note that GC roots are not affected by heap poisoning, thus we
7159 // do not have to unpoison `root_reg` here.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007160 }
7161}
7162
7163void CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7164 Location ref,
7165 CpuRegister obj,
7166 uint32_t offset,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007167 bool needs_null_check) {
7168 DCHECK(kEmitCompilerReadBarrier);
7169 DCHECK(kUseBakerReadBarrier);
7170
7171 // /* HeapReference<Object> */ ref = *(obj + offset)
7172 Address src(obj, offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00007173 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007174}
7175
7176void CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
7177 Location ref,
7178 CpuRegister obj,
7179 uint32_t data_offset,
7180 Location index,
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007181 bool needs_null_check) {
7182 DCHECK(kEmitCompilerReadBarrier);
7183 DCHECK(kUseBakerReadBarrier);
7184
Roland Levillain3d312422016-06-23 13:53:42 +01007185 static_assert(
7186 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
7187 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007188 // /* HeapReference<Object> */ ref =
7189 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007190 Address src = CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00007191 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007192}
7193
7194void CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
7195 Location ref,
7196 CpuRegister obj,
7197 const Address& src,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007198 bool needs_null_check,
7199 bool always_update_field,
7200 CpuRegister* temp1,
7201 CpuRegister* temp2) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007202 DCHECK(kEmitCompilerReadBarrier);
7203 DCHECK(kUseBakerReadBarrier);
7204
7205 // In slow path based read barriers, the read barrier call is
7206 // inserted after the original load. However, in fast path based
7207 // Baker's read barriers, we need to perform the load of
7208 // mirror::Object::monitor_ *before* the original reference load.
7209 // This load-load ordering is required by the read barrier.
7210 // The fast path/slow path (for Baker's algorithm) should look like:
7211 //
7212 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
7213 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
7214 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007215 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007216 // if (is_gray) {
7217 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
7218 // }
7219 //
7220 // Note: the original implementation in ReadBarrier::Barrier is
7221 // slightly more complex as:
7222 // - it implements the load-load fence using a data dependency on
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007223 // the high-bits of rb_state, which are expected to be all zeroes
7224 // (we use CodeGeneratorX86_64::GenerateMemoryBarrier instead
7225 // here, which is a no-op thanks to the x86-64 memory model);
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007226 // - it performs additional checks that we do not do here for
7227 // performance reasons.
7228
7229 CpuRegister ref_reg = ref.AsRegister<CpuRegister>();
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007230 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7231
Vladimir Marko953437b2016-08-24 08:30:46 +00007232 // Given the numeric representation, it's enough to check the low bit of the rb_state.
Roland Levillain14e5a292018-06-28 12:00:56 +01007233 static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007234 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko953437b2016-08-24 08:30:46 +00007235 constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
7236 constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
7237 constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
7238
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07007239 // if (rb_state == ReadBarrier::GrayState())
Vladimir Marko953437b2016-08-24 08:30:46 +00007240 // ref = ReadBarrier::Mark(ref);
7241 // At this point, just do the "if" and make sure that flags are preserved until the branch.
7242 __ testb(Address(obj, monitor_offset + gray_byte_position), Immediate(test_value));
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007243 if (needs_null_check) {
7244 MaybeRecordImplicitNullCheck(instruction);
7245 }
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007246
7247 // Load fence to prevent load-load reordering.
7248 // Note that this is a no-op, thanks to the x86-64 memory model.
7249 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
7250
7251 // The actual reference load.
7252 // /* HeapReference<Object> */ ref = *src
Vladimir Marko953437b2016-08-24 08:30:46 +00007253 __ movl(ref_reg, src); // Flags are unaffected.
7254
7255 // Note: Reference unpoisoning modifies the flags, so we need to delay it after the branch.
7256 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007257 SlowPathCode* slow_path;
7258 if (always_update_field) {
7259 DCHECK(temp1 != nullptr);
7260 DCHECK(temp2 != nullptr);
Vladimir Marko174b2e22017-10-12 13:34:49 +01007261 slow_path = new (GetScopedAllocator()) ReadBarrierMarkAndUpdateFieldSlowPathX86_64(
Andreas Gampe3db70682018-12-26 15:12:03 -08007262 instruction, ref, obj, src, /* unpoison_ref_before_marking= */ true, *temp1, *temp2);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007263 } else {
Vladimir Marko174b2e22017-10-12 13:34:49 +01007264 slow_path = new (GetScopedAllocator()) ReadBarrierMarkSlowPathX86_64(
Andreas Gampe3db70682018-12-26 15:12:03 -08007265 instruction, ref, /* unpoison_ref_before_marking= */ true);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01007266 }
Vladimir Marko953437b2016-08-24 08:30:46 +00007267 AddSlowPath(slow_path);
7268
7269 // We have done the "if" of the gray bit check above, now branch based on the flags.
7270 __ j(kNotZero, slow_path->GetEntryLabel());
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007271
7272 // Object* ref = ref_addr->AsMirrorPtr()
7273 __ MaybeUnpoisonHeapReference(ref_reg);
7274
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007275 __ Bind(slow_path->GetExitLabel());
7276}
7277
7278void CodeGeneratorX86_64::GenerateReadBarrierSlow(HInstruction* instruction,
7279 Location out,
7280 Location ref,
7281 Location obj,
7282 uint32_t offset,
7283 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00007284 DCHECK(kEmitCompilerReadBarrier);
7285
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007286 // Insert a slow path based read barrier *after* the reference load.
7287 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00007288 // If heap poisoning is enabled, the unpoisoning of the loaded
7289 // reference will be carried out by the runtime within the slow
7290 // path.
7291 //
7292 // Note that `ref` currently does not get unpoisoned (when heap
7293 // poisoning is enabled), which is alright as the `ref` argument is
7294 // not used by the artReadBarrierSlow entry point.
7295 //
7296 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Vladimir Marko174b2e22017-10-12 13:34:49 +01007297 SlowPathCode* slow_path = new (GetScopedAllocator())
Roland Levillain0d5a2812015-11-13 10:07:31 +00007298 ReadBarrierForHeapReferenceSlowPathX86_64(instruction, out, ref, obj, offset, index);
7299 AddSlowPath(slow_path);
7300
Roland Levillain0d5a2812015-11-13 10:07:31 +00007301 __ jmp(slow_path->GetEntryLabel());
7302 __ Bind(slow_path->GetExitLabel());
7303}
7304
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007305void CodeGeneratorX86_64::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7306 Location out,
7307 Location ref,
7308 Location obj,
7309 uint32_t offset,
7310 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00007311 if (kEmitCompilerReadBarrier) {
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007312 // Baker's read barriers shall be handled by the fast path
7313 // (CodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier).
7314 DCHECK(!kUseBakerReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007315 // If heap poisoning is enabled, unpoisoning will be taken care of
7316 // by the runtime within the slow path.
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007317 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007318 } else if (kPoisonHeapReferences) {
7319 __ UnpoisonHeapReference(out.AsRegister<CpuRegister>());
7320 }
7321}
7322
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007323void CodeGeneratorX86_64::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7324 Location out,
7325 Location root) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00007326 DCHECK(kEmitCompilerReadBarrier);
7327
Roland Levillain1e7f8db2015-12-15 10:54:19 +00007328 // Insert a slow path based read barrier *after* the GC root load.
7329 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00007330 // Note that GC roots are not affected by heap poisoning, so we do
7331 // not need to do anything special for this here.
7332 SlowPathCode* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01007333 new (GetScopedAllocator()) ReadBarrierForRootSlowPathX86_64(instruction, out, root);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007334 AddSlowPath(slow_path);
7335
Roland Levillain0d5a2812015-11-13 10:07:31 +00007336 __ jmp(slow_path->GetEntryLabel());
7337 __ Bind(slow_path->GetExitLabel());
7338}
7339
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007340void LocationsBuilderX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007341 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007342 LOG(FATAL) << "Unreachable";
7343}
7344
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01007345void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00007346 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00007347 LOG(FATAL) << "Unreachable";
7348}
7349
Mark Mendellfe57faa2015-09-18 09:26:15 -04007350// Simple implementation of packed switch - generate cascaded compare/jumps.
7351void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7352 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01007353 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Mark Mendellfe57faa2015-09-18 09:26:15 -04007354 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell9c86b482015-09-18 13:36:07 -04007355 locations->AddTemp(Location::RequiresRegister());
7356 locations->AddTemp(Location::RequiresRegister());
Mark Mendellfe57faa2015-09-18 09:26:15 -04007357}
7358
7359void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7360 int32_t lower_bound = switch_instr->GetStartValue();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007361 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04007362 LocationSummary* locations = switch_instr->GetLocations();
Mark Mendell9c86b482015-09-18 13:36:07 -04007363 CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
7364 CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
7365 CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007366 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7367
7368 // Should we generate smaller inline compare/jumps?
7369 if (num_entries <= kPackedSwitchJumpTableThreshold) {
7370 // Figure out the correct compare values and jump conditions.
7371 // Handle the first compare/branch as a special case because it might
7372 // jump to the default case.
7373 DCHECK_GT(num_entries, 2u);
7374 Condition first_condition;
7375 uint32_t index;
7376 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7377 if (lower_bound != 0) {
7378 first_condition = kLess;
7379 __ cmpl(value_reg_in, Immediate(lower_bound));
7380 __ j(first_condition, codegen_->GetLabelOf(default_block));
7381 __ j(kEqual, codegen_->GetLabelOf(successors[0]));
7382
7383 index = 1;
7384 } else {
7385 // Handle all the compare/jumps below.
7386 first_condition = kBelow;
7387 index = 0;
7388 }
7389
7390 // Handle the rest of the compare/jumps.
7391 for (; index + 1 < num_entries; index += 2) {
7392 int32_t compare_to_value = lower_bound + index + 1;
7393 __ cmpl(value_reg_in, Immediate(compare_to_value));
7394 // Jump to successors[index] if value < case_value[index].
7395 __ j(first_condition, codegen_->GetLabelOf(successors[index]));
7396 // Jump to successors[index + 1] if value == case_value[index + 1].
7397 __ j(kEqual, codegen_->GetLabelOf(successors[index + 1]));
7398 }
7399
7400 if (index != num_entries) {
7401 // There are an odd number of entries. Handle the last one.
7402 DCHECK_EQ(index + 1, num_entries);
Nicolas Geoffray6ce01732015-12-30 14:10:13 +00007403 __ cmpl(value_reg_in, Immediate(static_cast<int32_t>(lower_bound + index)));
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007404 __ j(kEqual, codegen_->GetLabelOf(successors[index]));
7405 }
7406
7407 // And the default for any other value.
7408 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7409 __ jmp(codegen_->GetLabelOf(default_block));
7410 }
7411 return;
7412 }
Mark Mendell9c86b482015-09-18 13:36:07 -04007413
7414 // Remove the bias, if needed.
7415 Register value_reg_out = value_reg_in.AsRegister();
7416 if (lower_bound != 0) {
7417 __ leal(temp_reg, Address(value_reg_in, -lower_bound));
7418 value_reg_out = temp_reg.AsRegister();
7419 }
7420 CpuRegister value_reg(value_reg_out);
7421
7422 // Is the value in range?
Mark Mendell9c86b482015-09-18 13:36:07 -04007423 __ cmpl(value_reg, Immediate(num_entries - 1));
7424 __ j(kAbove, codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04007425
Mark Mendell9c86b482015-09-18 13:36:07 -04007426 // We are in the range of the table.
7427 // Load the address of the jump table in the constant area.
7428 __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
Mark Mendellfe57faa2015-09-18 09:26:15 -04007429
Mark Mendell9c86b482015-09-18 13:36:07 -04007430 // Load the (signed) offset from the jump table.
7431 __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
7432
7433 // Add the offset to the address of the table base.
7434 __ addq(temp_reg, base_reg);
7435
7436 // And jump.
7437 __ jmp(temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04007438}
7439
xueliang.zhonge0eb4832017-10-30 13:43:14 +00007440void LocationsBuilderX86_64::VisitIntermediateAddress(HIntermediateAddress* instruction
7441 ATTRIBUTE_UNUSED) {
7442 LOG(FATAL) << "Unreachable";
7443}
7444
7445void InstructionCodeGeneratorX86_64::VisitIntermediateAddress(HIntermediateAddress* instruction
7446 ATTRIBUTE_UNUSED) {
7447 LOG(FATAL) << "Unreachable";
7448}
7449
Aart Bikc5d47542016-01-27 17:00:35 -08007450void CodeGeneratorX86_64::Load32BitValue(CpuRegister dest, int32_t value) {
7451 if (value == 0) {
7452 __ xorl(dest, dest);
7453 } else {
7454 __ movl(dest, Immediate(value));
7455 }
7456}
7457
Mark Mendell92e83bf2015-05-07 11:25:03 -04007458void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
7459 if (value == 0) {
Aart Bikc5d47542016-01-27 17:00:35 -08007460 // Clears upper bits too.
Mark Mendell92e83bf2015-05-07 11:25:03 -04007461 __ xorl(dest, dest);
Vladimir Markoed009782016-02-22 16:54:39 +00007462 } else if (IsUint<32>(value)) {
7463 // We can use a 32 bit move, as it will zero-extend and is shorter.
Mark Mendell92e83bf2015-05-07 11:25:03 -04007464 __ movl(dest, Immediate(static_cast<int32_t>(value)));
7465 } else {
7466 __ movq(dest, Immediate(value));
7467 }
7468}
7469
Mark Mendell7c0b44f2016-02-01 10:08:35 -05007470void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, int32_t value) {
7471 if (value == 0) {
7472 __ xorps(dest, dest);
7473 } else {
7474 __ movss(dest, LiteralInt32Address(value));
7475 }
7476}
7477
7478void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, int64_t value) {
7479 if (value == 0) {
7480 __ xorpd(dest, dest);
7481 } else {
7482 __ movsd(dest, LiteralInt64Address(value));
7483 }
7484}
7485
7486void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, float value) {
7487 Load32BitValue(dest, bit_cast<int32_t, float>(value));
7488}
7489
7490void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, double value) {
7491 Load64BitValue(dest, bit_cast<int64_t, double>(value));
7492}
7493
Aart Bika19616e2016-02-01 18:57:58 -08007494void CodeGeneratorX86_64::Compare32BitValue(CpuRegister dest, int32_t value) {
7495 if (value == 0) {
7496 __ testl(dest, dest);
7497 } else {
7498 __ cmpl(dest, Immediate(value));
7499 }
7500}
7501
7502void CodeGeneratorX86_64::Compare64BitValue(CpuRegister dest, int64_t value) {
7503 if (IsInt<32>(value)) {
7504 if (value == 0) {
7505 __ testq(dest, dest);
7506 } else {
7507 __ cmpq(dest, Immediate(static_cast<int32_t>(value)));
7508 }
7509 } else {
7510 // Value won't fit in an int.
7511 __ cmpq(dest, LiteralInt64Address(value));
7512 }
7513}
7514
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007515void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
7516 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
jessicahandojo4877b792016-09-08 19:49:13 -07007517 GenerateIntCompare(lhs_reg, rhs);
7518}
7519
7520void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007521 if (rhs.IsConstant()) {
7522 int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
jessicahandojo4877b792016-09-08 19:49:13 -07007523 Compare32BitValue(lhs, value);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007524 } else if (rhs.IsStackSlot()) {
jessicahandojo4877b792016-09-08 19:49:13 -07007525 __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007526 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07007527 __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01007528 }
7529}
7530
7531void CodeGeneratorX86_64::GenerateLongCompare(Location lhs, Location rhs) {
7532 CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
7533 if (rhs.IsConstant()) {
7534 int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
7535 Compare64BitValue(lhs_reg, value);
7536 } else if (rhs.IsDoubleStackSlot()) {
7537 __ cmpq(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
7538 } else {
7539 __ cmpq(lhs_reg, rhs.AsRegister<CpuRegister>());
7540 }
7541}
7542
7543Address CodeGeneratorX86_64::ArrayAddress(CpuRegister obj,
7544 Location index,
7545 ScaleFactor scale,
7546 uint32_t data_offset) {
7547 return index.IsConstant() ?
7548 Address(obj, (index.GetConstant()->AsIntConstant()->GetValue() << scale) + data_offset) :
7549 Address(obj, index.AsRegister<CpuRegister>(), scale, data_offset);
7550}
7551
Mark Mendellcfa410b2015-05-25 16:02:44 -04007552void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
7553 DCHECK(dest.IsDoubleStackSlot());
7554 if (IsInt<32>(value)) {
7555 // Can move directly as an int32 constant.
7556 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()),
7557 Immediate(static_cast<int32_t>(value)));
7558 } else {
7559 Load64BitValue(CpuRegister(TMP), value);
7560 __ movq(Address(CpuRegister(RSP), dest.GetStackIndex()), CpuRegister(TMP));
7561 }
7562}
7563
Mark Mendell9c86b482015-09-18 13:36:07 -04007564/**
7565 * Class to handle late fixup of offsets into constant area.
7566 */
7567class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
7568 public:
7569 RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
7570 : codegen_(&codegen), offset_into_constant_area_(offset) {}
7571
7572 protected:
7573 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
7574
7575 CodeGeneratorX86_64* codegen_;
7576
7577 private:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +01007578 void Process(const MemoryRegion& region, int pos) override {
Mark Mendell9c86b482015-09-18 13:36:07 -04007579 // Patch the correct offset for the instruction. We use the address of the
7580 // 'next' instruction, which is 'pos' (patch the 4 bytes before).
7581 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
7582 int32_t relative_position = constant_offset - pos;
7583
7584 // Patch in the right value.
7585 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
7586 }
7587
7588 // Location in constant area that the fixup refers to.
7589 size_t offset_into_constant_area_;
7590};
7591
7592/**
7593 t * Class to handle late fixup of offsets to a jump table that will be created in the
7594 * constant area.
7595 */
7596class JumpTableRIPFixup : public RIPFixup {
7597 public:
7598 JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
7599 : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
7600
7601 void CreateJumpTable() {
7602 X86_64Assembler* assembler = codegen_->GetAssembler();
7603
7604 // Ensure that the reference to the jump table has the correct offset.
7605 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
7606 SetOffset(offset_in_constant_table);
7607
7608 // Compute the offset from the start of the function to this jump table.
7609 const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
7610
7611 // Populate the jump table with the correct values for the jump table.
7612 int32_t num_entries = switch_instr_->GetNumEntries();
7613 HBasicBlock* block = switch_instr_->GetBlock();
7614 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
7615 // The value that we want is the target offset - the position of the table.
7616 for (int32_t i = 0; i < num_entries; i++) {
7617 HBasicBlock* b = successors[i];
7618 Label* l = codegen_->GetLabelOf(b);
7619 DCHECK(l->IsBound());
7620 int32_t offset_to_block = l->Position() - current_table_offset;
7621 assembler->AppendInt32(offset_to_block);
7622 }
7623 }
7624
7625 private:
7626 const HPackedSwitch* switch_instr_;
7627};
7628
Mark Mendellf55c3e02015-03-26 21:07:46 -04007629void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
7630 // Generate the constant area if needed.
Mark Mendell39dcf552015-04-09 20:42:42 -04007631 X86_64Assembler* assembler = GetAssembler();
Mark Mendell9c86b482015-09-18 13:36:07 -04007632 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
7633 // 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 -04007634 assembler->Align(4, 0);
7635 constant_area_start_ = assembler->CodeSize();
Mark Mendell9c86b482015-09-18 13:36:07 -04007636
7637 // Populate any jump tables.
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007638 for (JumpTableRIPFixup* jump_table : fixups_to_jump_tables_) {
Mark Mendell9c86b482015-09-18 13:36:07 -04007639 jump_table->CreateJumpTable();
7640 }
7641
7642 // And now add the constant area to the generated code.
Mark Mendell39dcf552015-04-09 20:42:42 -04007643 assembler->AddConstantArea();
Mark Mendellf55c3e02015-03-26 21:07:46 -04007644 }
7645
7646 // And finish up.
7647 CodeGenerator::Finalize(allocator);
7648}
7649
Mark Mendellf55c3e02015-03-26 21:07:46 -04007650Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007651 AssemblerFixup* fixup = new (GetGraph()->GetAllocator()) RIPFixup(*this, __ AddDouble(v));
Mark Mendellf55c3e02015-03-26 21:07:46 -04007652 return Address::RIP(fixup);
7653}
7654
7655Address CodeGeneratorX86_64::LiteralFloatAddress(float v) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007656 AssemblerFixup* fixup = new (GetGraph()->GetAllocator()) RIPFixup(*this, __ AddFloat(v));
Mark Mendellf55c3e02015-03-26 21:07:46 -04007657 return Address::RIP(fixup);
7658}
7659
7660Address CodeGeneratorX86_64::LiteralInt32Address(int32_t v) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007661 AssemblerFixup* fixup = new (GetGraph()->GetAllocator()) RIPFixup(*this, __ AddInt32(v));
Mark Mendellf55c3e02015-03-26 21:07:46 -04007662 return Address::RIP(fixup);
7663}
7664
7665Address CodeGeneratorX86_64::LiteralInt64Address(int64_t v) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007666 AssemblerFixup* fixup = new (GetGraph()->GetAllocator()) RIPFixup(*this, __ AddInt64(v));
Mark Mendellf55c3e02015-03-26 21:07:46 -04007667 return Address::RIP(fixup);
7668}
7669
Andreas Gampe85b62f22015-09-09 13:15:38 -07007670// TODO: trg as memory.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01007671void CodeGeneratorX86_64::MoveFromReturnRegister(Location trg, DataType::Type type) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07007672 if (!trg.IsValid()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01007673 DCHECK_EQ(type, DataType::Type::kVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007674 return;
7675 }
7676
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01007677 DCHECK_NE(type, DataType::Type::kVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007678
7679 Location return_loc = InvokeDexCallingConventionVisitorX86_64().GetReturnLocation(type);
7680 if (trg.Equals(return_loc)) {
7681 return;
7682 }
7683
7684 // Let the parallel move resolver take care of all of this.
Vladimir Markoca6fff82017-10-03 14:49:14 +01007685 HParallelMove parallel_move(GetGraph()->GetAllocator());
Andreas Gampe85b62f22015-09-09 13:15:38 -07007686 parallel_move.AddMove(return_loc, trg, type, nullptr);
7687 GetMoveResolver()->EmitNativeCode(&parallel_move);
7688}
7689
Mark Mendell9c86b482015-09-18 13:36:07 -04007690Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
7691 // Create a fixup to be used to create and address the jump table.
7692 JumpTableRIPFixup* table_fixup =
Vladimir Markoca6fff82017-10-03 14:49:14 +01007693 new (GetGraph()->GetAllocator()) JumpTableRIPFixup(*this, switch_instr);
Mark Mendell9c86b482015-09-18 13:36:07 -04007694
7695 // We have to populate the jump tables.
7696 fixups_to_jump_tables_.push_back(table_fixup);
7697 return Address::RIP(table_fixup);
7698}
7699
Mark Mendellea5af682015-10-22 17:35:49 -04007700void CodeGeneratorX86_64::MoveInt64ToAddress(const Address& addr_low,
7701 const Address& addr_high,
7702 int64_t v,
7703 HInstruction* instruction) {
7704 if (IsInt<32>(v)) {
7705 int32_t v_32 = v;
7706 __ movq(addr_low, Immediate(v_32));
7707 MaybeRecordImplicitNullCheck(instruction);
7708 } else {
7709 // Didn't fit in a register. Do it in pieces.
7710 int32_t low_v = Low32Bits(v);
7711 int32_t high_v = High32Bits(v);
7712 __ movl(addr_low, Immediate(low_v));
7713 MaybeRecordImplicitNullCheck(instruction);
7714 __ movl(addr_high, Immediate(high_v));
7715 }
7716}
7717
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007718void CodeGeneratorX86_64::PatchJitRootUse(uint8_t* code,
7719 const uint8_t* roots_data,
7720 const PatchInfo<Label>& info,
7721 uint64_t index_in_table) const {
7722 uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
7723 uintptr_t address =
7724 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
Andreas Gampec55bb392018-09-21 00:02:02 +00007725 using unaligned_uint32_t __attribute__((__aligned__(1))) = uint32_t;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007726 reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
7727 dchecked_integral_cast<uint32_t>(address);
7728}
7729
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007730void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7731 for (const PatchInfo<Label>& info : jit_string_patches_) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007732 StringReference string_reference(info.target_dex_file, dex::StringIndex(info.offset_or_index));
Vladimir Marko174b2e22017-10-12 13:34:49 +01007733 uint64_t index_in_table = GetJitStringRootIndex(string_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007734 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007735 }
7736
7737 for (const PatchInfo<Label>& info : jit_class_patches_) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007738 TypeReference type_reference(info.target_dex_file, dex::TypeIndex(info.offset_or_index));
Vladimir Marko174b2e22017-10-12 13:34:49 +01007739 uint64_t index_in_table = GetJitClassRootIndex(type_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01007740 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007741 }
7742}
7743
Shalini Salomi Bodapatib45a4352019-07-10 16:09:41 +05307744bool LocationsBuilderX86_64::CpuHasAvxFeatureFlag() {
7745 return codegen_->GetInstructionSetFeatures().HasAVX();
7746}
7747
7748bool LocationsBuilderX86_64::CpuHasAvx2FeatureFlag() {
7749 return codegen_->GetInstructionSetFeatures().HasAVX2();
7750}
7751
7752bool InstructionCodeGeneratorX86_64::CpuHasAvxFeatureFlag() {
7753 return codegen_->GetInstructionSetFeatures().HasAVX();
7754}
7755
7756bool InstructionCodeGeneratorX86_64::CpuHasAvx2FeatureFlag() {
7757 return codegen_->GetInstructionSetFeatures().HasAVX2();
7758}
7759
Roland Levillain4d027112015-07-01 15:41:14 +01007760#undef __
7761
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01007762} // namespace x86_64
7763} // namespace art