blob: a04b4129a851974d553a08c2d3173ad9d0a3a013 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010018
Vladimir Marko86c87522020-05-11 16:55:55 +010019#include "arch/x86/jni_frame_x86.h"
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000020#include "art_method-inl.h"
Vladimir Marko94ec2db2017-09-06 17:21:03 +010021#include "class_table.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010022#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000023#include "compiled_method.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010024#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000025#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010026#include "gc/accounting/card_table.h"
Vladimir Markoeebb8212018-06-05 14:57:24 +010027#include "gc/space/image_space.h"
Andreas Gampe09659c22017-09-18 18:23:32 -070028#include "heap_poisoning.h"
Nicolas Geoffray8b8d93d2020-09-17 14:30:01 +010029#include "interpreter/mterp/nterp.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040030#include "intrinsics.h"
31#include "intrinsics_x86.h"
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000032#include "jit/profiling_info.h"
Vladimir Markod8dbc8d2017-09-20 13:37:47 +010033#include "linker/linker_patch.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070034#include "lock_word.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070035#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070036#include "mirror/class-inl.h"
Andra Danciu52d2c0c2020-09-15 14:27:21 +000037#include "mirror/var_handle.h"
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +000038#include "scoped_thread_state_change-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010039#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010041#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000042#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010043#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000044
Vladimir Marko0a516052019-10-14 13:00:44 +000045namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010046
Roland Levillain0d5a2812015-11-13 10:07:31 +000047template<class MirrorType>
48class GcRoot;
49
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000050namespace x86 {
51
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010052static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010053static constexpr Register kMethodRegisterArgument = EAX;
Mark Mendell5f874182015-03-04 15:42:45 -050054static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010055
Mark Mendell24f2dfa2015-01-14 19:51:45 -050056static constexpr int kC2ConditionMask = 0x400;
57
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000058static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000059
Aart Bik1f8d51b2018-02-15 10:42:37 -080060static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000);
61static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000);
62
Vladimir Marko3232dbb2018-07-25 15:42:46 +010063static RegisterSet OneRegInReferenceOutSaveEverythingCallerSaves() {
64 InvokeRuntimeCallingConvention calling_convention;
65 RegisterSet caller_saves = RegisterSet::Empty();
66 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
67 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
68 // that the the kPrimNot result register is the same as the first argument register.
69 return caller_saves;
70}
71
Roland Levillain7cbd27f2016-08-11 23:53:33 +010072// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
73#define __ down_cast<X86Assembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070074#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86PointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075
Andreas Gampe85b62f22015-09-09 13:15:38 -070076class NullCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000078 explicit NullCheckSlowPathX86(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010079
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010080 void EmitNativeCode(CodeGenerator* codegen) override {
Alexandre Rames8158f282015-08-07 10:26:17 +010081 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010082 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000083 if (instruction_->CanThrowIntoCatchBlock()) {
84 // Live registers will be restored in the catch block if caught.
85 SaveLiveRegisters(codegen, instruction_->GetLocations());
86 }
Serban Constantinescuba45db02016-07-12 22:53:02 +010087 x86_codegen->InvokeRuntime(kQuickThrowNullPointer,
Alexandre Rames8158f282015-08-07 10:26:17 +010088 instruction_,
89 instruction_->GetDexPc(),
90 this);
Roland Levillain888d0672015-11-23 18:53:50 +000091 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010092 }
93
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010094 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +010095
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010096 const char* GetDescription() const override { return "NullCheckSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +010097
Nicolas Geoffraye5038322014-07-04 09:41:32 +010098 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010099 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
100};
101
Andreas Gampe85b62f22015-09-09 13:15:38 -0700102class DivZeroCheckSlowPathX86 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000103 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000104 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000105
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100106 void EmitNativeCode(CodeGenerator* codegen) override {
Alexandre Rames8158f282015-08-07 10:26:17 +0100107 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +0000108 __ Bind(GetEntryLabel());
Serban Constantinescuba45db02016-07-12 22:53:02 +0100109 x86_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000110 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000111 }
112
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100113 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +0100114
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100115 const char* GetDescription() const override { return "DivZeroCheckSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100116
Calin Juravled0d48522014-11-04 16:40:20 +0000117 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000118 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
119};
120
Andreas Gampe85b62f22015-09-09 13:15:38 -0700121class DivRemMinusOneSlowPathX86 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000122 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000123 DivRemMinusOneSlowPathX86(HInstruction* instruction, Register reg, bool is_div)
124 : SlowPathCode(instruction), reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000125
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100126 void EmitNativeCode(CodeGenerator* codegen) override {
Calin Juravled0d48522014-11-04 16:40:20 +0000127 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +0000128 if (is_div_) {
129 __ negl(reg_);
130 } else {
131 __ movl(reg_, Immediate(0));
132 }
Calin Juravled0d48522014-11-04 16:40:20 +0000133 __ jmp(GetExitLabel());
134 }
135
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100136 const char* GetDescription() const override { return "DivRemMinusOneSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100137
Calin Juravled0d48522014-11-04 16:40:20 +0000138 private:
139 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000140 bool is_div_;
141 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +0000142};
143
Andreas Gampe85b62f22015-09-09 13:15:38 -0700144class BoundsCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100145 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000146 explicit BoundsCheckSlowPathX86(HBoundsCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100147
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100148 void EmitNativeCode(CodeGenerator* codegen) override {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100149 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100150 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100151 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000152 // We're moving two locations to locations that could overlap, so we need a parallel
153 // move resolver.
David Brazdil77a48ae2015-09-15 12:34:04 +0000154 if (instruction_->CanThrowIntoCatchBlock()) {
155 // Live registers will be restored in the catch block if caught.
156 SaveLiveRegisters(codegen, instruction_->GetLocations());
157 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400158
159 // Are we using an array length from memory?
160 HInstruction* array_length = instruction_->InputAt(1);
161 Location length_loc = locations->InAt(1);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100162 InvokeRuntimeCallingConvention calling_convention;
Mark Mendellee8d9712016-07-12 11:13:15 -0400163 if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
164 // Load the array length into our temporary.
Nicolas Geoffray0aff3a82017-10-13 13:12:36 +0100165 HArrayLength* length = array_length->AsArrayLength();
166 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
Mark Mendellee8d9712016-07-12 11:13:15 -0400167 Location array_loc = array_length->GetLocations()->InAt(0);
168 Address array_len(array_loc.AsRegister<Register>(), len_offset);
169 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
170 // Check for conflicts with index.
171 if (length_loc.Equals(locations->InAt(0))) {
172 // We know we aren't using parameter 2.
173 length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
174 }
175 __ movl(length_loc.AsRegister<Register>(), array_len);
Nicolas Geoffray0aff3a82017-10-13 13:12:36 +0100176 if (mirror::kUseStringCompression && length->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +0100177 __ shrl(length_loc.AsRegister<Register>(), Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -0700178 }
Mark Mendellee8d9712016-07-12 11:13:15 -0400179 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000180 x86_codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100181 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000182 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100183 DataType::Type::kInt32,
Mark Mendellee8d9712016-07-12 11:13:15 -0400184 length_loc,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100185 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100186 DataType::Type::kInt32);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100187 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
188 ? kQuickThrowStringBounds
189 : kQuickThrowArrayBounds;
190 x86_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100191 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000192 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100193 }
194
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100195 bool IsFatal() const override { return true; }
Alexandre Rames8158f282015-08-07 10:26:17 +0100196
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100197 const char* GetDescription() const override { return "BoundsCheckSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100198
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100199 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100200 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
201};
202
Andreas Gampe85b62f22015-09-09 13:15:38 -0700203class SuspendCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000204 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000205 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000206 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000207
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100208 void EmitNativeCode(CodeGenerator* codegen) override {
Aart Bikb13c65b2017-03-21 20:14:07 -0700209 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100210 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000211 __ Bind(GetEntryLabel());
Aart Bik24b905f2017-04-06 09:59:06 -0700212 SaveLiveRegisters(codegen, locations); // Only saves full width XMM for SIMD.
Serban Constantinescuba45db02016-07-12 22:53:02 +0100213 x86_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000214 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Aart Bik24b905f2017-04-06 09:59:06 -0700215 RestoreLiveRegisters(codegen, locations); // Only restores full width XMM for SIMD.
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100216 if (successor_ == nullptr) {
217 __ jmp(GetReturnLabel());
218 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100219 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100220 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000221 }
222
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100223 Label* GetReturnLabel() {
224 DCHECK(successor_ == nullptr);
225 return &return_label_;
226 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000227
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100228 HBasicBlock* GetSuccessor() const {
229 return successor_;
230 }
231
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100232 const char* GetDescription() const override { return "SuspendCheckSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100233
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000234 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100235 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000236 Label return_label_;
237
238 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
239};
240
Vladimir Markoaad75c62016-10-03 08:46:48 +0000241class LoadStringSlowPathX86 : public SlowPathCode {
242 public:
243 explicit LoadStringSlowPathX86(HLoadString* instruction): SlowPathCode(instruction) {}
244
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100245 void EmitNativeCode(CodeGenerator* codegen) override {
Vladimir Markoaad75c62016-10-03 08:46:48 +0000246 LocationSummary* locations = instruction_->GetLocations();
247 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
248
249 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
250 __ Bind(GetEntryLabel());
251 SaveLiveRegisters(codegen, locations);
252
253 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000254 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
255 __ movl(calling_convention.GetRegisterAt(0), Immediate(string_index.index_));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000256 x86_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
257 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
258 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
259 RestoreLiveRegisters(codegen, locations);
260
Vladimir Markoaad75c62016-10-03 08:46:48 +0000261 __ jmp(GetExitLabel());
262 }
263
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100264 const char* GetDescription() const override { return "LoadStringSlowPathX86"; }
Vladimir Markoaad75c62016-10-03 08:46:48 +0000265
266 private:
267 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
268};
269
Andreas Gampe85b62f22015-09-09 13:15:38 -0700270class LoadClassSlowPathX86 : public SlowPathCode {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000271 public:
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100272 LoadClassSlowPathX86(HLoadClass* cls, HInstruction* at)
273 : SlowPathCode(at), cls_(cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000274 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100275 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000276 }
277
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100278 void EmitNativeCode(CodeGenerator* codegen) override {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000279 LocationSummary* locations = instruction_->GetLocations();
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100280 Location out = locations->Out();
281 const uint32_t dex_pc = instruction_->GetDexPc();
282 bool must_resolve_type = instruction_->IsLoadClass() && cls_->MustResolveTypeOnSlowPath();
283 bool must_do_clinit = instruction_->IsClinitCheck() || cls_->MustGenerateClinitCheck();
284
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000285 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
286 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000287 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000288
289 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100290 if (must_resolve_type) {
291 DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_codegen->GetGraph()->GetDexFile()));
292 dex::TypeIndex type_index = cls_->GetTypeIndex();
293 __ movl(calling_convention.GetRegisterAt(0), Immediate(type_index.index_));
Vladimir Marko8f63f102020-09-28 12:10:28 +0100294 if (cls_->NeedsAccessCheck()) {
295 CheckEntrypointTypes<kQuickResolveTypeAndVerifyAccess, void*, uint32_t>();
296 x86_codegen->InvokeRuntime(kQuickResolveTypeAndVerifyAccess, instruction_, dex_pc, this);
297 } else {
298 CheckEntrypointTypes<kQuickResolveType, void*, uint32_t>();
299 x86_codegen->InvokeRuntime(kQuickResolveType, instruction_, dex_pc, this);
300 }
Vladimir Markoa9f303c2018-07-20 16:43:56 +0100301 // If we also must_do_clinit, the resolved type is now in the correct register.
302 } else {
303 DCHECK(must_do_clinit);
304 Location source = instruction_->IsLoadClass() ? out : locations->InAt(0);
305 x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), source);
306 }
307 if (must_do_clinit) {
308 x86_codegen->InvokeRuntime(kQuickInitializeStaticStorage, instruction_, dex_pc, this);
309 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, mirror::Class*>();
Roland Levillain888d0672015-11-23 18:53:50 +0000310 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000311
312 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313 if (out.IsValid()) {
314 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
315 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000316 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000317 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000318 __ jmp(GetExitLabel());
319 }
320
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100321 const char* GetDescription() const override { return "LoadClassSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100322
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000323 private:
324 // The class this slow path will load.
325 HLoadClass* const cls_;
326
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000327 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
328};
329
Andreas Gampe85b62f22015-09-09 13:15:38 -0700330class TypeCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000331 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000332 TypeCheckSlowPathX86(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000333 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000334
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100335 void EmitNativeCode(CodeGenerator* codegen) override {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000336 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000337 DCHECK(instruction_->IsCheckCast()
338 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000339
340 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
341 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000342
Vladimir Markoe619f6c2017-12-12 16:00:01 +0000343 if (kPoisonHeapReferences &&
344 instruction_->IsCheckCast() &&
345 instruction_->AsCheckCast()->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) {
346 // First, unpoison the `cls` reference that was poisoned for direct memory comparison.
347 __ UnpoisonHeapReference(locations->InAt(1).AsRegister<Register>());
348 }
349
Vladimir Marko87584542017-12-12 17:47:52 +0000350 if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000351 SaveLiveRegisters(codegen, locations);
352 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000353
354 // We're moving two locations to locations that could overlap, so we need a parallel
355 // move resolver.
356 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800357 x86_codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800358 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100359 DataType::Type::kReference,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800360 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800361 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100362 DataType::Type::kReference);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000363 if (instruction_->IsInstanceOf()) {
Serban Constantinescuba45db02016-07-12 22:53:02 +0100364 x86_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
Alexandre Rames8158f282015-08-07 10:26:17 +0100365 instruction_,
366 instruction_->GetDexPc(),
367 this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800368 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000369 } else {
370 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800371 x86_codegen->InvokeRuntime(kQuickCheckInstanceOf,
372 instruction_,
373 instruction_->GetDexPc(),
374 this);
375 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000376 }
377
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000378 if (!is_fatal_) {
379 if (instruction_->IsInstanceOf()) {
380 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
381 }
382 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray75374372015-09-17 17:12:19 +0000383
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000384 __ jmp(GetExitLabel());
385 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000386 }
387
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100388 const char* GetDescription() const override { return "TypeCheckSlowPathX86"; }
389 bool IsFatal() const override { return is_fatal_; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100390
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000391 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000392 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000393
394 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
395};
396
Andreas Gampe85b62f22015-09-09 13:15:38 -0700397class DeoptimizationSlowPathX86 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700398 public:
Aart Bik42249c32016-01-07 15:33:50 -0800399 explicit DeoptimizationSlowPathX86(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000400 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700401
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100402 void EmitNativeCode(CodeGenerator* codegen) override {
Alexandre Rames8158f282015-08-07 10:26:17 +0100403 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700404 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100405 LocationSummary* locations = instruction_->GetLocations();
406 SaveLiveRegisters(codegen, locations);
407 InvokeRuntimeCallingConvention calling_convention;
408 x86_codegen->Load32BitValue(
409 calling_convention.GetRegisterAt(0),
410 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescuba45db02016-07-12 22:53:02 +0100411 x86_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100412 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700413 }
414
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100415 const char* GetDescription() const override { return "DeoptimizationSlowPathX86"; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100416
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700417 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700418 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
419};
420
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100421class ArraySetSlowPathX86 : public SlowPathCode {
422 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000423 explicit ArraySetSlowPathX86(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100424
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100425 void EmitNativeCode(CodeGenerator* codegen) override {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100426 LocationSummary* locations = instruction_->GetLocations();
427 __ Bind(GetEntryLabel());
428 SaveLiveRegisters(codegen, locations);
429
430 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100431 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100432 parallel_move.AddMove(
433 locations->InAt(0),
434 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100435 DataType::Type::kReference,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100436 nullptr);
437 parallel_move.AddMove(
438 locations->InAt(1),
439 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100440 DataType::Type::kInt32,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100441 nullptr);
442 parallel_move.AddMove(
443 locations->InAt(2),
444 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100445 DataType::Type::kReference,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100446 nullptr);
447 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
448
449 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100450 x86_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000451 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100452 RestoreLiveRegisters(codegen, locations);
453 __ jmp(GetExitLabel());
454 }
455
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100456 const char* GetDescription() const override { return "ArraySetSlowPathX86"; }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100457
458 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100459 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86);
460};
461
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100462// Slow path marking an object reference `ref` during a read
463// barrier. The field `obj.field` in the object `obj` holding this
464// reference does not get updated by this slow path after marking (see
465// ReadBarrierMarkAndUpdateFieldSlowPathX86 below for that).
466//
467// This means that after the execution of this slow path, `ref` will
468// always be up-to-date, but `obj.field` may not; i.e., after the
469// flip, `ref` will be a to-space reference, but `obj.field` will
470// probably still be a from-space reference (unless it gets updated by
471// another thread, or if another thread installed another object
472// reference (different from `ref`) in `obj.field`).
Roland Levillain7c1559a2015-12-15 10:55:36 +0000473class ReadBarrierMarkSlowPathX86 : public SlowPathCode {
474 public:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100475 ReadBarrierMarkSlowPathX86(HInstruction* instruction,
476 Location ref,
477 bool unpoison_ref_before_marking)
478 : SlowPathCode(instruction),
479 ref_(ref),
480 unpoison_ref_before_marking_(unpoison_ref_before_marking) {
Roland Levillain7c1559a2015-12-15 10:55:36 +0000481 DCHECK(kEmitCompilerReadBarrier);
482 }
483
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100484 const char* GetDescription() const override { return "ReadBarrierMarkSlowPathX86"; }
Roland Levillain7c1559a2015-12-15 10:55:36 +0000485
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100486 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain7c1559a2015-12-15 10:55:36 +0000487 LocationSummary* locations = instruction_->GetLocations();
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100488 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillain7c1559a2015-12-15 10:55:36 +0000489 DCHECK(locations->CanCall());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100490 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain7c1559a2015-12-15 10:55:36 +0000491 DCHECK(instruction_->IsInstanceFieldGet() ||
Alex Light3a73ffb2021-01-25 14:11:05 +0000492 instruction_->IsPredicatedInstanceFieldGet() ||
Roland Levillain7c1559a2015-12-15 10:55:36 +0000493 instruction_->IsStaticFieldGet() ||
494 instruction_->IsArrayGet() ||
Roland Levillain16d9f942016-08-25 17:27:56 +0100495 instruction_->IsArraySet() ||
Roland Levillain7c1559a2015-12-15 10:55:36 +0000496 instruction_->IsLoadClass() ||
497 instruction_->IsLoadString() ||
498 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100499 instruction_->IsCheckCast() ||
Andra Danciu1ca6f322020-08-12 08:58:07 +0000500 (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain7c1559a2015-12-15 10:55:36 +0000501 << "Unexpected instruction in read barrier marking slow path: "
502 << instruction_->DebugName();
503
504 __ Bind(GetEntryLabel());
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100505 if (unpoison_ref_before_marking_) {
Vladimir Marko953437b2016-08-24 08:30:46 +0000506 // Object* ref = ref_addr->AsMirrorPtr()
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100507 __ MaybeUnpoisonHeapReference(ref_reg);
Vladimir Marko953437b2016-08-24 08:30:46 +0000508 }
Roland Levillain4359e612016-07-20 11:32:19 +0100509 // No need to save live registers; it's taken care of by the
510 // entrypoint. Also, there is no need to update the stack mask,
511 // as this runtime call will not trigger a garbage collection.
Roland Levillain7c1559a2015-12-15 10:55:36 +0000512 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100513 DCHECK_NE(ref_reg, ESP);
514 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCpuRegisters) << ref_reg;
Roland Levillain02b75802016-07-13 11:54:35 +0100515 // "Compact" slow path, saving two moves.
516 //
517 // Instead of using the standard runtime calling convention (input
518 // and output in EAX):
519 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100520 // EAX <- ref
Roland Levillain02b75802016-07-13 11:54:35 +0100521 // EAX <- ReadBarrierMark(EAX)
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100522 // ref <- EAX
Roland Levillain02b75802016-07-13 11:54:35 +0100523 //
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100524 // we just use rX (the register containing `ref`) as input and output
Roland Levillain02b75802016-07-13 11:54:35 +0100525 // of a dedicated entrypoint:
526 //
527 // rX <- ReadBarrierMarkRegX(rX)
528 //
Roland Levillain97c46462017-05-11 14:04:03 +0100529 int32_t entry_point_offset = Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(ref_reg);
Roland Levillaindec8f632016-07-22 17:10:06 +0100530 // This runtime call does not require a stack map.
531 x86_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
Roland Levillain7c1559a2015-12-15 10:55:36 +0000532 __ jmp(GetExitLabel());
533 }
534
535 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100536 // The location (register) of the marked object reference.
537 const Location ref_;
538 // Should the reference in `ref_` be unpoisoned prior to marking it?
539 const bool unpoison_ref_before_marking_;
Roland Levillain7c1559a2015-12-15 10:55:36 +0000540
541 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86);
542};
543
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100544// Slow path marking an object reference `ref` during a read barrier,
545// and if needed, atomically updating the field `obj.field` in the
546// object `obj` holding this reference after marking (contrary to
547// ReadBarrierMarkSlowPathX86 above, which never tries to update
548// `obj.field`).
549//
550// This means that after the execution of this slow path, both `ref`
551// and `obj.field` will be up-to-date; i.e., after the flip, both will
552// hold the same to-space reference (unless another thread installed
553// another object reference (different from `ref`) in `obj.field`).
554class ReadBarrierMarkAndUpdateFieldSlowPathX86 : public SlowPathCode {
555 public:
556 ReadBarrierMarkAndUpdateFieldSlowPathX86(HInstruction* instruction,
557 Location ref,
558 Register obj,
559 const Address& field_addr,
560 bool unpoison_ref_before_marking,
561 Register temp)
562 : SlowPathCode(instruction),
563 ref_(ref),
564 obj_(obj),
565 field_addr_(field_addr),
566 unpoison_ref_before_marking_(unpoison_ref_before_marking),
567 temp_(temp) {
568 DCHECK(kEmitCompilerReadBarrier);
569 }
570
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100571 const char* GetDescription() const override { return "ReadBarrierMarkAndUpdateFieldSlowPathX86"; }
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100572
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100573 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100574 LocationSummary* locations = instruction_->GetLocations();
575 Register ref_reg = ref_.AsRegister<Register>();
576 DCHECK(locations->CanCall());
577 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
578 // This slow path is only used by the UnsafeCASObject intrinsic.
Andra Danciu5e13d452020-09-08 14:35:09 +0000579 DCHECK((instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100580 << "Unexpected instruction in read barrier marking and field updating slow path: "
581 << instruction_->DebugName();
582 DCHECK(instruction_->GetLocations()->Intrinsified());
Andra Danciu52d2c0c2020-09-15 14:27:21 +0000583 Intrinsics intrinsic = instruction_->AsInvoke()->GetIntrinsic();
584 static constexpr auto kVarHandleCAS = mirror::VarHandle::AccessModeTemplate::kCompareAndSet;
Andra Danciu9dfb1a92020-09-22 13:27:18 +0000585 static constexpr auto kVarHandleGetAndSet =
586 mirror::VarHandle::AccessModeTemplate::kGetAndUpdate;
Andra Danciu370948e2020-09-23 08:07:25 +0000587 static constexpr auto kVarHandleCAX =
588 mirror::VarHandle::AccessModeTemplate::kCompareAndExchange;
Andra Danciu52d2c0c2020-09-15 14:27:21 +0000589 DCHECK(intrinsic == Intrinsics::kUnsafeCASObject ||
Sorin Basca2f01e8e2021-06-18 06:44:07 +0000590 intrinsic == Intrinsics::kJdkUnsafeCASObject ||
Andra Danciu9dfb1a92020-09-22 13:27:18 +0000591 mirror::VarHandle::GetAccessModeTemplateByIntrinsic(intrinsic) == kVarHandleCAS ||
Andra Danciu370948e2020-09-23 08:07:25 +0000592 mirror::VarHandle::GetAccessModeTemplateByIntrinsic(intrinsic) == kVarHandleGetAndSet ||
593 mirror::VarHandle::GetAccessModeTemplateByIntrinsic(intrinsic) == kVarHandleCAX);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100594
595 __ Bind(GetEntryLabel());
596 if (unpoison_ref_before_marking_) {
597 // Object* ref = ref_addr->AsMirrorPtr()
598 __ MaybeUnpoisonHeapReference(ref_reg);
599 }
600
601 // Save the old (unpoisoned) reference.
602 __ movl(temp_, ref_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* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
608 DCHECK_NE(ref_reg, ESP);
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 EAX):
614 //
615 // EAX <- ref
616 // EAX <- ReadBarrierMark(EAX)
617 // ref <- EAX
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 //
Roland Levillain97c46462017-05-11 14:04:03 +0100624 int32_t entry_point_offset = Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(ref_reg);
Roland Levillaina1aa3b12016-10-26 13:03:38 +0100625 // This runtime call does not require a stack map.
626 x86_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
627
628 // If the new reference is different from the old reference,
629 // update the field in the holder (`*field_addr`).
630 //
631 // Note that this field could also hold a different object, if
632 // another thread had concurrently changed it. In that case, the
633 // LOCK CMPXCHGL instruction in the compare-and-set (CAS)
634 // operation below would abort the CAS, leaving the field as-is.
635 NearLabel done;
636 __ cmpl(temp_, ref_reg);
637 __ j(kEqual, &done);
638
639 // Update the the holder's field atomically. This may fail if
640 // mutator updates before us, but it's OK. This is achieved
641 // using a strong compare-and-set (CAS) operation with relaxed
642 // memory synchronization ordering, where the expected value is
643 // the old reference and the desired value is the new reference.
644 // This operation is implemented with a 32-bit LOCK CMPXLCHG
645 // instruction, which requires the expected value (the old
646 // reference) to be in EAX. Save EAX beforehand, and move the
647 // expected value (stored in `temp_`) into EAX.
648 __ pushl(EAX);
649 __ movl(EAX, temp_);
650
651 // Convenience aliases.
652 Register base = obj_;
653 Register expected = EAX;
654 Register value = ref_reg;
655
656 bool base_equals_value = (base == value);
657 if (kPoisonHeapReferences) {
658 if (base_equals_value) {
659 // If `base` and `value` are the same register location, move
660 // `value` to a temporary register. This way, poisoning
661 // `value` won't invalidate `base`.
662 value = temp_;
663 __ movl(value, base);
664 }
665
666 // Check that the register allocator did not assign the location
667 // of `expected` (EAX) to `value` nor to `base`, so that heap
668 // poisoning (when enabled) works as intended below.
669 // - If `value` were equal to `expected`, both references would
670 // be poisoned twice, meaning they would not be poisoned at
671 // all, as heap poisoning uses address negation.
672 // - If `base` were equal to `expected`, poisoning `expected`
673 // would invalidate `base`.
674 DCHECK_NE(value, expected);
675 DCHECK_NE(base, expected);
676
677 __ PoisonHeapReference(expected);
678 __ PoisonHeapReference(value);
679 }
680
681 __ LockCmpxchgl(field_addr_, value);
682
683 // If heap poisoning is enabled, we need to unpoison the values
684 // that were poisoned earlier.
685 if (kPoisonHeapReferences) {
686 if (base_equals_value) {
687 // `value` has been moved to a temporary register, no need
688 // to unpoison it.
689 } else {
690 __ UnpoisonHeapReference(value);
691 }
692 // No need to unpoison `expected` (EAX), as it is be overwritten below.
693 }
694
695 // Restore EAX.
696 __ popl(EAX);
697
698 __ Bind(&done);
699 __ jmp(GetExitLabel());
700 }
701
702 private:
703 // The location (register) of the marked object reference.
704 const Location ref_;
705 // The register containing the object holding the marked object reference field.
706 const Register obj_;
707 // The address of the marked reference field. The base of this address must be `obj_`.
708 const Address field_addr_;
709
710 // Should the reference in `ref_` be unpoisoned prior to marking it?
711 const bool unpoison_ref_before_marking_;
712
713 const Register temp_;
714
715 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathX86);
716};
717
Roland Levillain0d5a2812015-11-13 10:07:31 +0000718// Slow path generating a read barrier for a heap reference.
719class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode {
720 public:
721 ReadBarrierForHeapReferenceSlowPathX86(HInstruction* instruction,
722 Location out,
723 Location ref,
724 Location obj,
725 uint32_t offset,
726 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000727 : SlowPathCode(instruction),
Roland Levillain0d5a2812015-11-13 10:07:31 +0000728 out_(out),
729 ref_(ref),
730 obj_(obj),
731 offset_(offset),
732 index_(index) {
733 DCHECK(kEmitCompilerReadBarrier);
734 // If `obj` is equal to `out` or `ref`, it means the initial object
735 // has been overwritten by (or after) the heap object reference load
736 // to be instrumented, e.g.:
737 //
738 // __ movl(out, Address(out, offset));
Roland Levillain7c1559a2015-12-15 10:55:36 +0000739 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000740 //
741 // In that case, we have lost the information about the original
742 // object, and the emitted read barrier cannot work properly.
743 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
744 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
745 }
746
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100747 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000748 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
749 LocationSummary* locations = instruction_->GetLocations();
750 Register reg_out = out_.AsRegister<Register>();
751 DCHECK(locations->CanCall());
752 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +0100753 DCHECK(instruction_->IsInstanceFieldGet() ||
Alex Light3a73ffb2021-01-25 14:11:05 +0000754 instruction_->IsPredicatedInstanceFieldGet() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100755 instruction_->IsStaticFieldGet() ||
756 instruction_->IsArrayGet() ||
757 instruction_->IsInstanceOf() ||
758 instruction_->IsCheckCast() ||
Vladimir Marko94d2c812020-11-05 10:04:45 +0000759 (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
Roland Levillain7c1559a2015-12-15 10:55:36 +0000760 << "Unexpected instruction in read barrier for heap reference slow path: "
761 << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000762
763 __ Bind(GetEntryLabel());
764 SaveLiveRegisters(codegen, locations);
765
766 // We may have to change the index's value, but as `index_` is a
767 // constant member (like other "inputs" of this slow path),
768 // introduce a copy of it, `index`.
769 Location index = index_;
770 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100771 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain0d5a2812015-11-13 10:07:31 +0000772 if (instruction_->IsArrayGet()) {
773 // Compute the actual memory offset and store it in `index`.
774 Register index_reg = index_.AsRegister<Register>();
775 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
776 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
777 // We are about to change the value of `index_reg` (see the
778 // calls to art::x86::X86Assembler::shll and
779 // art::x86::X86Assembler::AddImmediate below), but it has
780 // not been saved by the previous call to
781 // art::SlowPathCode::SaveLiveRegisters, as it is a
782 // callee-save register --
783 // art::SlowPathCode::SaveLiveRegisters does not consider
784 // callee-save registers, as it has been designed with the
785 // assumption that callee-save registers are supposed to be
786 // handled by the called function. So, as a callee-save
787 // register, `index_reg` _would_ eventually be saved onto
788 // the stack, but it would be too late: we would have
789 // changed its value earlier. Therefore, we manually save
790 // it here into another freely available register,
791 // `free_reg`, chosen of course among the caller-save
792 // registers (as a callee-save `free_reg` register would
793 // exhibit the same problem).
794 //
795 // Note we could have requested a temporary register from
796 // the register allocator instead; but we prefer not to, as
797 // this is a slow path, and we know we can find a
798 // caller-save register that is available.
799 Register free_reg = FindAvailableCallerSaveRegister(codegen);
800 __ movl(free_reg, index_reg);
801 index_reg = free_reg;
802 index = Location::RegisterLocation(index_reg);
803 } else {
804 // The initial register stored in `index_` has already been
805 // saved in the call to art::SlowPathCode::SaveLiveRegisters
806 // (as it is not a callee-save register), so we can freely
807 // use it.
808 }
809 // Shifting the index value contained in `index_reg` by the scale
810 // factor (2) cannot overflow in practice, as the runtime is
811 // unable to allocate object arrays with a size larger than
812 // 2^26 - 1 (that is, 2^28 - 4 bytes).
813 __ shll(index_reg, Immediate(TIMES_4));
814 static_assert(
815 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
816 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
817 __ AddImmediate(index_reg, Immediate(offset_));
818 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100819 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
820 // intrinsics, `index_` is not shifted by a scale factor of 2
821 // (as in the case of ArrayGet), as it is actually an offset
822 // to an object field within an object.
823 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain0d5a2812015-11-13 10:07:31 +0000824 DCHECK(instruction_->GetLocations()->Intrinsified());
825 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
Sorin Basca2f01e8e2021-06-18 06:44:07 +0000826 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile) ||
827 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kJdkUnsafeGetObject) ||
Sorin Basca4a4696a2021-10-09 07:14:40 +0000828 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kJdkUnsafeGetObjectVolatile) ||
829 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kJdkUnsafeGetObjectAcquire))
Roland Levillain0d5a2812015-11-13 10:07:31 +0000830 << instruction_->AsInvoke()->GetIntrinsic();
831 DCHECK_EQ(offset_, 0U);
832 DCHECK(index_.IsRegisterPair());
833 // UnsafeGet's offset location is a register pair, the low
834 // part contains the correct offset.
835 index = index_.ToLow();
836 }
837 }
838
839 // We're moving two or three locations to locations that could
840 // overlap, so we need a parallel move resolver.
841 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100842 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Roland Levillain0d5a2812015-11-13 10:07:31 +0000843 parallel_move.AddMove(ref_,
844 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100845 DataType::Type::kReference,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000846 nullptr);
847 parallel_move.AddMove(obj_,
848 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100849 DataType::Type::kReference,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000850 nullptr);
851 if (index.IsValid()) {
852 parallel_move.AddMove(index,
853 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100854 DataType::Type::kInt32,
Roland Levillain0d5a2812015-11-13 10:07:31 +0000855 nullptr);
856 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
857 } else {
858 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
859 __ movl(calling_convention.GetRegisterAt(2), Immediate(offset_));
860 }
Serban Constantinescuba45db02016-07-12 22:53:02 +0100861 x86_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain0d5a2812015-11-13 10:07:31 +0000862 CheckEntrypointTypes<
863 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
864 x86_codegen->Move32(out_, Location::RegisterLocation(EAX));
865
866 RestoreLiveRegisters(codegen, locations);
867 __ jmp(GetExitLabel());
868 }
869
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100870 const char* GetDescription() const override { return "ReadBarrierForHeapReferenceSlowPathX86"; }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000871
872 private:
873 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
874 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
875 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
876 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
877 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
878 return static_cast<Register>(i);
879 }
880 }
881 // We shall never fail to find a free caller-save register, as
882 // there are more than two core caller-save registers on x86
883 // (meaning it is possible to find one which is different from
884 // `ref` and `obj`).
885 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
886 LOG(FATAL) << "Could not find a free caller-save register";
887 UNREACHABLE();
888 }
889
Roland Levillain0d5a2812015-11-13 10:07:31 +0000890 const Location out_;
891 const Location ref_;
892 const Location obj_;
893 const uint32_t offset_;
894 // An additional location containing an index to an array.
895 // Only used for HArrayGet and the UnsafeGetObject &
896 // UnsafeGetObjectVolatile intrinsics.
897 const Location index_;
898
899 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86);
900};
901
902// Slow path generating a read barrier for a GC root.
903class ReadBarrierForRootSlowPathX86 : public SlowPathCode {
904 public:
905 ReadBarrierForRootSlowPathX86(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000906 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillain7c1559a2015-12-15 10:55:36 +0000907 DCHECK(kEmitCompilerReadBarrier);
908 }
Roland Levillain0d5a2812015-11-13 10:07:31 +0000909
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100910 void EmitNativeCode(CodeGenerator* codegen) override {
Roland Levillain0d5a2812015-11-13 10:07:31 +0000911 LocationSummary* locations = instruction_->GetLocations();
912 Register reg_out = out_.AsRegister<Register>();
913 DCHECK(locations->CanCall());
914 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain7c1559a2015-12-15 10:55:36 +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* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
924 x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescuba45db02016-07-12 22:53:02 +0100925 x86_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_codegen->Move32(out_, Location::RegisterLocation(EAX));
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"; }
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);
943};
944
Mythri Alle2d4feeb2021-10-13 15:39:37 +0000945class MethodEntryExitHooksSlowPathX86 : public SlowPathCode {
946 public:
947 explicit MethodEntryExitHooksSlowPathX86(HInstruction* instruction) : SlowPathCode(instruction) {}
948
949 void EmitNativeCode(CodeGenerator* codegen) override {
950 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
951 LocationSummary* locations = instruction_->GetLocations();
952 QuickEntrypointEnum entry_point =
953 (instruction_->IsMethodEntryHook()) ? kQuickMethodEntryHook : kQuickMethodExitHook;
954 __ Bind(GetEntryLabel());
955 SaveLiveRegisters(codegen, locations);
956 x86_codegen->InvokeRuntime(entry_point, instruction_, instruction_->GetDexPc(), this);
957 RestoreLiveRegisters(codegen, locations);
958 __ jmp(GetExitLabel());
959 }
960
961 const char* GetDescription() const override {
962 return "MethodEntryExitHooksSlowPath";
963 }
964
965 private:
966 DISALLOW_COPY_AND_ASSIGN(MethodEntryExitHooksSlowPathX86);
967};
968
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100969#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100970// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
971#define __ down_cast<X86Assembler*>(GetAssembler())-> // NOLINT
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100972
Aart Bike9f37602015-10-09 11:15:55 -0700973inline Condition X86Condition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700974 switch (cond) {
975 case kCondEQ: return kEqual;
976 case kCondNE: return kNotEqual;
977 case kCondLT: return kLess;
978 case kCondLE: return kLessEqual;
979 case kCondGT: return kGreater;
980 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700981 case kCondB: return kBelow;
982 case kCondBE: return kBelowEqual;
983 case kCondA: return kAbove;
984 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700985 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100986 LOG(FATAL) << "Unreachable";
987 UNREACHABLE();
988}
989
Aart Bike9f37602015-10-09 11:15:55 -0700990// Maps signed condition to unsigned condition and FP condition to x86 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100991inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
992 switch (cond) {
993 case kCondEQ: return kEqual;
994 case kCondNE: return kNotEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700995 // Signed to unsigned, and FP to x86 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100996 case kCondLT: return kBelow;
997 case kCondLE: return kBelowEqual;
998 case kCondGT: return kAbove;
999 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -07001000 // Unsigned remain unchanged.
1001 case kCondB: return kBelow;
1002 case kCondBE: return kBelowEqual;
1003 case kCondA: return kAbove;
1004 case kCondAE: return kAboveEqual;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001005 }
1006 LOG(FATAL) << "Unreachable";
1007 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001008}
1009
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001010void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001011 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001012}
1013
1014void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001015 stream << XmmRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001016}
1017
Vladimir Markoa0431112018-06-25 09:32:54 +01001018const X86InstructionSetFeatures& CodeGeneratorX86::GetInstructionSetFeatures() const {
1019 return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86InstructionSetFeatures();
1020}
1021
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001022size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1023 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
1024 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001025}
1026
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001027size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1028 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
1029 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001030}
1031
Mark Mendell7c8d0092015-01-26 11:21:33 -05001032size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001033 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001034 __ movups(Address(ESP, stack_index), XmmRegister(reg_id));
Aart Bikb13c65b2017-03-21 20:14:07 -07001035 } else {
1036 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
1037 }
Artem Serov6a0b6572019-07-26 20:38:37 +01001038 return GetSlowPathFPWidth();
Mark Mendell7c8d0092015-01-26 11:21:33 -05001039}
1040
1041size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Aart Bikb13c65b2017-03-21 20:14:07 -07001042 if (GetGraph()->HasSIMD()) {
Aart Bik5576f372017-03-23 16:17:37 -07001043 __ movups(XmmRegister(reg_id), Address(ESP, stack_index));
Aart Bikb13c65b2017-03-21 20:14:07 -07001044 } else {
1045 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
1046 }
Artem Serov6a0b6572019-07-26 20:38:37 +01001047 return GetSlowPathFPWidth();
Mark Mendell7c8d0092015-01-26 11:21:33 -05001048}
1049
Calin Juravle175dc732015-08-25 15:42:32 +01001050void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint,
1051 HInstruction* instruction,
1052 uint32_t dex_pc,
1053 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001054 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001055 GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(entrypoint).Int32Value());
1056 if (EntrypointRequiresStackMap(entrypoint)) {
1057 RecordPcInfo(instruction, dex_pc, slow_path);
1058 }
Alexandre Rames8158f282015-08-07 10:26:17 +01001059}
1060
Roland Levillaindec8f632016-07-22 17:10:06 +01001061void CodeGeneratorX86::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1062 HInstruction* instruction,
1063 SlowPathCode* slow_path) {
1064 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescuba45db02016-07-12 22:53:02 +01001065 GenerateInvokeRuntime(entry_point_offset);
1066}
1067
1068void CodeGeneratorX86::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01001069 __ fs()->call(Address::Absolute(entry_point_offset));
1070}
1071
Mark Mendellfb8d2792015-03-31 22:16:59 -04001072CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
Roland Levillain0d5a2812015-11-13 10:07:31 +00001073 const CompilerOptions& compiler_options,
1074 OptimizingCompilerStats* stats)
Mark Mendell5f874182015-03-04 15:42:45 -05001075 : CodeGenerator(graph,
1076 kNumberOfCpuRegisters,
1077 kNumberOfXmmRegisters,
1078 kNumberOfRegisterPairs,
1079 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1080 arraysize(kCoreCalleeSaves))
1081 | (1 << kFakeReturnRegister),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001082 0,
1083 compiler_options,
1084 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001085 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001086 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001087 instruction_visitor_(graph, this),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001088 move_resolver_(graph->GetAllocator(), this),
1089 assembler_(graph->GetAllocator()),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001090 boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1091 method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1092 boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1093 type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko8f63f102020-09-28 12:10:28 +01001094 public_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1095 package_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001096 boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001097 string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoeb9eb002020-10-02 13:54:19 +01001098 boot_image_jni_entrypoint_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko2d06e022019-07-08 15:45:19 +01001099 boot_image_other_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001100 jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1101 jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko93205e32016-04-13 11:59:46 +01001102 constant_area_start_(-1),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001103 fixups_to_jump_tables_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00001104 method_address_offset_(std::less<uint32_t>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001105 graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001106 // Use a fake return address register to mimic Quick.
1107 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001108}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001109
David Brazdil58282f42016-01-14 12:45:10 +00001110void CodeGeneratorX86::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001111 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01001112 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001113}
1114
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001115InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001116 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001117 assembler_(codegen->GetAssembler()),
1118 codegen_(codegen) {}
1119
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001120static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01001121 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001122}
1123
Mythri Alle2d4feeb2021-10-13 15:39:37 +00001124void SetInForReturnValue(HInstruction* ret, LocationSummary* locations) {
1125 switch (ret->InputAt(0)->GetType()) {
1126 case DataType::Type::kReference:
1127 case DataType::Type::kBool:
1128 case DataType::Type::kUint8:
1129 case DataType::Type::kInt8:
1130 case DataType::Type::kUint16:
1131 case DataType::Type::kInt16:
1132 case DataType::Type::kInt32:
1133 locations->SetInAt(0, Location::RegisterLocation(EAX));
1134 break;
1135
1136 case DataType::Type::kInt64:
1137 locations->SetInAt(0, Location::RegisterPairLocation(EAX, EDX));
1138 break;
1139
1140 case DataType::Type::kFloat32:
1141 case DataType::Type::kFloat64:
1142 locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
1143 break;
1144
1145 case DataType::Type::kVoid:
1146 locations->SetInAt(0, Location::NoLocation());
1147 break;
1148
1149 default:
1150 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
1151 }
1152}
1153
1154void LocationsBuilderX86::VisitMethodExitHook(HMethodExitHook* method_hook) {
1155 LocationSummary* locations = new (GetGraph()->GetAllocator())
1156 LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1157 SetInForReturnValue(method_hook, locations);
1158}
1159
1160void InstructionCodeGeneratorX86::GenerateMethodEntryExitHook(HInstruction* instruction) {
1161 SlowPathCode* slow_path =
1162 new (codegen_->GetScopedAllocator()) MethodEntryExitHooksSlowPathX86(instruction);
1163 codegen_->AddSlowPath(slow_path);
1164
1165 uint64_t address = reinterpret_cast64<uint64_t>(Runtime::Current()->GetInstrumentation());
1166 int offset = instrumentation::Instrumentation::NeedsEntryExitHooksOffset().Int32Value();
1167 __ cmpw(Address::Absolute(address + offset), Immediate(0));
1168 __ j(kEqual, slow_path->GetEntryLabel());
1169 __ Bind(slow_path->GetExitLabel());
1170}
1171
1172void InstructionCodeGeneratorX86::VisitMethodExitHook(HMethodExitHook* instruction) {
1173 DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1174 DCHECK(codegen_->RequiresCurrentMethod());
1175 GenerateMethodEntryExitHook(instruction);
1176}
1177
1178void LocationsBuilderX86::VisitMethodEntryHook(HMethodEntryHook* method_hook) {
1179 new (GetGraph()->GetAllocator()) LocationSummary(method_hook, LocationSummary::kCallOnSlowPath);
1180}
1181
1182void InstructionCodeGeneratorX86::VisitMethodEntryHook(HMethodEntryHook* instruction) {
1183 DCHECK(codegen_->GetCompilerOptions().IsJitCompiler() && GetGraph()->IsDebuggable());
1184 DCHECK(codegen_->RequiresCurrentMethod());
1185 GenerateMethodEntryExitHook(instruction);
1186}
1187
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001188void CodeGeneratorX86::MaybeIncrementHotness(bool is_frame_entry) {
1189 if (GetCompilerOptions().CountHotnessInCompiledCode()) {
1190 Register reg = EAX;
1191 if (is_frame_entry) {
1192 reg = kMethodRegisterArgument;
1193 } else {
1194 __ pushl(EAX);
Vladimir Markodec78172020-06-19 15:31:23 +01001195 __ cfi().AdjustCFAOffset(4);
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001196 __ movl(EAX, Address(ESP, kX86WordSize));
1197 }
1198 NearLabel overflow;
1199 __ cmpw(Address(reg, ArtMethod::HotnessCountOffset().Int32Value()),
Vladimir Markoce131fe2021-10-26 20:03:35 +00001200 Immediate(ArtMethod::MaxCounter()));
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001201 __ j(kEqual, &overflow);
Vladimir Markoce131fe2021-10-26 20:03:35 +00001202 __ addw(Address(reg, ArtMethod::HotnessCountOffset().Int32Value()),
1203 Immediate(1));
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001204 __ Bind(&overflow);
1205 if (!is_frame_entry) {
1206 __ popl(EAX);
Vladimir Markodec78172020-06-19 15:31:23 +01001207 __ cfi().AdjustCFAOffset(-4);
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001208 }
1209 }
1210
1211 if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) {
Nicolas Geoffray095dc462020-08-17 16:40:28 +01001212 ScopedProfilingInfoUse spiu(
1213 Runtime::Current()->GetJit(), GetGraph()->GetArtMethod(), Thread::Current());
1214 ProfilingInfo* info = spiu.GetProfilingInfo();
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00001215 if (info != nullptr) {
1216 uint32_t address = reinterpret_cast32<uint32_t>(info);
1217 NearLabel done;
1218 if (HasEmptyFrame()) {
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001219 CHECK(is_frame_entry);
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00001220 // Alignment
Vladimir Markodec78172020-06-19 15:31:23 +01001221 IncreaseFrame(8);
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00001222 // We need a temporary. The stub also expects the method at bottom of stack.
1223 __ pushl(EAX);
1224 __ cfi().AdjustCFAOffset(4);
1225 __ movl(EAX, Immediate(address));
1226 __ addw(Address(EAX, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()),
1227 Immediate(1));
Nicolas Geoffray8b8d93d2020-09-17 14:30:01 +01001228 __ andw(Address(EAX, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()),
1229 Immediate(interpreter::kTieredHotnessMask));
1230 __ j(kNotZero, &done);
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00001231 GenerateInvokeRuntime(
1232 GetThreadOffset<kX86PointerSize>(kQuickCompileOptimized).Int32Value());
1233 __ Bind(&done);
1234 // We don't strictly require to restore EAX, but this makes the generated
1235 // code easier to reason about.
1236 __ popl(EAX);
1237 __ cfi().AdjustCFAOffset(-4);
Vladimir Markodec78172020-06-19 15:31:23 +01001238 DecreaseFrame(8);
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00001239 } else {
1240 if (!RequiresCurrentMethod()) {
1241 CHECK(is_frame_entry);
1242 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
1243 }
1244 // We need a temporary.
1245 __ pushl(EAX);
1246 __ cfi().AdjustCFAOffset(4);
1247 __ movl(EAX, Immediate(address));
1248 __ addw(Address(EAX, ProfilingInfo::BaselineHotnessCountOffset().Int32Value()),
1249 Immediate(1));
1250 __ popl(EAX); // Put stack as expected before exiting or calling stub.
1251 __ cfi().AdjustCFAOffset(-4);
1252 __ j(kCarryClear, &done);
1253 GenerateInvokeRuntime(
1254 GetThreadOffset<kX86PointerSize>(kQuickCompileOptimized).Int32Value());
1255 __ Bind(&done);
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001256 }
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001257 }
1258 }
1259}
1260
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001261void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001262 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001263 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +00001264 bool skip_overflow_check =
1265 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001266 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +00001267
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00001268 if (!skip_overflow_check) {
Vladimir Marko33bff252017-11-01 14:35:42 +00001269 size_t reserved_bytes = GetStackOverflowReservedBytes(InstructionSet::kX86);
1270 __ testl(EAX, Address(ESP, -static_cast<int32_t>(reserved_bytes)));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001271 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +01001272 }
1273
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001274 if (!HasEmptyFrame()) {
1275 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
1276 Register reg = kCoreCalleeSaves[i];
1277 if (allocated_registers_.ContainsCoreRegister(reg)) {
1278 __ pushl(reg);
1279 __ cfi().AdjustCFAOffset(kX86WordSize);
1280 __ cfi().RelOffset(DWARFReg(reg), 0);
1281 }
1282 }
Mark Mendell5f874182015-03-04 15:42:45 -05001283
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001284 int adjust = GetFrameSize() - FrameEntrySpillSize();
Vladimir Markodec78172020-06-19 15:31:23 +01001285 IncreaseFrame(adjust);
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001286 // Save the current method if we need it. Note that we do not
1287 // do this in HCurrentMethod, as the instruction might have been removed
1288 // in the SSA graph.
1289 if (RequiresCurrentMethod()) {
1290 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
1291 }
1292
1293 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1294 // Initialize should_deoptimize flag to 0.
1295 __ movl(Address(ESP, GetStackOffsetOfShouldDeoptimizeFlag()), Immediate(0));
Mark Mendell5f874182015-03-04 15:42:45 -05001296 }
1297 }
1298
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001299 MaybeIncrementHotness(/* is_frame_entry= */ true);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001300}
1301
1302void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +01001303 __ cfi().RememberState();
1304 if (!HasEmptyFrame()) {
1305 int adjust = GetFrameSize() - FrameEntrySpillSize();
Vladimir Markodec78172020-06-19 15:31:23 +01001306 DecreaseFrame(adjust);
Mark Mendell5f874182015-03-04 15:42:45 -05001307
David Srbeckyc34dc932015-04-12 09:27:43 +01001308 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
1309 Register reg = kCoreCalleeSaves[i];
1310 if (allocated_registers_.ContainsCoreRegister(reg)) {
1311 __ popl(reg);
1312 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
1313 __ cfi().Restore(DWARFReg(reg));
1314 }
Mark Mendell5f874182015-03-04 15:42:45 -05001315 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001316 }
David Srbeckyc34dc932015-04-12 09:27:43 +01001317 __ ret();
1318 __ cfi().RestoreState();
1319 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001320}
1321
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001322void CodeGeneratorX86::Bind(HBasicBlock* block) {
1323 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001324}
1325
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001326Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001327 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001328 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001329 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001330 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001331 case DataType::Type::kInt8:
1332 case DataType::Type::kUint16:
1333 case DataType::Type::kInt16:
Aart Bik66c158e2018-01-31 12:55:04 -08001334 case DataType::Type::kUint32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001335 case DataType::Type::kInt32:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001336 return Location::RegisterLocation(EAX);
1337
Aart Bik66c158e2018-01-31 12:55:04 -08001338 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001339 case DataType::Type::kInt64:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001340 return Location::RegisterPairLocation(EAX, EDX);
1341
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001342 case DataType::Type::kVoid:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001343 return Location::NoLocation();
1344
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001345 case DataType::Type::kFloat64:
1346 case DataType::Type::kFloat32:
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001347 return Location::FpuRegisterLocation(XMM0);
1348 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001349
1350 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001351}
1352
1353Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
1354 return Location::RegisterLocation(kMethodRegisterArgument);
1355}
1356
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001357Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001358 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001359 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001360 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001361 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001362 case DataType::Type::kInt8:
1363 case DataType::Type::kUint16:
1364 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01001365 case DataType::Type::kInt32: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001366 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001367 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001368 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001369 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001370 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001371 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001372 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001373 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001374
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001375 case DataType::Type::kInt64: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001376 uint32_t index = gp_index_;
1377 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001378 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001379 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001380 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
1381 calling_convention.GetRegisterPairAt(index));
1382 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001383 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001384 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
1385 }
1386 }
1387
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001388 case DataType::Type::kFloat32: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001389 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001390 stack_index_++;
1391 if (index < calling_convention.GetNumberOfFpuRegisters()) {
1392 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
1393 } else {
1394 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
1395 }
1396 }
1397
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001398 case DataType::Type::kFloat64: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001399 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001400 stack_index_ += 2;
1401 if (index < calling_convention.GetNumberOfFpuRegisters()) {
1402 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
1403 } else {
1404 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001405 }
1406 }
1407
Aart Bik66c158e2018-01-31 12:55:04 -08001408 case DataType::Type::kUint32:
1409 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001410 case DataType::Type::kVoid:
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001411 LOG(FATAL) << "Unexpected parameter type " << type;
Elliott Hughesc1896c92018-11-29 11:33:18 -08001412 UNREACHABLE();
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001413 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00001414 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001415}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001416
Vladimir Marko86c87522020-05-11 16:55:55 +01001417Location CriticalNativeCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
1418 DCHECK_NE(type, DataType::Type::kReference);
1419
1420 Location location;
1421 if (DataType::Is64BitType(type)) {
1422 location = Location::DoubleStackSlot(stack_offset_);
1423 stack_offset_ += 2 * kFramePointerSize;
1424 } else {
1425 location = Location::StackSlot(stack_offset_);
1426 stack_offset_ += kFramePointerSize;
1427 }
1428 if (for_register_allocation_) {
1429 location = Location::Any();
1430 }
1431 return location;
1432}
1433
1434Location CriticalNativeCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
1435 // We perform conversion to the managed ABI return register after the call if needed.
1436 InvokeDexCallingConventionVisitorX86 dex_calling_convention;
1437 return dex_calling_convention.GetReturnLocation(type);
1438}
1439
1440Location CriticalNativeCallingConventionVisitorX86::GetMethodLocation() const {
1441 // Pass the method in the hidden argument EAX.
1442 return Location::RegisterLocation(EAX);
1443}
1444
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001445void CodeGeneratorX86::Move32(Location destination, Location source) {
1446 if (source.Equals(destination)) {
1447 return;
1448 }
1449 if (destination.IsRegister()) {
1450 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001451 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001452 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001453 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Andra Danciu5e13d452020-09-08 14:35:09 +00001454 } else if (source.IsConstant()) {
1455 int32_t value = GetInt32ValueOf(source.GetConstant());
1456 __ movl(destination.AsRegister<Register>(), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001457 } else {
1458 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001459 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001460 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001461 } else if (destination.IsFpuRegister()) {
1462 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001463 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001464 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001465 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001466 } else {
1467 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001468 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001469 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001470 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001471 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001472 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001473 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001474 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001475 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05001476 } else if (source.IsConstant()) {
1477 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001478 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05001479 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001480 } else {
1481 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001482 __ pushl(Address(ESP, source.GetStackIndex()));
1483 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001484 }
1485 }
1486}
1487
1488void CodeGeneratorX86::Move64(Location destination, Location source) {
1489 if (source.Equals(destination)) {
1490 return;
1491 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001492 if (destination.IsRegisterPair()) {
1493 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001494 EmitParallelMoves(
1495 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1496 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001497 DataType::Type::kInt32,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001498 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001499 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001500 DataType::Type::kInt32);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001501 } else if (source.IsFpuRegister()) {
Calin Juravlee460d1d2015-09-29 04:52:17 +01001502 XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
1503 __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
1504 __ psrlq(src_reg, Immediate(32));
1505 __ movd(destination.AsRegisterPairHigh<Register>(), src_reg);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001506 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001507 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001508 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001509 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
1510 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001511 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
1512 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001513 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05001514 if (source.IsFpuRegister()) {
1515 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
1516 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001517 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Calin Juravlee460d1d2015-09-29 04:52:17 +01001518 } else if (source.IsRegisterPair()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001519 size_t elem_size = DataType::Size(DataType::Type::kInt32);
Vladimir Markodec78172020-06-19 15:31:23 +01001520 // Push the 2 source registers to the stack.
1521 __ pushl(source.AsRegisterPairHigh<Register>());
1522 __ cfi().AdjustCFAOffset(elem_size);
1523 __ pushl(source.AsRegisterPairLow<Register>());
1524 __ cfi().AdjustCFAOffset(elem_size);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001525 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
1526 // And remove the temporary stack space we allocated.
Vladimir Markodec78172020-06-19 15:31:23 +01001527 DecreaseFrame(2 * elem_size);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001528 } else {
1529 LOG(FATAL) << "Unimplemented";
1530 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001531 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00001532 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001533 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001534 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001535 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001536 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001537 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001538 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001539 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001540 } else if (source.IsConstant()) {
1541 HConstant* constant = source.GetConstant();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001542 DCHECK(constant->IsLongConstant() || constant->IsDoubleConstant());
1543 int64_t value = GetInt64ValueOf(constant);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001544 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01001545 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
1546 Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001547 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001548 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001549 EmitParallelMoves(
1550 Location::StackSlot(source.GetStackIndex()),
1551 Location::StackSlot(destination.GetStackIndex()),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001552 DataType::Type::kInt32,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001553 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001554 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001555 DataType::Type::kInt32);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001556 }
1557 }
1558}
1559
Andra Danciu1ca6f322020-08-12 08:58:07 +00001560static Address CreateAddress(Register base,
1561 Register index = Register::kNoRegister,
1562 ScaleFactor scale = TIMES_1,
1563 int32_t disp = 0) {
1564 if (index == Register::kNoRegister) {
1565 return Address(base, disp);
1566 }
1567
1568 return Address(base, index, scale, disp);
1569}
1570
Andra Danciud0f71f22020-09-17 09:00:15 +00001571void CodeGeneratorX86::LoadFromMemoryNoBarrier(DataType::Type dst_type,
1572 Location dst,
1573 Address src,
Ulya Trafimovich322eced2021-06-02 15:39:36 +01001574 HInstruction* instr,
Andra Danciud0f71f22020-09-17 09:00:15 +00001575 XmmRegister temp,
1576 bool is_atomic_load) {
Andra Danciu1ca6f322020-08-12 08:58:07 +00001577 switch (dst_type) {
1578 case DataType::Type::kBool:
1579 case DataType::Type::kUint8:
1580 __ movzxb(dst.AsRegister<Register>(), src);
1581 break;
1582 case DataType::Type::kInt8:
1583 __ movsxb(dst.AsRegister<Register>(), src);
1584 break;
1585 case DataType::Type::kInt16:
1586 __ movsxw(dst.AsRegister<Register>(), src);
1587 break;
1588 case DataType::Type::kUint16:
1589 __ movzxw(dst.AsRegister<Register>(), src);
1590 break;
1591 case DataType::Type::kInt32:
Andra Danciu1ca6f322020-08-12 08:58:07 +00001592 __ movl(dst.AsRegister<Register>(), src);
1593 break;
Andra Danciud0f71f22020-09-17 09:00:15 +00001594 case DataType::Type::kInt64: {
1595 if (is_atomic_load) {
1596 __ movsd(temp, src);
Ulya Trafimovich322eced2021-06-02 15:39:36 +01001597 if (instr != nullptr) {
1598 MaybeRecordImplicitNullCheck(instr);
1599 }
Andra Danciud0f71f22020-09-17 09:00:15 +00001600 __ movd(dst.AsRegisterPairLow<Register>(), temp);
1601 __ psrlq(temp, Immediate(32));
1602 __ movd(dst.AsRegisterPairHigh<Register>(), temp);
1603 } else {
1604 DCHECK_NE(src.GetBaseRegister(), dst.AsRegisterPairLow<Register>());
Ulya Trafimovich893e2ed2021-06-10 16:18:12 +01001605 Address src_high = Address::displace(src, kX86WordSize);
Andra Danciud0f71f22020-09-17 09:00:15 +00001606 __ movl(dst.AsRegisterPairLow<Register>(), src);
Ulya Trafimovich322eced2021-06-02 15:39:36 +01001607 if (instr != nullptr) {
1608 MaybeRecordImplicitNullCheck(instr);
1609 }
Andra Danciud0f71f22020-09-17 09:00:15 +00001610 __ movl(dst.AsRegisterPairHigh<Register>(), src_high);
1611 }
Andra Danciu1ca6f322020-08-12 08:58:07 +00001612 break;
1613 }
1614 case DataType::Type::kFloat32:
1615 __ movss(dst.AsFpuRegister<XmmRegister>(), src);
1616 break;
1617 case DataType::Type::kFloat64:
1618 __ movsd(dst.AsFpuRegister<XmmRegister>(), src);
1619 break;
Andra Danciu1ca6f322020-08-12 08:58:07 +00001620 case DataType::Type::kReference:
Ulya Trafimovich322eced2021-06-02 15:39:36 +01001621 DCHECK(!kEmitCompilerReadBarrier);
Andra Danciud0f71f22020-09-17 09:00:15 +00001622 __ movl(dst.AsRegister<Register>(), src);
1623 __ MaybeUnpoisonHeapReference(dst.AsRegister<Register>());
1624 break;
1625 default:
Andra Danciu1ca6f322020-08-12 08:58:07 +00001626 LOG(FATAL) << "Unreachable type " << dst_type;
1627 }
Ulya Trafimovich322eced2021-06-02 15:39:36 +01001628 if (instr != nullptr && dst_type != DataType::Type::kInt64) {
1629 // kInt64 needs special handling that is done in the above switch.
1630 MaybeRecordImplicitNullCheck(instr);
1631 }
Andra Danciu1ca6f322020-08-12 08:58:07 +00001632}
1633
Andra Danciu73c31802020-09-01 13:17:05 +00001634void CodeGeneratorX86::MoveToMemory(DataType::Type src_type,
1635 Location src,
1636 Register dst_base,
1637 Register dst_index,
1638 ScaleFactor dst_scale,
1639 int32_t dst_disp) {
1640 DCHECK(dst_base != Register::kNoRegister);
1641 Address dst = CreateAddress(dst_base, dst_index, dst_scale, dst_disp);
1642
1643 switch (src_type) {
1644 case DataType::Type::kBool:
1645 case DataType::Type::kUint8:
1646 case DataType::Type::kInt8: {
1647 if (src.IsConstant()) {
1648 __ movb(dst, Immediate(CodeGenerator::GetInt8ValueOf(src.GetConstant())));
1649 } else {
1650 __ movb(dst, src.AsRegister<ByteRegister>());
1651 }
1652 break;
1653 }
1654 case DataType::Type::kUint16:
1655 case DataType::Type::kInt16: {
1656 if (src.IsConstant()) {
1657 __ movw(dst, Immediate(CodeGenerator::GetInt16ValueOf(src.GetConstant())));
1658 } else {
1659 __ movw(dst, src.AsRegister<Register>());
1660 }
1661 break;
1662 }
1663 case DataType::Type::kUint32:
1664 case DataType::Type::kInt32: {
1665 if (src.IsConstant()) {
1666 int32_t v = CodeGenerator::GetInt32ValueOf(src.GetConstant());
1667 __ movl(dst, Immediate(v));
1668 } else {
1669 __ movl(dst, src.AsRegister<Register>());
1670 }
1671 break;
1672 }
1673 case DataType::Type::kUint64:
1674 case DataType::Type::kInt64: {
1675 Address dst_next_4_bytes = CreateAddress(dst_base, dst_index, dst_scale, dst_disp + 4);
1676 if (src.IsConstant()) {
1677 int64_t v = CodeGenerator::GetInt64ValueOf(src.GetConstant());
1678 __ movl(dst, Immediate(Low32Bits(v)));
1679 __ movl(dst_next_4_bytes, Immediate(High32Bits(v)));
1680 } else {
1681 __ movl(dst, src.AsRegisterPairLow<Register>());
1682 __ movl(dst_next_4_bytes, src.AsRegisterPairHigh<Register>());
1683 }
1684 break;
1685 }
1686 case DataType::Type::kFloat32: {
1687 if (src.IsConstant()) {
1688 int32_t v = CodeGenerator::GetInt32ValueOf(src.GetConstant());
1689 __ movl(dst, Immediate(v));
1690 } else {
1691 __ movss(dst, src.AsFpuRegister<XmmRegister>());
1692 }
1693 break;
1694 }
1695 case DataType::Type::kFloat64: {
1696 Address dst_next_4_bytes = CreateAddress(dst_base, dst_index, dst_scale, dst_disp + 4);
1697 if (src.IsConstant()) {
1698 int64_t v = CodeGenerator::GetInt64ValueOf(src.GetConstant());
1699 __ movl(dst, Immediate(Low32Bits(v)));
1700 __ movl(dst_next_4_bytes, Immediate(High32Bits(v)));
1701 } else {
1702 __ movsd(dst, src.AsFpuRegister<XmmRegister>());
1703 }
1704 break;
1705 }
1706 case DataType::Type::kVoid:
1707 case DataType::Type::kReference:
1708 LOG(FATAL) << "Unreachable type " << src_type;
1709 }
1710}
1711
Calin Juravle175dc732015-08-25 15:42:32 +01001712void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
1713 DCHECK(location.IsRegister());
1714 __ movl(location.AsRegister<Register>(), Immediate(value));
1715}
1716
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001717void CodeGeneratorX86::MoveLocation(Location dst, Location src, DataType::Type dst_type) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001718 HParallelMove move(GetGraph()->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001719 if (dst_type == DataType::Type::kInt64 && !src.IsConstant() && !src.IsFpuRegister()) {
1720 move.AddMove(src.ToLow(), dst.ToLow(), DataType::Type::kInt32, nullptr);
1721 move.AddMove(src.ToHigh(), dst.ToHigh(), DataType::Type::kInt32, nullptr);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001722 } else {
David Brazdil74eb1b22015-12-14 11:44:01 +00001723 move.AddMove(src, dst, dst_type, nullptr);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001724 }
David Brazdil74eb1b22015-12-14 11:44:01 +00001725 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001726}
1727
1728void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) {
1729 if (location.IsRegister()) {
1730 locations->AddTemp(location);
1731 } else if (location.IsRegisterPair()) {
1732 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1733 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1734 } else {
1735 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1736 }
1737}
1738
David Brazdilfc6a86a2015-06-26 10:33:45 +00001739void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Aart Bika8b8e9b2018-01-09 11:01:02 -08001740 if (successor->IsExitBlock()) {
1741 DCHECK(got->GetPrevious()->AlwaysThrows());
1742 return; // no code needed
1743 }
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001744
1745 HBasicBlock* block = got->GetBlock();
1746 HInstruction* previous = got->GetPrevious();
1747
1748 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001749 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +00001750 codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001751 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1752 return;
1753 }
1754
1755 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1756 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1757 }
1758 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001759 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001760 }
1761}
1762
David Brazdilfc6a86a2015-06-26 10:33:45 +00001763void LocationsBuilderX86::VisitGoto(HGoto* got) {
1764 got->SetLocations(nullptr);
1765}
1766
1767void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
1768 HandleGoto(got, got->GetSuccessor());
1769}
1770
1771void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1772 try_boundary->SetLocations(nullptr);
1773}
1774
1775void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1776 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1777 if (!successor->IsExitBlock()) {
1778 HandleGoto(try_boundary, successor);
1779 }
1780}
1781
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001782void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001783 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001784}
1785
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001786void InstructionCodeGeneratorX86::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001787}
1788
Mark Mendell152408f2015-12-31 12:28:50 -05001789template<class LabelType>
Mark Mendellc4701932015-04-10 13:18:51 -04001790void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
Mark Mendell152408f2015-12-31 12:28:50 -05001791 LabelType* true_label,
1792 LabelType* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001793 if (cond->IsFPConditionTrueIfNaN()) {
1794 __ j(kUnordered, true_label);
1795 } else if (cond->IsFPConditionFalseIfNaN()) {
1796 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001797 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001798 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001799}
1800
Mark Mendell152408f2015-12-31 12:28:50 -05001801template<class LabelType>
Mark Mendellc4701932015-04-10 13:18:51 -04001802void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
Mark Mendell152408f2015-12-31 12:28:50 -05001803 LabelType* true_label,
1804 LabelType* false_label) {
Mark Mendellc4701932015-04-10 13:18:51 -04001805 LocationSummary* locations = cond->GetLocations();
1806 Location left = locations->InAt(0);
1807 Location right = locations->InAt(1);
1808 IfCondition if_cond = cond->GetCondition();
1809
Mark Mendellc4701932015-04-10 13:18:51 -04001810 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001811 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001812 IfCondition true_high_cond = if_cond;
1813 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001814 Condition final_condition = X86UnsignedOrFPCondition(if_cond); // unsigned on lower part
Mark Mendellc4701932015-04-10 13:18:51 -04001815
1816 // Set the conditions for the test, remembering that == needs to be
1817 // decided using the low words.
1818 switch (if_cond) {
1819 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001820 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001821 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001822 break;
1823 case kCondLT:
1824 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001825 break;
1826 case kCondLE:
1827 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001828 break;
1829 case kCondGT:
1830 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001831 break;
1832 case kCondGE:
1833 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001834 break;
Aart Bike9f37602015-10-09 11:15:55 -07001835 case kCondB:
1836 false_high_cond = kCondA;
1837 break;
1838 case kCondBE:
1839 true_high_cond = kCondB;
1840 break;
1841 case kCondA:
1842 false_high_cond = kCondB;
1843 break;
1844 case kCondAE:
1845 true_high_cond = kCondA;
1846 break;
Mark Mendellc4701932015-04-10 13:18:51 -04001847 }
1848
1849 if (right.IsConstant()) {
1850 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001851 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001852 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001853
Aart Bika19616e2016-02-01 18:57:58 -08001854 codegen_->Compare32BitValue(left_high, val_high);
Mark Mendellc4701932015-04-10 13:18:51 -04001855 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001856 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001857 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001858 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001859 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001860 __ j(X86Condition(true_high_cond), true_label);
1861 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001862 }
1863 // Must be equal high, so compare the lows.
Aart Bika19616e2016-02-01 18:57:58 -08001864 codegen_->Compare32BitValue(left_low, val_low);
Mark Mendell8659e842016-02-16 10:41:46 -05001865 } else if (right.IsRegisterPair()) {
Mark Mendellc4701932015-04-10 13:18:51 -04001866 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001867 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001868
1869 __ cmpl(left_high, right_high);
1870 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001871 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001872 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001873 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001874 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001875 __ j(X86Condition(true_high_cond), true_label);
1876 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001877 }
1878 // Must be equal high, so compare the lows.
1879 __ cmpl(left_low, right_low);
Mark Mendell8659e842016-02-16 10:41:46 -05001880 } else {
1881 DCHECK(right.IsDoubleStackSlot());
1882 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
1883 if (if_cond == kCondNE) {
1884 __ j(X86Condition(true_high_cond), true_label);
1885 } else if (if_cond == kCondEQ) {
1886 __ j(X86Condition(false_high_cond), false_label);
1887 } else {
1888 __ j(X86Condition(true_high_cond), true_label);
1889 __ j(X86Condition(false_high_cond), false_label);
1890 }
1891 // Must be equal high, so compare the lows.
1892 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Mark Mendellc4701932015-04-10 13:18:51 -04001893 }
1894 // The last comparison might be unsigned.
1895 __ j(final_condition, true_label);
1896}
1897
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00001898void InstructionCodeGeneratorX86::GenerateFPCompare(Location lhs,
1899 Location rhs,
1900 HInstruction* insn,
1901 bool is_double) {
1902 HX86LoadFromConstantTable* const_area = insn->InputAt(1)->AsX86LoadFromConstantTable();
1903 if (is_double) {
1904 if (rhs.IsFpuRegister()) {
1905 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1906 } else if (const_area != nullptr) {
1907 DCHECK(const_area->IsEmittedAtUseSite());
1908 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(),
1909 codegen_->LiteralDoubleAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00001910 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
1911 const_area->GetBaseMethodAddress(),
1912 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00001913 } else {
1914 DCHECK(rhs.IsDoubleStackSlot());
1915 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
1916 }
1917 } else {
1918 if (rhs.IsFpuRegister()) {
1919 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1920 } else if (const_area != nullptr) {
1921 DCHECK(const_area->IsEmittedAtUseSite());
1922 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(),
1923 codegen_->LiteralFloatAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00001924 const_area->GetConstant()->AsFloatConstant()->GetValue(),
1925 const_area->GetBaseMethodAddress(),
1926 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00001927 } else {
1928 DCHECK(rhs.IsStackSlot());
1929 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
1930 }
1931 }
1932}
1933
Mark Mendell152408f2015-12-31 12:28:50 -05001934template<class LabelType>
David Brazdil0debae72015-11-12 18:37:00 +00001935void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condition,
Mark Mendell152408f2015-12-31 12:28:50 -05001936 LabelType* true_target_in,
1937 LabelType* false_target_in) {
David Brazdil0debae72015-11-12 18:37:00 +00001938 // Generated branching requires both targets to be explicit. If either of the
1939 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
Mark Mendell152408f2015-12-31 12:28:50 -05001940 LabelType fallthrough_target;
1941 LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1942 LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
David Brazdil0debae72015-11-12 18:37:00 +00001943
Mark Mendellc4701932015-04-10 13:18:51 -04001944 LocationSummary* locations = condition->GetLocations();
1945 Location left = locations->InAt(0);
1946 Location right = locations->InAt(1);
1947
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001948 DataType::Type type = condition->InputAt(0)->GetType();
Mark Mendellc4701932015-04-10 13:18:51 -04001949 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001950 case DataType::Type::kInt64:
Mark Mendellc4701932015-04-10 13:18:51 -04001951 GenerateLongComparesAndJumps(condition, true_target, false_target);
1952 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001953 case DataType::Type::kFloat32:
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00001954 GenerateFPCompare(left, right, condition, false);
Mark Mendellc4701932015-04-10 13:18:51 -04001955 GenerateFPJumps(condition, true_target, false_target);
1956 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001957 case DataType::Type::kFloat64:
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00001958 GenerateFPCompare(left, right, condition, true);
Mark Mendellc4701932015-04-10 13:18:51 -04001959 GenerateFPJumps(condition, true_target, false_target);
1960 break;
1961 default:
1962 LOG(FATAL) << "Unexpected compare type " << type;
1963 }
1964
David Brazdil0debae72015-11-12 18:37:00 +00001965 if (false_target != &fallthrough_target) {
Mark Mendellc4701932015-04-10 13:18:51 -04001966 __ jmp(false_target);
1967 }
David Brazdil0debae72015-11-12 18:37:00 +00001968
1969 if (fallthrough_target.IsLinked()) {
1970 __ Bind(&fallthrough_target);
1971 }
Mark Mendellc4701932015-04-10 13:18:51 -04001972}
1973
David Brazdil0debae72015-11-12 18:37:00 +00001974static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) {
1975 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS
1976 // are set only strictly before `branch`. We can't use the eflags on long/FP
1977 // conditions if they are materialized due to the complex branching.
1978 return cond->IsCondition() &&
1979 cond->GetNext() == branch &&
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001980 cond->InputAt(0)->GetType() != DataType::Type::kInt64 &&
1981 !DataType::IsFloatingPointType(cond->InputAt(0)->GetType());
David Brazdil0debae72015-11-12 18:37:00 +00001982}
1983
Mark Mendell152408f2015-12-31 12:28:50 -05001984template<class LabelType>
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001985void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001986 size_t condition_input_index,
Mark Mendell152408f2015-12-31 12:28:50 -05001987 LabelType* true_target,
1988 LabelType* false_target) {
David Brazdil0debae72015-11-12 18:37:00 +00001989 HInstruction* cond = instruction->InputAt(condition_input_index);
1990
1991 if (true_target == nullptr && false_target == nullptr) {
1992 // Nothing to do. The code always falls through.
1993 return;
1994 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001995 // Constant condition, statically compared against "true" (integer value 1).
1996 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001997 if (true_target != nullptr) {
1998 __ jmp(true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001999 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002000 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00002001 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00002002 if (false_target != nullptr) {
2003 __ jmp(false_target);
2004 }
2005 }
2006 return;
2007 }
2008
2009 // The following code generates these patterns:
2010 // (1) true_target == nullptr && false_target != nullptr
2011 // - opposite condition true => branch to false_target
2012 // (2) true_target != nullptr && false_target == nullptr
2013 // - condition true => branch to true_target
2014 // (3) true_target != nullptr && false_target != nullptr
2015 // - condition true => branch to true_target
2016 // - branch to false_target
2017 if (IsBooleanValueOrMaterializedCondition(cond)) {
2018 if (AreEflagsSetFrom(cond, instruction)) {
2019 if (true_target == nullptr) {
2020 __ j(X86Condition(cond->AsCondition()->GetOppositeCondition()), false_target);
2021 } else {
2022 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
2023 }
2024 } else {
2025 // Materialized condition, compare against 0.
2026 Location lhs = instruction->GetLocations()->InAt(condition_input_index);
2027 if (lhs.IsRegister()) {
2028 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
2029 } else {
2030 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
2031 }
2032 if (true_target == nullptr) {
2033 __ j(kEqual, false_target);
2034 } else {
2035 __ j(kNotEqual, true_target);
2036 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002037 }
2038 } else {
David Brazdil0debae72015-11-12 18:37:00 +00002039 // Condition has not been materialized, use its inputs as the comparison and
2040 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04002041 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00002042
2043 // If this is a long or FP comparison that has been folded into
2044 // the HCondition, generate the comparison directly.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002045 DataType::Type type = condition->InputAt(0)->GetType();
2046 if (type == DataType::Type::kInt64 || DataType::IsFloatingPointType(type)) {
David Brazdil0debae72015-11-12 18:37:00 +00002047 GenerateCompareTestAndBranch(condition, true_target, false_target);
2048 return;
2049 }
2050
2051 Location lhs = condition->GetLocations()->InAt(0);
2052 Location rhs = condition->GetLocations()->InAt(1);
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002053 // LHS is guaranteed to be in a register (see LocationsBuilderX86::HandleCondition).
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01002054 codegen_->GenerateIntCompare(lhs, rhs);
David Brazdil0debae72015-11-12 18:37:00 +00002055 if (true_target == nullptr) {
2056 __ j(X86Condition(condition->GetOppositeCondition()), false_target);
2057 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04002058 __ j(X86Condition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07002059 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002060 }
David Brazdil0debae72015-11-12 18:37:00 +00002061
2062 // If neither branch falls through (case 3), the conditional branch to `true_target`
2063 // was already emitted (case 2) and we need to emit a jump to `false_target`.
2064 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002065 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002066 }
2067}
2068
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002069void LocationsBuilderX86::VisitIf(HIf* if_instr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002070 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00002071 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002072 locations->SetInAt(0, Location::Any());
2073 }
2074}
2075
2076void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002077 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2078 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2079 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2080 nullptr : codegen_->GetLabelOf(true_successor);
2081 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2082 nullptr : codegen_->GetLabelOf(false_successor);
Andreas Gampe3db70682018-12-26 15:12:03 -08002083 GenerateTestAndBranch(if_instr, /* condition_input_index= */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002084}
2085
2086void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002087 LocationSummary* locations = new (GetGraph()->GetAllocator())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002088 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002089 InvokeRuntimeCallingConvention calling_convention;
2090 RegisterSet caller_saves = RegisterSet::Empty();
2091 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2092 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00002093 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002094 locations->SetInAt(0, Location::Any());
2095 }
2096}
2097
2098void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08002099 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathX86>(deoptimize);
David Brazdil74eb1b22015-12-14 11:44:01 +00002100 GenerateTestAndBranch<Label>(deoptimize,
Andreas Gampe3db70682018-12-26 15:12:03 -08002101 /* condition_input_index= */ 0,
David Brazdil74eb1b22015-12-14 11:44:01 +00002102 slow_path->GetEntryLabel(),
Andreas Gampe3db70682018-12-26 15:12:03 -08002103 /* false_target= */ nullptr);
David Brazdil74eb1b22015-12-14 11:44:01 +00002104}
2105
Mingyao Yang063fc772016-08-02 11:02:54 -07002106void LocationsBuilderX86::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002107 LocationSummary* locations = new (GetGraph()->GetAllocator())
Mingyao Yang063fc772016-08-02 11:02:54 -07002108 LocationSummary(flag, LocationSummary::kNoCall);
2109 locations->SetOut(Location::RequiresRegister());
2110}
2111
2112void InstructionCodeGeneratorX86::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2113 __ movl(flag->GetLocations()->Out().AsRegister<Register>(),
2114 Address(ESP, codegen_->GetStackOffsetOfShouldDeoptimizeFlag()));
2115}
2116
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002117static bool SelectCanUseCMOV(HSelect* select) {
2118 // There are no conditional move instructions for XMMs.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002119 if (DataType::IsFloatingPointType(select->GetType())) {
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002120 return false;
2121 }
2122
2123 // A FP condition doesn't generate the single CC that we need.
2124 // In 32 bit mode, a long condition doesn't generate a single CC either.
2125 HInstruction* condition = select->GetCondition();
2126 if (condition->IsCondition()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002127 DataType::Type compare_type = condition->InputAt(0)->GetType();
2128 if (compare_type == DataType::Type::kInt64 ||
2129 DataType::IsFloatingPointType(compare_type)) {
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002130 return false;
2131 }
2132 }
2133
2134 // We can generate a CMOV for this Select.
2135 return true;
2136}
2137
David Brazdil74eb1b22015-12-14 11:44:01 +00002138void LocationsBuilderX86::VisitSelect(HSelect* select) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002139 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002140 if (DataType::IsFloatingPointType(select->GetType())) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002141 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002142 locations->SetInAt(1, Location::Any());
David Brazdil74eb1b22015-12-14 11:44:01 +00002143 } else {
2144 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002145 if (SelectCanUseCMOV(select)) {
2146 if (select->InputAt(1)->IsConstant()) {
2147 // Cmov can't handle a constant value.
2148 locations->SetInAt(1, Location::RequiresRegister());
2149 } else {
2150 locations->SetInAt(1, Location::Any());
2151 }
2152 } else {
2153 locations->SetInAt(1, Location::Any());
2154 }
David Brazdil74eb1b22015-12-14 11:44:01 +00002155 }
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002156 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
2157 locations->SetInAt(2, Location::RequiresRegister());
David Brazdil74eb1b22015-12-14 11:44:01 +00002158 }
2159 locations->SetOut(Location::SameAsFirstInput());
2160}
2161
2162void InstructionCodeGeneratorX86::VisitSelect(HSelect* select) {
2163 LocationSummary* locations = select->GetLocations();
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002164 DCHECK(locations->InAt(0).Equals(locations->Out()));
2165 if (SelectCanUseCMOV(select)) {
2166 // If both the condition and the source types are integer, we can generate
2167 // a CMOV to implement Select.
2168
2169 HInstruction* select_condition = select->GetCondition();
2170 Condition cond = kNotEqual;
2171
2172 // Figure out how to test the 'condition'.
2173 if (select_condition->IsCondition()) {
2174 HCondition* condition = select_condition->AsCondition();
2175 if (!condition->IsEmittedAtUseSite()) {
2176 // This was a previously materialized condition.
2177 // Can we use the existing condition code?
2178 if (AreEflagsSetFrom(condition, select)) {
2179 // Materialization was the previous instruction. Condition codes are right.
2180 cond = X86Condition(condition->GetCondition());
2181 } else {
2182 // No, we have to recreate the condition code.
2183 Register cond_reg = locations->InAt(2).AsRegister<Register>();
2184 __ testl(cond_reg, cond_reg);
2185 }
2186 } else {
2187 // We can't handle FP or long here.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002188 DCHECK_NE(condition->InputAt(0)->GetType(), DataType::Type::kInt64);
2189 DCHECK(!DataType::IsFloatingPointType(condition->InputAt(0)->GetType()));
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002190 LocationSummary* cond_locations = condition->GetLocations();
Roland Levillain0b671c02016-08-19 12:02:34 +01002191 codegen_->GenerateIntCompare(cond_locations->InAt(0), cond_locations->InAt(1));
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002192 cond = X86Condition(condition->GetCondition());
2193 }
2194 } else {
Roland Levillain5e8d5f02016-10-18 18:03:43 +01002195 // Must be a Boolean condition, which needs to be compared to 0.
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002196 Register cond_reg = locations->InAt(2).AsRegister<Register>();
2197 __ testl(cond_reg, cond_reg);
2198 }
2199
2200 // If the condition is true, overwrite the output, which already contains false.
2201 Location false_loc = locations->InAt(0);
2202 Location true_loc = locations->InAt(1);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002203 if (select->GetType() == DataType::Type::kInt64) {
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002204 // 64 bit conditional move.
2205 Register false_high = false_loc.AsRegisterPairHigh<Register>();
2206 Register false_low = false_loc.AsRegisterPairLow<Register>();
2207 if (true_loc.IsRegisterPair()) {
2208 __ cmovl(cond, false_high, true_loc.AsRegisterPairHigh<Register>());
2209 __ cmovl(cond, false_low, true_loc.AsRegisterPairLow<Register>());
2210 } else {
2211 __ cmovl(cond, false_high, Address(ESP, true_loc.GetHighStackIndex(kX86WordSize)));
2212 __ cmovl(cond, false_low, Address(ESP, true_loc.GetStackIndex()));
2213 }
2214 } else {
2215 // 32 bit conditional move.
2216 Register false_reg = false_loc.AsRegister<Register>();
2217 if (true_loc.IsRegister()) {
2218 __ cmovl(cond, false_reg, true_loc.AsRegister<Register>());
2219 } else {
2220 __ cmovl(cond, false_reg, Address(ESP, true_loc.GetStackIndex()));
2221 }
2222 }
2223 } else {
2224 NearLabel false_target;
2225 GenerateTestAndBranch<NearLabel>(
Andreas Gampe3db70682018-12-26 15:12:03 -08002226 select, /* condition_input_index= */ 2, /* true_target= */ nullptr, &false_target);
Mark Mendell0c5b18e2016-02-06 13:58:35 -05002227 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
2228 __ Bind(&false_target);
2229 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002230}
2231
David Srbecky0cf44932015-12-09 14:09:59 +00002232void LocationsBuilderX86::VisitNativeDebugInfo(HNativeDebugInfo* info) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002233 new (GetGraph()->GetAllocator()) LocationSummary(info);
David Srbecky0cf44932015-12-09 14:09:59 +00002234}
2235
David Srbeckyd28f4a02016-03-14 17:14:24 +00002236void InstructionCodeGeneratorX86::VisitNativeDebugInfo(HNativeDebugInfo*) {
2237 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00002238}
2239
Vladimir Markodec78172020-06-19 15:31:23 +01002240void CodeGeneratorX86::IncreaseFrame(size_t adjustment) {
2241 __ subl(ESP, Immediate(adjustment));
2242 __ cfi().AdjustCFAOffset(adjustment);
2243}
2244
2245void CodeGeneratorX86::DecreaseFrame(size_t adjustment) {
2246 __ addl(ESP, Immediate(adjustment));
2247 __ cfi().AdjustCFAOffset(-adjustment);
2248}
2249
David Srbeckyc7098ff2016-02-09 14:30:11 +00002250void CodeGeneratorX86::GenerateNop() {
2251 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00002252}
2253
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002254void LocationsBuilderX86::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002255 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002256 new (GetGraph()->GetAllocator()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04002257 // Handle the long/FP comparisons made in instruction simplification.
2258 switch (cond->InputAt(0)->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002259 case DataType::Type::kInt64: {
Mark Mendellc4701932015-04-10 13:18:51 -04002260 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendell8659e842016-02-16 10:41:46 -05002261 locations->SetInAt(1, Location::Any());
David Brazdilb3e773e2016-01-26 11:28:37 +00002262 if (!cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04002263 locations->SetOut(Location::RequiresRegister());
2264 }
2265 break;
2266 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002267 case DataType::Type::kFloat32:
2268 case DataType::Type::kFloat64: {
Mark Mendellc4701932015-04-10 13:18:51 -04002269 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002270 if (cond->InputAt(1)->IsX86LoadFromConstantTable()) {
2271 DCHECK(cond->InputAt(1)->IsEmittedAtUseSite());
2272 } else if (cond->InputAt(1)->IsConstant()) {
2273 locations->SetInAt(1, Location::RequiresFpuRegister());
2274 } else {
2275 locations->SetInAt(1, Location::Any());
2276 }
David Brazdilb3e773e2016-01-26 11:28:37 +00002277 if (!cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04002278 locations->SetOut(Location::RequiresRegister());
2279 }
2280 break;
2281 }
2282 default:
2283 locations->SetInAt(0, Location::RequiresRegister());
2284 locations->SetInAt(1, Location::Any());
David Brazdilb3e773e2016-01-26 11:28:37 +00002285 if (!cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04002286 // We need a byte register.
2287 locations->SetOut(Location::RegisterLocation(ECX));
2288 }
2289 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002290 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00002291}
2292
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002293void InstructionCodeGeneratorX86::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002294 if (cond->IsEmittedAtUseSite()) {
Mark Mendellc4701932015-04-10 13:18:51 -04002295 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002296 }
Mark Mendellc4701932015-04-10 13:18:51 -04002297
2298 LocationSummary* locations = cond->GetLocations();
2299 Location lhs = locations->InAt(0);
2300 Location rhs = locations->InAt(1);
2301 Register reg = locations->Out().AsRegister<Register>();
Mark Mendell152408f2015-12-31 12:28:50 -05002302 NearLabel true_label, false_label;
Mark Mendellc4701932015-04-10 13:18:51 -04002303
2304 switch (cond->InputAt(0)->GetType()) {
2305 default: {
2306 // Integer case.
2307
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01002308 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04002309 __ xorl(reg, reg);
Roland Levillain0b671c02016-08-19 12:02:34 +01002310 codegen_->GenerateIntCompare(lhs, rhs);
Aart Bike9f37602015-10-09 11:15:55 -07002311 __ setb(X86Condition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04002312 return;
2313 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002314 case DataType::Type::kInt64:
Mark Mendellc4701932015-04-10 13:18:51 -04002315 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2316 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002317 case DataType::Type::kFloat32:
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002318 GenerateFPCompare(lhs, rhs, cond, false);
Mark Mendellc4701932015-04-10 13:18:51 -04002319 GenerateFPJumps(cond, &true_label, &false_label);
2320 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002321 case DataType::Type::kFloat64:
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002322 GenerateFPCompare(lhs, rhs, cond, true);
Mark Mendellc4701932015-04-10 13:18:51 -04002323 GenerateFPJumps(cond, &true_label, &false_label);
2324 break;
2325 }
2326
2327 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002328 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04002329
Roland Levillain4fa13f62015-07-06 18:11:54 +01002330 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04002331 __ Bind(&false_label);
2332 __ xorl(reg, reg);
2333 __ jmp(&done_label);
2334
Roland Levillain4fa13f62015-07-06 18:11:54 +01002335 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04002336 __ Bind(&true_label);
2337 __ movl(reg, Immediate(1));
2338 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07002339}
2340
2341void LocationsBuilderX86::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002342 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002343}
2344
2345void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002346 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002347}
2348
2349void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002350 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002351}
2352
2353void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002354 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002355}
2356
2357void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002358 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002359}
2360
2361void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002362 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002363}
2364
2365void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002366 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002367}
2368
2369void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002370 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002371}
2372
2373void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002374 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002375}
2376
2377void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002378 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002379}
2380
2381void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002382 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002383}
2384
2385void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002386 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002387}
2388
Aart Bike9f37602015-10-09 11:15:55 -07002389void LocationsBuilderX86::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002390 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002391}
2392
2393void InstructionCodeGeneratorX86::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002394 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002395}
2396
2397void LocationsBuilderX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002398 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002399}
2400
2401void InstructionCodeGeneratorX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002402 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002403}
2404
2405void LocationsBuilderX86::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002406 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002407}
2408
2409void InstructionCodeGeneratorX86::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002410 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002411}
2412
2413void LocationsBuilderX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002414 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002415}
2416
2417void InstructionCodeGeneratorX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002418 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002419}
2420
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002421void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002422 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002423 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002424 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00002425}
2426
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002427void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002428 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002429}
2430
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002431void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
2432 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002433 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002434 locations->SetOut(Location::ConstantLocation(constant));
2435}
2436
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002437void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002438 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00002439}
2440
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002441void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002442 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002443 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002444 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002445}
2446
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002447void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002448 // Will be generated at use site.
2449}
2450
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002451void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
2452 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002453 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002454 locations->SetOut(Location::ConstantLocation(constant));
2455}
2456
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002457void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002458 // Will be generated at use site.
2459}
2460
2461void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
2462 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002463 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002464 locations->SetOut(Location::ConstantLocation(constant));
2465}
2466
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002467void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002468 // Will be generated at use site.
2469}
2470
Igor Murashkind01745e2017-04-05 16:40:31 -07002471void LocationsBuilderX86::VisitConstructorFence(HConstructorFence* constructor_fence) {
2472 constructor_fence->SetLocations(nullptr);
2473}
2474
2475void InstructionCodeGeneratorX86::VisitConstructorFence(
2476 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
2477 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2478}
2479
Calin Juravle27df7582015-04-17 19:12:31 +01002480void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2481 memory_barrier->SetLocations(nullptr);
2482}
2483
2484void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00002485 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01002486}
2487
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002488void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002489 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00002490}
2491
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002492void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002493 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002494}
2495
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002496void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002497 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002498 new (GetGraph()->GetAllocator()) LocationSummary(ret, LocationSummary::kNoCall);
Mythri Alle2d4feeb2021-10-13 15:39:37 +00002499 SetInForReturnValue(ret, locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002500}
2501
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002502void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray57cacb72019-12-08 22:07:08 +00002503 switch (ret->InputAt(0)->GetType()) {
2504 case DataType::Type::kReference:
2505 case DataType::Type::kBool:
2506 case DataType::Type::kUint8:
2507 case DataType::Type::kInt8:
2508 case DataType::Type::kUint16:
2509 case DataType::Type::kInt16:
2510 case DataType::Type::kInt32:
2511 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
2512 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002513
Nicolas Geoffray57cacb72019-12-08 22:07:08 +00002514 case DataType::Type::kInt64:
2515 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
2516 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
2517 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002518
Nicolas Geoffray57cacb72019-12-08 22:07:08 +00002519 case DataType::Type::kFloat32:
2520 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
2521 if (GetGraph()->IsCompilingOsr()) {
2522 // To simplify callers of an OSR method, we put the return value in both
2523 // floating point and core registers.
2524 __ movd(EAX, XMM0);
2525 }
2526 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002527
Nicolas Geoffray57cacb72019-12-08 22:07:08 +00002528 case DataType::Type::kFloat64:
2529 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
2530 if (GetGraph()->IsCompilingOsr()) {
2531 // To simplify callers of an OSR method, we put the return value in both
2532 // floating point and core registers.
2533 __ movd(EAX, XMM0);
2534 // Use XMM1 as temporary register to not clobber XMM0.
2535 __ movaps(XMM1, XMM0);
2536 __ psrlq(XMM1, Immediate(32));
2537 __ movd(EDX, XMM1);
2538 }
2539 break;
2540
2541 default:
2542 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002543 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002544 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002545}
2546
Calin Juravle175dc732015-08-25 15:42:32 +01002547void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2548 // The trampoline uses the same calling convention as dex calling conventions,
2549 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
2550 // the method_idx.
2551 HandleInvoke(invoke);
2552}
2553
2554void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
2555 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
2556}
2557
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002558void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002559 // Explicit clinit checks triggered by static invokes must have been pruned by
2560 // art::PrepareForRegisterAllocation.
2561 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002562
Mark Mendellfb8d2792015-03-31 22:16:59 -04002563 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04002564 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markoeebb8212018-06-05 14:57:24 +01002565 if (invoke->GetLocations()->CanCall() &&
2566 invoke->HasPcRelativeMethodLoadKind() &&
2567 invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).IsInvalid()) {
Vladimir Markoc53c0792015-11-19 15:48:33 +00002568 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
Vladimir Marko0f7dca42015-11-02 14:36:43 +00002569 }
Mark Mendell09ed1a32015-03-25 08:30:06 -04002570 return;
2571 }
2572
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01002573 if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
Vladimir Marko86c87522020-05-11 16:55:55 +01002574 CriticalNativeCallingConventionVisitorX86 calling_convention_visitor(
2575 /*for_register_allocation=*/ true);
2576 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
2577 } else {
2578 HandleInvoke(invoke);
2579 }
Nicolas Geoffray94015b92015-06-04 18:21:04 +01002580
Vladimir Marko86c87522020-05-11 16:55:55 +01002581 // For PC-relative load kinds the invoke has an extra input, the PC-relative address base.
Vladimir Marko65979462017-05-19 17:25:12 +01002582 if (invoke->HasPcRelativeMethodLoadKind()) {
Vladimir Markob4536b72015-11-24 13:45:23 +00002583 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
Vladimir Marko0f7dca42015-11-02 14:36:43 +00002584 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002585}
2586
Mark Mendell09ed1a32015-03-25 08:30:06 -04002587static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
2588 if (invoke->GetLocations()->Intrinsified()) {
2589 IntrinsicCodeGeneratorX86 intrinsic(codegen);
2590 intrinsic.Dispatch(invoke);
2591 return true;
2592 }
2593 return false;
2594}
2595
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00002596void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00002597 // Explicit clinit checks triggered by static invokes must have been pruned by
2598 // art::PrepareForRegisterAllocation.
2599 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01002600
Mark Mendell09ed1a32015-03-25 08:30:06 -04002601 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2602 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002603 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002604
Nicolas Geoffray94015b92015-06-04 18:21:04 +01002605 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04002606 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01002607 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002608}
2609
2610void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffraye5234232015-12-02 09:06:11 +00002611 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
2612 if (intrinsic.TryDispatch(invoke)) {
2613 return;
2614 }
2615
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002616 HandleInvoke(invoke);
Nicolas Geoffray9b5271e2019-12-04 14:39:46 +00002617
2618 if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) {
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002619 // Add one temporary for inline cache update.
2620 invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP));
2621 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002622}
2623
2624void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002625 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002626 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002627}
2628
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01002629void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002630 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2631 return;
2632 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002633
Andreas Gampebfb5ba92015-09-01 15:45:02 +00002634 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002635 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00002636}
2637
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002638void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002639 // This call to HandleInvoke allocates a temporary (core) register
2640 // which is also used to transfer the hidden argument from FP to
2641 // core register.
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002642 HandleInvoke(invoke);
2643 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00002644 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002645
Nicolas Geoffray9b5271e2019-12-04 14:39:46 +00002646 if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) {
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002647 // Add one temporary for inline cache update.
2648 invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP));
2649 }
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01002650
2651 // For PC-relative load kinds the invoke has an extra input, the PC-relative address base.
2652 if (IsPcRelativeMethodLoadKind(invoke->GetHiddenArgumentLoadKind())) {
2653 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
2654 }
2655
2656 if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
2657 invoke->GetLocations()->SetInAt(invoke->GetNumberOfArguments() - 1,
2658 Location::RequiresRegister());
2659 }
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002660}
2661
2662void CodeGeneratorX86::MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass) {
2663 DCHECK_EQ(EAX, klass);
Nicolas Geoffray17a39ba2019-11-27 20:57:48 +00002664 // We know the destination of an intrinsic, so no need to record inline
2665 // caches (also the intrinsic location builder doesn't request an additional
2666 // temporary).
2667 if (!instruction->GetLocations()->Intrinsified() &&
Nicolas Geoffray9b5271e2019-12-04 14:39:46 +00002668 GetGraph()->IsCompilingBaseline() &&
Nicolas Geoffray17a39ba2019-11-27 20:57:48 +00002669 !Runtime::Current()->IsAotCompiler()) {
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002670 DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke());
Nicolas Geoffray095dc462020-08-17 16:40:28 +01002671 ScopedProfilingInfoUse spiu(
2672 Runtime::Current()->GetJit(), GetGraph()->GetArtMethod(), Thread::Current());
2673 ProfilingInfo* info = spiu.GetProfilingInfo();
Nicolas Geoffray796aa2c2019-12-17 10:20:05 +00002674 if (info != nullptr) {
2675 InlineCache* cache = info->GetInlineCache(instruction->GetDexPc());
2676 uint32_t address = reinterpret_cast32<uint32_t>(cache);
2677 if (kIsDebugBuild) {
2678 uint32_t temp_index = instruction->GetLocations()->GetTempCount() - 1u;
2679 CHECK_EQ(EBP, instruction->GetLocations()->GetTemp(temp_index).AsRegister<Register>());
2680 }
2681 Register temp = EBP;
2682 NearLabel done;
2683 __ movl(temp, Immediate(address));
2684 // Fast path for a monomorphic cache.
2685 __ cmpl(klass, Address(temp, InlineCache::ClassesOffset().Int32Value()));
2686 __ j(kEqual, &done);
2687 GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(kQuickUpdateInlineCache).Int32Value());
2688 __ Bind(&done);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002689 }
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002690 }
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002691}
2692
2693void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
2694 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain0d5a2812015-11-13 10:07:31 +00002695 LocationSummary* locations = invoke->GetLocations();
2696 Register temp = locations->GetTemp(0).AsRegister<Register>();
2697 XmmRegister hidden_reg = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002698 Location receiver = locations->InAt(0);
2699 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2700
Roland Levillain0d5a2812015-11-13 10:07:31 +00002701 // Set the hidden argument. This is safe to do this here, as XMM7
2702 // won't be modified thereafter, before the `call` instruction.
2703 DCHECK_EQ(XMM7, hidden_reg);
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01002704 if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRecursive) {
2705 __ movd(hidden_reg, locations->InAt(invoke->GetNumberOfArguments() - 1).AsRegister<Register>());
Nicolas Geoffrayd6bd1072020-11-30 18:42:01 +00002706 } else if (invoke->GetHiddenArgumentLoadKind() != MethodLoadKind::kRuntimeCall) {
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01002707 codegen_->LoadMethod(invoke->GetHiddenArgumentLoadKind(), locations->GetTemp(0), invoke);
2708 __ movd(hidden_reg, temp);
2709 }
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002710
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002711 if (receiver.IsStackSlot()) {
2712 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
Roland Levillain0d5a2812015-11-13 10:07:31 +00002713 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002714 __ movl(temp, Address(temp, class_offset));
2715 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00002716 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002717 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002718 }
Roland Levillain4d027112015-07-01 15:41:14 +01002719 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00002720 // Instead of simply (possibly) unpoisoning `temp` here, we should
2721 // emit a read barrier for the previous class reference load.
2722 // However this is not required in practice, as this is an
2723 // intermediate/temporary reference and because the current
2724 // concurrent copying collector keeps the from-space memory
2725 // intact/accessible until the end of the marking phase (the
2726 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002727 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00002728
2729 codegen_->MaybeGenerateInlineCacheCheck(invoke, temp);
2730
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002731 // temp = temp->GetAddressOfIMT()
2732 __ movl(temp,
2733 Address(temp, mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002734 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00002735 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00002736 invoke->GetImtIndex(), kX86PointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002737 __ movl(temp, Address(temp, method_offset));
Nicolas Geoffrayd6bd1072020-11-30 18:42:01 +00002738 if (invoke->GetHiddenArgumentLoadKind() == MethodLoadKind::kRuntimeCall) {
2739 // We pass the method from the IMT in case of a conflict. This will ensure
2740 // we go into the runtime to resolve the actual method.
2741 __ movd(hidden_reg, temp);
2742 }
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002743 // call temp->GetEntryPoint();
Roland Levillain0d5a2812015-11-13 10:07:31 +00002744 __ call(Address(temp,
Andreas Gampe542451c2016-07-26 09:02:02 -07002745 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002746
2747 DCHECK(!codegen_->IsLeafMethod());
2748 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2749}
2750
Orion Hodsonac141392017-01-13 11:53:47 +00002751void LocationsBuilderX86::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
Andra Danciua0130e82020-07-23 12:34:56 +00002752 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
2753 if (intrinsic.TryDispatch(invoke)) {
2754 return;
2755 }
Orion Hodsonac141392017-01-13 11:53:47 +00002756 HandleInvoke(invoke);
2757}
2758
2759void InstructionCodeGeneratorX86::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
Andra Danciua0130e82020-07-23 12:34:56 +00002760 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2761 return;
2762 }
Orion Hodsonac141392017-01-13 11:53:47 +00002763 codegen_->GenerateInvokePolymorphicCall(invoke);
2764}
2765
Orion Hodson4c8e12e2018-05-18 08:33:20 +01002766void LocationsBuilderX86::VisitInvokeCustom(HInvokeCustom* invoke) {
2767 HandleInvoke(invoke);
2768}
2769
2770void InstructionCodeGeneratorX86::VisitInvokeCustom(HInvokeCustom* invoke) {
2771 codegen_->GenerateInvokeCustomCall(invoke);
2772}
2773
Roland Levillain88cb1752014-10-20 16:36:47 +01002774void LocationsBuilderX86::VisitNeg(HNeg* neg) {
2775 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002776 new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
Roland Levillain88cb1752014-10-20 16:36:47 +01002777 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002778 case DataType::Type::kInt32:
2779 case DataType::Type::kInt64:
Roland Levillain88cb1752014-10-20 16:36:47 +01002780 locations->SetInAt(0, Location::RequiresRegister());
2781 locations->SetOut(Location::SameAsFirstInput());
2782 break;
2783
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002784 case DataType::Type::kFloat32:
Roland Levillain5368c212014-11-27 15:03:41 +00002785 locations->SetInAt(0, Location::RequiresFpuRegister());
2786 locations->SetOut(Location::SameAsFirstInput());
2787 locations->AddTemp(Location::RequiresRegister());
2788 locations->AddTemp(Location::RequiresFpuRegister());
2789 break;
2790
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002791 case DataType::Type::kFloat64:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002792 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00002793 locations->SetOut(Location::SameAsFirstInput());
2794 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01002795 break;
2796
2797 default:
2798 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2799 }
2800}
2801
2802void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
2803 LocationSummary* locations = neg->GetLocations();
2804 Location out = locations->Out();
2805 Location in = locations->InAt(0);
2806 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002807 case DataType::Type::kInt32:
Roland Levillain88cb1752014-10-20 16:36:47 +01002808 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002809 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002810 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01002811 break;
2812
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002813 case DataType::Type::kInt64:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002814 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002815 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002816 __ negl(out.AsRegisterPairLow<Register>());
2817 // Negation is similar to subtraction from zero. The least
2818 // significant byte triggers a borrow when it is different from
2819 // zero; to take it into account, add 1 to the most significant
2820 // byte if the carry flag (CF) is set to 1 after the first NEGL
2821 // operation.
2822 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
2823 __ negl(out.AsRegisterPairHigh<Register>());
2824 break;
2825
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002826 case DataType::Type::kFloat32: {
Roland Levillain5368c212014-11-27 15:03:41 +00002827 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002828 Register constant = locations->GetTemp(0).AsRegister<Register>();
2829 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002830 // Implement float negation with an exclusive or with value
2831 // 0x80000000 (mask for bit 31, representing the sign of a
2832 // single-precision floating-point number).
2833 __ movl(constant, Immediate(INT32_C(0x80000000)));
2834 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002835 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00002836 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002837 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00002838
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002839 case DataType::Type::kFloat64: {
Roland Levillain5368c212014-11-27 15:03:41 +00002840 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002841 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00002842 // Implement double negation with an exclusive or with value
2843 // 0x8000000000000000 (mask for bit 63, representing the sign of
2844 // a double-precision floating-point number).
2845 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002846 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01002847 break;
Roland Levillain5368c212014-11-27 15:03:41 +00002848 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002849
2850 default:
2851 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2852 }
2853}
2854
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002855void LocationsBuilderX86::VisitX86FPNeg(HX86FPNeg* neg) {
2856 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002857 new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002858 DCHECK(DataType::IsFloatingPointType(neg->GetType()));
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002859 locations->SetInAt(0, Location::RequiresFpuRegister());
2860 locations->SetInAt(1, Location::RequiresRegister());
2861 locations->SetOut(Location::SameAsFirstInput());
2862 locations->AddTemp(Location::RequiresFpuRegister());
2863}
2864
2865void InstructionCodeGeneratorX86::VisitX86FPNeg(HX86FPNeg* neg) {
2866 LocationSummary* locations = neg->GetLocations();
2867 Location out = locations->Out();
2868 DCHECK(locations->InAt(0).Equals(out));
2869
2870 Register constant_area = locations->InAt(1).AsRegister<Register>();
2871 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002872 if (neg->GetType() == DataType::Type::kFloat32) {
Nicolas Geoffray133719e2017-01-22 15:44:39 +00002873 __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x80000000),
2874 neg->GetBaseMethodAddress(),
2875 constant_area));
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002876 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
2877 } else {
Nicolas Geoffray133719e2017-01-22 15:44:39 +00002878 __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000),
2879 neg->GetBaseMethodAddress(),
2880 constant_area));
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00002881 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
2882 }
2883}
2884
Roland Levillaindff1f282014-11-05 14:15:05 +00002885void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002886 DataType::Type result_type = conversion->GetResultType();
2887 DataType::Type input_type = conversion->GetInputType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002888 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
2889 << input_type << " -> " << result_type;
Roland Levillain624279f2014-12-04 11:54:28 +00002890
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002891 // The float-to-long and double-to-long type conversions rely on a
2892 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002893 LocationSummary::CallKind call_kind =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002894 ((input_type == DataType::Type::kFloat32 || input_type == DataType::Type::kFloat64)
2895 && result_type == DataType::Type::kInt64)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002896 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00002897 : LocationSummary::kNoCall;
2898 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002899 new (GetGraph()->GetAllocator()) LocationSummary(conversion, call_kind);
Roland Levillain624279f2014-12-04 11:54:28 +00002900
Roland Levillaindff1f282014-11-05 14:15:05 +00002901 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002902 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002903 case DataType::Type::kInt8:
Roland Levillain51d3fc42014-11-13 14:11:42 +00002904 switch (input_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002905 case DataType::Type::kUint8:
2906 case DataType::Type::kInt8:
2907 case DataType::Type::kUint16:
2908 case DataType::Type::kInt16:
2909 case DataType::Type::kInt32:
2910 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
2911 // Make the output overlap to please the register allocator. This greatly simplifies
2912 // the validation of the linear scan implementation
2913 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2914 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002915 case DataType::Type::kInt64: {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002916 HInstruction* input = conversion->InputAt(0);
2917 Location input_location = input->IsConstant()
2918 ? Location::ConstantLocation(input->AsConstant())
2919 : Location::RegisterPairLocation(EAX, EDX);
2920 locations->SetInAt(0, input_location);
2921 // Make the output overlap to please the register allocator. This greatly simplifies
2922 // the validation of the linear scan implementation
2923 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2924 break;
2925 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00002926
2927 default:
2928 LOG(FATAL) << "Unexpected type conversion from " << input_type
2929 << " to " << result_type;
2930 }
2931 break;
2932
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002933 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002934 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002935 DCHECK(DataType::IsIntegralType(input_type)) << input_type;
2936 locations->SetInAt(0, Location::Any());
2937 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain01a8d712014-11-14 16:27:39 +00002938 break;
2939
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002940 case DataType::Type::kInt32:
Roland Levillain946e1432014-11-11 17:35:19 +00002941 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002942 case DataType::Type::kInt64:
Roland Levillain946e1432014-11-11 17:35:19 +00002943 locations->SetInAt(0, Location::Any());
2944 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2945 break;
2946
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002947 case DataType::Type::kFloat32:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002948 locations->SetInAt(0, Location::RequiresFpuRegister());
2949 locations->SetOut(Location::RequiresRegister());
2950 locations->AddTemp(Location::RequiresFpuRegister());
2951 break;
2952
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002953 case DataType::Type::kFloat64:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002954 locations->SetInAt(0, Location::RequiresFpuRegister());
2955 locations->SetOut(Location::RequiresRegister());
2956 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002957 break;
2958
2959 default:
2960 LOG(FATAL) << "Unexpected type conversion from " << input_type
2961 << " to " << result_type;
2962 }
2963 break;
2964
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002965 case DataType::Type::kInt64:
Roland Levillaindff1f282014-11-05 14:15:05 +00002966 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002967 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002968 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002969 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002970 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002971 case DataType::Type::kInt16:
2972 case DataType::Type::kInt32:
Roland Levillaindff1f282014-11-05 14:15:05 +00002973 locations->SetInAt(0, Location::RegisterLocation(EAX));
2974 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2975 break;
2976
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002977 case DataType::Type::kFloat32:
2978 case DataType::Type::kFloat64: {
Vladimir Marko949c91f2015-01-27 10:48:44 +00002979 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00002980 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
2981 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
2982
Vladimir Marko949c91f2015-01-27 10:48:44 +00002983 // The runtime helper puts the result in EAX, EDX.
2984 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00002985 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00002986 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00002987
2988 default:
2989 LOG(FATAL) << "Unexpected type conversion from " << input_type
2990 << " to " << result_type;
2991 }
2992 break;
2993
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002994 case DataType::Type::kFloat32:
Roland Levillaincff13742014-11-17 14:32:17 +00002995 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002996 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002997 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002998 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002999 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003000 case DataType::Type::kInt16:
3001 case DataType::Type::kInt32:
Roland Levillaincff13742014-11-17 14:32:17 +00003002 locations->SetInAt(0, Location::RequiresRegister());
3003 locations->SetOut(Location::RequiresFpuRegister());
3004 break;
3005
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003006 case DataType::Type::kInt64:
Roland Levillain232ade02015-04-20 15:14:36 +01003007 locations->SetInAt(0, Location::Any());
3008 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00003009 break;
3010
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003011 case DataType::Type::kFloat64:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003012 locations->SetInAt(0, Location::RequiresFpuRegister());
3013 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003014 break;
3015
3016 default:
3017 LOG(FATAL) << "Unexpected type conversion from " << input_type
3018 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08003019 }
Roland Levillaincff13742014-11-17 14:32:17 +00003020 break;
3021
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003022 case DataType::Type::kFloat64:
Roland Levillaincff13742014-11-17 14:32:17 +00003023 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003024 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003025 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003026 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003027 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003028 case DataType::Type::kInt16:
3029 case DataType::Type::kInt32:
Roland Levillaincff13742014-11-17 14:32:17 +00003030 locations->SetInAt(0, Location::RequiresRegister());
3031 locations->SetOut(Location::RequiresFpuRegister());
3032 break;
3033
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003034 case DataType::Type::kInt64:
Roland Levillain232ade02015-04-20 15:14:36 +01003035 locations->SetInAt(0, Location::Any());
3036 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00003037 break;
3038
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003039 case DataType::Type::kFloat32:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003040 locations->SetInAt(0, Location::RequiresFpuRegister());
3041 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003042 break;
3043
3044 default:
3045 LOG(FATAL) << "Unexpected type conversion from " << input_type
3046 << " to " << result_type;
3047 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003048 break;
3049
3050 default:
3051 LOG(FATAL) << "Unexpected type conversion from " << input_type
3052 << " to " << result_type;
3053 }
3054}
3055
3056void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
3057 LocationSummary* locations = conversion->GetLocations();
3058 Location out = locations->Out();
3059 Location in = locations->InAt(0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003060 DataType::Type result_type = conversion->GetResultType();
3061 DataType::Type input_type = conversion->GetInputType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003062 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
3063 << input_type << " -> " << result_type;
Roland Levillaindff1f282014-11-05 14:15:05 +00003064 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003065 case DataType::Type::kUint8:
3066 switch (input_type) {
3067 case DataType::Type::kInt8:
3068 case DataType::Type::kUint16:
3069 case DataType::Type::kInt16:
3070 case DataType::Type::kInt32:
3071 if (in.IsRegister()) {
3072 __ movzxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
3073 } else {
3074 DCHECK(in.GetConstant()->IsIntConstant());
3075 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3076 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
3077 }
3078 break;
3079 case DataType::Type::kInt64:
3080 if (in.IsRegisterPair()) {
3081 __ movzxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
3082 } else {
3083 DCHECK(in.GetConstant()->IsLongConstant());
3084 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3085 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
3086 }
3087 break;
3088
3089 default:
3090 LOG(FATAL) << "Unexpected type conversion from " << input_type
3091 << " to " << result_type;
3092 }
3093 break;
3094
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003095 case DataType::Type::kInt8:
Roland Levillain51d3fc42014-11-13 14:11:42 +00003096 switch (input_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003097 case DataType::Type::kUint8:
3098 case DataType::Type::kUint16:
3099 case DataType::Type::kInt16:
3100 case DataType::Type::kInt32:
3101 if (in.IsRegister()) {
3102 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
3103 } else {
3104 DCHECK(in.GetConstant()->IsIntConstant());
3105 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
3106 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
3107 }
3108 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003109 case DataType::Type::kInt64:
Vladimir Markob52bbde2016-02-12 12:06:05 +00003110 if (in.IsRegisterPair()) {
3111 __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
3112 } else {
3113 DCHECK(in.GetConstant()->IsLongConstant());
3114 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3115 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
3116 }
3117 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003118
3119 default:
3120 LOG(FATAL) << "Unexpected type conversion from " << input_type
3121 << " to " << result_type;
3122 }
3123 break;
3124
3125 case DataType::Type::kUint16:
3126 switch (input_type) {
3127 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003128 case DataType::Type::kInt16:
3129 case DataType::Type::kInt32:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003130 if (in.IsRegister()) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003131 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
3132 } else if (in.IsStackSlot()) {
3133 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003134 } else {
3135 DCHECK(in.GetConstant()->IsIntConstant());
3136 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003137 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
3138 }
3139 break;
3140 case DataType::Type::kInt64:
3141 if (in.IsRegisterPair()) {
3142 __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3143 } else if (in.IsDoubleStackSlot()) {
3144 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3145 } else {
3146 DCHECK(in.GetConstant()->IsLongConstant());
3147 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3148 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003149 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00003150 break;
3151
3152 default:
3153 LOG(FATAL) << "Unexpected type conversion from " << input_type
3154 << " to " << result_type;
3155 }
3156 break;
3157
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003158 case DataType::Type::kInt16:
Roland Levillain01a8d712014-11-14 16:27:39 +00003159 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003160 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003161 case DataType::Type::kInt32:
Roland Levillain01a8d712014-11-14 16:27:39 +00003162 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003163 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00003164 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003165 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00003166 } else {
3167 DCHECK(in.GetConstant()->IsIntConstant());
3168 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003169 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00003170 }
3171 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003172 case DataType::Type::kInt64:
3173 if (in.IsRegisterPair()) {
3174 __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
3175 } else if (in.IsDoubleStackSlot()) {
3176 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
3177 } else {
3178 DCHECK(in.GetConstant()->IsLongConstant());
3179 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
3180 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
3181 }
3182 break;
Roland Levillain01a8d712014-11-14 16:27:39 +00003183
3184 default:
3185 LOG(FATAL) << "Unexpected type conversion from " << input_type
3186 << " to " << result_type;
3187 }
3188 break;
3189
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003190 case DataType::Type::kInt32:
Roland Levillain946e1432014-11-11 17:35:19 +00003191 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003192 case DataType::Type::kInt64:
Roland Levillain946e1432014-11-11 17:35:19 +00003193 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003194 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00003195 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003196 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00003197 } else {
3198 DCHECK(in.IsConstant());
3199 DCHECK(in.GetConstant()->IsLongConstant());
3200 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003201 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00003202 }
3203 break;
3204
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003205 case DataType::Type::kFloat32: {
Roland Levillain3f8f9362014-12-02 17:45:01 +00003206 XmmRegister input = in.AsFpuRegister<XmmRegister>();
3207 Register output = out.AsRegister<Register>();
3208 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04003209 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00003210
3211 __ movl(output, Immediate(kPrimIntMax));
3212 // temp = int-to-float(output)
3213 __ cvtsi2ss(temp, output);
3214 // if input >= temp goto done
3215 __ comiss(input, temp);
3216 __ j(kAboveEqual, &done);
3217 // if input == NaN goto nan
3218 __ j(kUnordered, &nan);
3219 // output = float-to-int-truncate(input)
3220 __ cvttss2si(output, input);
3221 __ jmp(&done);
3222 __ Bind(&nan);
3223 // output = 0
3224 __ xorl(output, output);
3225 __ Bind(&done);
3226 break;
3227 }
3228
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003229 case DataType::Type::kFloat64: {
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003230 XmmRegister input = in.AsFpuRegister<XmmRegister>();
3231 Register output = out.AsRegister<Register>();
3232 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04003233 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003234
3235 __ movl(output, Immediate(kPrimIntMax));
3236 // temp = int-to-double(output)
3237 __ cvtsi2sd(temp, output);
3238 // if input >= temp goto done
3239 __ comisd(input, temp);
3240 __ j(kAboveEqual, &done);
3241 // if input == NaN goto nan
3242 __ j(kUnordered, &nan);
3243 // output = double-to-int-truncate(input)
3244 __ cvttsd2si(output, input);
3245 __ jmp(&done);
3246 __ Bind(&nan);
3247 // output = 0
3248 __ xorl(output, output);
3249 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00003250 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003251 }
Roland Levillain946e1432014-11-11 17:35:19 +00003252
3253 default:
3254 LOG(FATAL) << "Unexpected type conversion from " << input_type
3255 << " to " << result_type;
3256 }
3257 break;
3258
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003259 case DataType::Type::kInt64:
Roland Levillaindff1f282014-11-05 14:15:05 +00003260 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003261 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003262 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003263 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003264 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003265 case DataType::Type::kInt16:
3266 case DataType::Type::kInt32:
Roland Levillaindff1f282014-11-05 14:15:05 +00003267 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
3268 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003269 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00003270 __ cdq();
3271 break;
3272
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003273 case DataType::Type::kFloat32:
Serban Constantinescuba45db02016-07-12 22:53:02 +01003274 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003275 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00003276 break;
3277
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003278 case DataType::Type::kFloat64:
Serban Constantinescuba45db02016-07-12 22:53:02 +01003279 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003280 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00003281 break;
3282
3283 default:
3284 LOG(FATAL) << "Unexpected type conversion from " << input_type
3285 << " to " << result_type;
3286 }
3287 break;
3288
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003289 case DataType::Type::kFloat32:
Roland Levillaincff13742014-11-17 14:32:17 +00003290 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003291 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003292 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003293 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003294 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003295 case DataType::Type::kInt16:
3296 case DataType::Type::kInt32:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003297 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00003298 break;
3299
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003300 case DataType::Type::kInt64: {
Roland Levillain232ade02015-04-20 15:14:36 +01003301 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00003302
Roland Levillain232ade02015-04-20 15:14:36 +01003303 // Create stack space for the call to
3304 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
3305 // TODO: enhance register allocator to ask for stack temporaries.
3306 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003307 adjustment = DataType::Size(DataType::Type::kInt64);
Vladimir Markodec78172020-06-19 15:31:23 +01003308 codegen_->IncreaseFrame(adjustment);
Roland Levillain232ade02015-04-20 15:14:36 +01003309 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003310
Roland Levillain232ade02015-04-20 15:14:36 +01003311 // Load the value to the FP stack, using temporaries if needed.
3312 PushOntoFPStack(in, 0, adjustment, false, true);
3313
3314 if (out.IsStackSlot()) {
3315 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
3316 } else {
3317 __ fstps(Address(ESP, 0));
3318 Location stack_temp = Location::StackSlot(0);
3319 codegen_->Move32(out, stack_temp);
3320 }
3321
3322 // Remove the temporary stack space we allocated.
3323 if (adjustment != 0) {
Vladimir Markodec78172020-06-19 15:31:23 +01003324 codegen_->DecreaseFrame(adjustment);
Roland Levillain232ade02015-04-20 15:14:36 +01003325 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003326 break;
3327 }
3328
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003329 case DataType::Type::kFloat64:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003330 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003331 break;
3332
3333 default:
3334 LOG(FATAL) << "Unexpected type conversion from " << input_type
3335 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08003336 }
Roland Levillaincff13742014-11-17 14:32:17 +00003337 break;
3338
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003339 case DataType::Type::kFloat64:
Roland Levillaincff13742014-11-17 14:32:17 +00003340 switch (input_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003341 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003342 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003343 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003344 case DataType::Type::kUint16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003345 case DataType::Type::kInt16:
3346 case DataType::Type::kInt32:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003347 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00003348 break;
3349
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003350 case DataType::Type::kInt64: {
Roland Levillain232ade02015-04-20 15:14:36 +01003351 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00003352
Roland Levillain232ade02015-04-20 15:14:36 +01003353 // Create stack space for the call to
3354 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
3355 // TODO: enhance register allocator to ask for stack temporaries.
3356 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003357 adjustment = DataType::Size(DataType::Type::kInt64);
Vladimir Markodec78172020-06-19 15:31:23 +01003358 codegen_->IncreaseFrame(adjustment);
Roland Levillain232ade02015-04-20 15:14:36 +01003359 }
3360
3361 // Load the value to the FP stack, using temporaries if needed.
3362 PushOntoFPStack(in, 0, adjustment, false, true);
3363
3364 if (out.IsDoubleStackSlot()) {
3365 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
3366 } else {
3367 __ fstpl(Address(ESP, 0));
3368 Location stack_temp = Location::DoubleStackSlot(0);
3369 codegen_->Move64(out, stack_temp);
3370 }
3371
3372 // Remove the temporary stack space we allocated.
3373 if (adjustment != 0) {
Vladimir Markodec78172020-06-19 15:31:23 +01003374 codegen_->DecreaseFrame(adjustment);
Roland Levillain232ade02015-04-20 15:14:36 +01003375 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00003376 break;
3377 }
3378
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003379 case DataType::Type::kFloat32:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003380 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003381 break;
3382
3383 default:
3384 LOG(FATAL) << "Unexpected type conversion from " << input_type
3385 << " to " << result_type;
Igor Murashkin2ffb7032017-11-08 13:35:21 -08003386 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003387 break;
3388
3389 default:
3390 LOG(FATAL) << "Unexpected type conversion from " << input_type
3391 << " to " << result_type;
3392 }
3393}
3394
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003395void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003396 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003397 new (GetGraph()->GetAllocator()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003398 switch (add->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003399 case DataType::Type::kInt32: {
Mark Mendell09b84632015-02-13 17:48:38 -05003400 locations->SetInAt(0, Location::RequiresRegister());
3401 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
3402 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3403 break;
3404 }
3405
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003406 case DataType::Type::kInt64: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003407 locations->SetInAt(0, Location::RequiresRegister());
3408 locations->SetInAt(1, Location::Any());
3409 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003410 break;
3411 }
3412
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003413 case DataType::Type::kFloat32:
3414 case DataType::Type::kFloat64: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003415 locations->SetInAt(0, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003416 if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3417 DCHECK(add->InputAt(1)->IsEmittedAtUseSite());
Nicolas Geoffray7770a3e2016-02-03 10:13:41 +00003418 } else if (add->InputAt(1)->IsConstant()) {
3419 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003420 } else {
3421 locations->SetInAt(1, Location::Any());
3422 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003423 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003424 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003425 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003426
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003427 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003428 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Elliott Hughesc1896c92018-11-29 11:33:18 -08003429 UNREACHABLE();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003430 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003431}
3432
3433void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
3434 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003435 Location first = locations->InAt(0);
3436 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05003437 Location out = locations->Out();
3438
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003439 switch (add->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003440 case DataType::Type::kInt32: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003441 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003442 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3443 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04003444 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
3445 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05003446 } else {
3447 __ leal(out.AsRegister<Register>(), Address(
3448 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
3449 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003450 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003451 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
3452 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
3453 __ addl(out.AsRegister<Register>(), Immediate(value));
3454 } else {
3455 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
3456 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003457 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05003458 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003459 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003460 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003461 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003462 }
3463
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003464 case DataType::Type::kInt64: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003465 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003466 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3467 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003468 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003469 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3470 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003471 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003472 } else {
3473 DCHECK(second.IsConstant()) << second;
3474 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3475 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
3476 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003477 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003478 break;
3479 }
3480
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003481 case DataType::Type::kFloat32: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003482 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003483 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04003484 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3485 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003486 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003487 __ addss(first.AsFpuRegister<XmmRegister>(),
3488 codegen_->LiteralFloatAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003489 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3490 const_area->GetBaseMethodAddress(),
3491 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark Mendell0616ae02015-04-17 12:49:27 -04003492 } else {
3493 DCHECK(second.IsStackSlot());
3494 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003495 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003496 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003497 }
3498
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003499 case DataType::Type::kFloat64: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003500 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003501 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04003502 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
3503 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003504 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003505 __ addsd(first.AsFpuRegister<XmmRegister>(),
3506 codegen_->LiteralDoubleAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003507 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3508 const_area->GetBaseMethodAddress(),
3509 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark Mendell0616ae02015-04-17 12:49:27 -04003510 } else {
3511 DCHECK(second.IsDoubleStackSlot());
3512 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003513 }
3514 break;
3515 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003516
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003517 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003518 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003519 }
3520}
3521
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003522void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003523 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003524 new (GetGraph()->GetAllocator()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003525 switch (sub->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003526 case DataType::Type::kInt32:
3527 case DataType::Type::kInt64: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003528 locations->SetInAt(0, Location::RequiresRegister());
3529 locations->SetInAt(1, Location::Any());
3530 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003531 break;
3532 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003533 case DataType::Type::kFloat32:
3534 case DataType::Type::kFloat64: {
Calin Juravle11351682014-10-23 15:38:15 +01003535 locations->SetInAt(0, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003536 if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3537 DCHECK(sub->InputAt(1)->IsEmittedAtUseSite());
Nicolas Geoffray7770a3e2016-02-03 10:13:41 +00003538 } else if (sub->InputAt(1)->IsConstant()) {
3539 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003540 } else {
3541 locations->SetInAt(1, Location::Any());
3542 }
Calin Juravle11351682014-10-23 15:38:15 +01003543 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003544 break;
Calin Juravle11351682014-10-23 15:38:15 +01003545 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003546
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003547 default:
Calin Juravle11351682014-10-23 15:38:15 +01003548 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003549 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003550}
3551
3552void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
3553 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003554 Location first = locations->InAt(0);
3555 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01003556 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003557 switch (sub->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003558 case DataType::Type::kInt32: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003559 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003560 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003561 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003562 __ subl(first.AsRegister<Register>(),
3563 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003564 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003565 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003566 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003567 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003568 }
3569
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003570 case DataType::Type::kInt64: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003571 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01003572 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3573 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003574 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01003575 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003576 __ sbbl(first.AsRegisterPairHigh<Register>(),
3577 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003578 } else {
3579 DCHECK(second.IsConstant()) << second;
3580 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3581 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
3582 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003583 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003584 break;
3585 }
3586
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003587 case DataType::Type::kFloat32: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003588 if (second.IsFpuRegister()) {
3589 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3590 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3591 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003592 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003593 __ subss(first.AsFpuRegister<XmmRegister>(),
3594 codegen_->LiteralFloatAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003595 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3596 const_area->GetBaseMethodAddress(),
3597 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark Mendell0616ae02015-04-17 12:49:27 -04003598 } else {
3599 DCHECK(second.IsStackSlot());
3600 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3601 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003602 break;
Calin Juravle11351682014-10-23 15:38:15 +01003603 }
3604
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003605 case DataType::Type::kFloat64: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003606 if (second.IsFpuRegister()) {
3607 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3608 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
3609 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003610 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003611 __ subsd(first.AsFpuRegister<XmmRegister>(),
3612 codegen_->LiteralDoubleAddress(
3613 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003614 const_area->GetBaseMethodAddress(),
Mark Mendell0616ae02015-04-17 12:49:27 -04003615 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3616 } else {
3617 DCHECK(second.IsDoubleStackSlot());
3618 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3619 }
Calin Juravle11351682014-10-23 15:38:15 +01003620 break;
3621 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003622
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003623 default:
Calin Juravle11351682014-10-23 15:38:15 +01003624 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003625 }
3626}
3627
Calin Juravle34bacdf2014-10-07 20:23:36 +01003628void LocationsBuilderX86::VisitMul(HMul* mul) {
3629 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003630 new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003631 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003632 case DataType::Type::kInt32:
Calin Juravle34bacdf2014-10-07 20:23:36 +01003633 locations->SetInAt(0, Location::RequiresRegister());
3634 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003635 if (mul->InputAt(1)->IsIntConstant()) {
3636 // Can use 3 operand multiply.
3637 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3638 } else {
3639 locations->SetOut(Location::SameAsFirstInput());
3640 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003641 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003642 case DataType::Type::kInt64: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01003643 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003644 locations->SetInAt(1, Location::Any());
3645 locations->SetOut(Location::SameAsFirstInput());
3646 // Needed for imul on 32bits with 64bits output.
3647 locations->AddTemp(Location::RegisterLocation(EAX));
3648 locations->AddTemp(Location::RegisterLocation(EDX));
3649 break;
3650 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003651 case DataType::Type::kFloat32:
3652 case DataType::Type::kFloat64: {
Calin Juravleb5bfa962014-10-21 18:02:24 +01003653 locations->SetInAt(0, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003654 if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3655 DCHECK(mul->InputAt(1)->IsEmittedAtUseSite());
Nicolas Geoffray7770a3e2016-02-03 10:13:41 +00003656 } else if (mul->InputAt(1)->IsConstant()) {
3657 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00003658 } else {
3659 locations->SetInAt(1, Location::Any());
3660 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003661 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003662 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003663 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003664
3665 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003666 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003667 }
3668}
3669
3670void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
3671 LocationSummary* locations = mul->GetLocations();
3672 Location first = locations->InAt(0);
3673 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003674 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003675
3676 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003677 case DataType::Type::kInt32:
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003678 // The constant may have ended up in a register, so test explicitly to avoid
3679 // problems where the output may not be the same as the first operand.
3680 if (mul->InputAt(1)->IsIntConstant()) {
3681 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
3682 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
3683 } else if (second.IsRegister()) {
3684 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003685 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003686 } else {
3687 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04003688 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00003689 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01003690 }
3691 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01003692
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003693 case DataType::Type::kInt64: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01003694 Register in1_hi = first.AsRegisterPairHigh<Register>();
3695 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003696 Register eax = locations->GetTemp(0).AsRegister<Register>();
3697 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003698
3699 DCHECK_EQ(EAX, eax);
3700 DCHECK_EQ(EDX, edx);
3701
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003702 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01003703 // output: in1
3704 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
3705 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
3706 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003707 if (second.IsConstant()) {
3708 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003709
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003710 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
3711 int32_t low_value = Low32Bits(value);
3712 int32_t high_value = High32Bits(value);
3713 Immediate low(low_value);
3714 Immediate high(high_value);
3715
3716 __ movl(eax, high);
3717 // eax <- in1.lo * in2.hi
3718 __ imull(eax, in1_lo);
3719 // in1.hi <- in1.hi * in2.lo
3720 __ imull(in1_hi, low);
3721 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3722 __ addl(in1_hi, eax);
3723 // move in2_lo to eax to prepare for double precision
3724 __ movl(eax, low);
3725 // edx:eax <- in1.lo * in2.lo
3726 __ mull(in1_lo);
3727 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3728 __ addl(in1_hi, edx);
3729 // in1.lo <- (in1.lo * in2.lo)[31:0];
3730 __ movl(in1_lo, eax);
3731 } else if (second.IsRegisterPair()) {
3732 Register in2_hi = second.AsRegisterPairHigh<Register>();
3733 Register in2_lo = second.AsRegisterPairLow<Register>();
3734
3735 __ movl(eax, in2_hi);
3736 // eax <- in1.lo * in2.hi
3737 __ imull(eax, in1_lo);
3738 // in1.hi <- in1.hi * in2.lo
3739 __ imull(in1_hi, in2_lo);
3740 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3741 __ addl(in1_hi, eax);
3742 // move in1_lo to eax to prepare for double precision
3743 __ movl(eax, in1_lo);
3744 // edx:eax <- in1.lo * in2.lo
3745 __ mull(in2_lo);
3746 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3747 __ addl(in1_hi, edx);
3748 // in1.lo <- (in1.lo * in2.lo)[31:0];
3749 __ movl(in1_lo, eax);
3750 } else {
3751 DCHECK(second.IsDoubleStackSlot()) << second;
3752 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
3753 Address in2_lo(ESP, second.GetStackIndex());
3754
3755 __ movl(eax, in2_hi);
3756 // eax <- in1.lo * in2.hi
3757 __ imull(eax, in1_lo);
3758 // in1.hi <- in1.hi * in2.lo
3759 __ imull(in1_hi, in2_lo);
3760 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
3761 __ addl(in1_hi, eax);
3762 // move in1_lo to eax to prepare for double precision
3763 __ movl(eax, in1_lo);
3764 // edx:eax <- in1.lo * in2.lo
3765 __ mull(in2_lo);
3766 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
3767 __ addl(in1_hi, edx);
3768 // in1.lo <- (in1.lo * in2.lo)[31:0];
3769 __ movl(in1_lo, eax);
3770 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003771
3772 break;
3773 }
3774
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003775 case DataType::Type::kFloat32: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003776 DCHECK(first.Equals(locations->Out()));
3777 if (second.IsFpuRegister()) {
3778 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3779 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3780 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003781 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003782 __ mulss(first.AsFpuRegister<XmmRegister>(),
3783 codegen_->LiteralFloatAddress(
3784 const_area->GetConstant()->AsFloatConstant()->GetValue(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003785 const_area->GetBaseMethodAddress(),
Mark Mendell0616ae02015-04-17 12:49:27 -04003786 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3787 } else {
3788 DCHECK(second.IsStackSlot());
3789 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3790 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003791 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003792 }
3793
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003794 case DataType::Type::kFloat64: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003795 DCHECK(first.Equals(locations->Out()));
3796 if (second.IsFpuRegister()) {
3797 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3798 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
3799 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00003800 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04003801 __ mulsd(first.AsFpuRegister<XmmRegister>(),
3802 codegen_->LiteralDoubleAddress(
3803 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00003804 const_area->GetBaseMethodAddress(),
Mark Mendell0616ae02015-04-17 12:49:27 -04003805 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3806 } else {
3807 DCHECK(second.IsDoubleStackSlot());
3808 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3809 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01003810 break;
3811 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003812
3813 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003814 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003815 }
3816}
3817
Roland Levillain232ade02015-04-20 15:14:36 +01003818void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
3819 uint32_t temp_offset,
3820 uint32_t stack_adjustment,
3821 bool is_fp,
3822 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003823 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01003824 DCHECK(!is_wide);
3825 if (is_fp) {
3826 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
3827 } else {
3828 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
3829 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003830 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01003831 DCHECK(is_wide);
3832 if (is_fp) {
3833 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
3834 } else {
3835 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
3836 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003837 } else {
3838 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01003839 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003840 Location stack_temp = Location::StackSlot(temp_offset);
3841 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01003842 if (is_fp) {
3843 __ flds(Address(ESP, temp_offset));
3844 } else {
3845 __ filds(Address(ESP, temp_offset));
3846 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003847 } else {
3848 Location stack_temp = Location::DoubleStackSlot(temp_offset);
3849 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01003850 if (is_fp) {
3851 __ fldl(Address(ESP, temp_offset));
3852 } else {
3853 __ fildl(Address(ESP, temp_offset));
3854 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003855 }
3856 }
3857}
3858
3859void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003860 DataType::Type type = rem->GetResultType();
3861 bool is_float = type == DataType::Type::kFloat32;
3862 size_t elem_size = DataType::Size(type);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003863 LocationSummary* locations = rem->GetLocations();
3864 Location first = locations->InAt(0);
3865 Location second = locations->InAt(1);
3866 Location out = locations->Out();
3867
3868 // Create stack space for 2 elements.
3869 // TODO: enhance register allocator to ask for stack temporaries.
Vladimir Markodec78172020-06-19 15:31:23 +01003870 codegen_->IncreaseFrame(2 * elem_size);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003871
3872 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01003873 const bool is_wide = !is_float;
Andreas Gampe3db70682018-12-26 15:12:03 -08003874 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp= */ true, is_wide);
3875 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp= */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003876
3877 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04003878 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003879 __ Bind(&retry);
3880 __ fprem();
3881
3882 // Move FP status to AX.
3883 __ fstsw();
3884
3885 // And see if the argument reduction is complete. This is signaled by the
3886 // C2 FPU flag bit set to 0.
3887 __ andl(EAX, Immediate(kC2ConditionMask));
3888 __ j(kNotEqual, &retry);
3889
3890 // We have settled on the final value. Retrieve it into an XMM register.
3891 // Store FP top of stack to real stack.
3892 if (is_float) {
3893 __ fsts(Address(ESP, 0));
3894 } else {
3895 __ fstl(Address(ESP, 0));
3896 }
3897
3898 // Pop the 2 items from the FP stack.
3899 __ fucompp();
3900
3901 // Load the value from the stack into an XMM register.
3902 DCHECK(out.IsFpuRegister()) << out;
3903 if (is_float) {
3904 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
3905 } else {
3906 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
3907 }
3908
3909 // And remove the temporary stack space we allocated.
Vladimir Markodec78172020-06-19 15:31:23 +01003910 codegen_->DecreaseFrame(2 * elem_size);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003911}
3912
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003913
3914void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3915 DCHECK(instruction->IsDiv() || instruction->IsRem());
3916
3917 LocationSummary* locations = instruction->GetLocations();
3918 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003919 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003920
3921 Register out_register = locations->Out().AsRegister<Register>();
3922 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003923 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003924
3925 DCHECK(imm == 1 || imm == -1);
3926
3927 if (instruction->IsRem()) {
3928 __ xorl(out_register, out_register);
3929 } else {
3930 __ movl(out_register, input_register);
3931 if (imm == -1) {
3932 __ negl(out_register);
3933 }
3934 }
3935}
3936
Shalini Salomi Bodapatia66784b2018-11-06 13:05:44 +05303937void InstructionCodeGeneratorX86::RemByPowerOfTwo(HRem* instruction) {
3938 LocationSummary* locations = instruction->GetLocations();
3939 Location second = locations->InAt(1);
3940
3941 Register out = locations->Out().AsRegister<Register>();
3942 Register numerator = locations->InAt(0).AsRegister<Register>();
3943
3944 int32_t imm = Int64FromConstant(second.GetConstant());
3945 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3946 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
3947
3948 Register tmp = locations->GetTemp(0).AsRegister<Register>();
3949 NearLabel done;
3950 __ movl(out, numerator);
3951 __ andl(out, Immediate(abs_imm-1));
3952 __ j(Condition::kZero, &done);
3953 __ leal(tmp, Address(out, static_cast<int32_t>(~(abs_imm-1))));
3954 __ testl(numerator, numerator);
3955 __ cmovl(Condition::kLess, out, tmp);
3956 __ Bind(&done);
3957}
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003958
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003959void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003960 LocationSummary* locations = instruction->GetLocations();
3961
3962 Register out_register = locations->Out().AsRegister<Register>();
3963 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003964 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003965 DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
3966 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003967
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003968 Register num = locations->GetTemp(0).AsRegister<Register>();
3969
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003970 __ leal(num, Address(input_register, abs_imm - 1));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003971 __ testl(input_register, input_register);
3972 __ cmovl(kGreaterEqual, num, input_register);
3973 int shift = CTZ(imm);
3974 __ sarl(num, Immediate(shift));
3975
3976 if (imm < 0) {
3977 __ negl(num);
3978 }
3979
3980 __ movl(out_register, num);
3981}
3982
3983void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3984 DCHECK(instruction->IsDiv() || instruction->IsRem());
3985
3986 LocationSummary* locations = instruction->GetLocations();
3987 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
3988
3989 Register eax = locations->InAt(0).AsRegister<Register>();
3990 Register out = locations->Out().AsRegister<Register>();
3991 Register num;
3992 Register edx;
3993
3994 if (instruction->IsDiv()) {
3995 edx = locations->GetTemp(0).AsRegister<Register>();
3996 num = locations->GetTemp(1).AsRegister<Register>();
3997 } else {
3998 edx = locations->Out().AsRegister<Register>();
3999 num = locations->GetTemp(0).AsRegister<Register>();
4000 }
4001
4002 DCHECK_EQ(EAX, eax);
4003 DCHECK_EQ(EDX, edx);
4004 if (instruction->IsDiv()) {
4005 DCHECK_EQ(EAX, out);
4006 } else {
4007 DCHECK_EQ(EDX, out);
4008 }
4009
4010 int64_t magic;
4011 int shift;
Andreas Gampe3db70682018-12-26 15:12:03 -08004012 CalculateMagicAndShiftForDivRem(imm, /* is_long= */ false, &magic, &shift);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004013
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004014 // Save the numerator.
4015 __ movl(num, eax);
4016
4017 // EAX = magic
4018 __ movl(eax, Immediate(magic));
4019
4020 // EDX:EAX = magic * numerator
4021 __ imull(num);
4022
4023 if (imm > 0 && magic < 0) {
4024 // EDX += num
4025 __ addl(edx, num);
4026 } else if (imm < 0 && magic > 0) {
4027 __ subl(edx, num);
4028 }
4029
4030 // Shift if needed.
4031 if (shift != 0) {
4032 __ sarl(edx, Immediate(shift));
4033 }
4034
4035 // EDX += 1 if EDX < 0
4036 __ movl(eax, edx);
4037 __ shrl(edx, Immediate(31));
4038 __ addl(edx, eax);
4039
4040 if (instruction->IsRem()) {
4041 __ movl(eax, num);
4042 __ imull(edx, Immediate(imm));
4043 __ subl(eax, edx);
4044 __ movl(edx, eax);
4045 } else {
4046 __ movl(eax, edx);
4047 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004048}
4049
Calin Juravlebacfec32014-11-14 15:54:36 +00004050void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
4051 DCHECK(instruction->IsDiv() || instruction->IsRem());
4052
4053 LocationSummary* locations = instruction->GetLocations();
4054 Location out = locations->Out();
4055 Location first = locations->InAt(0);
4056 Location second = locations->InAt(1);
4057 bool is_div = instruction->IsDiv();
4058
4059 switch (instruction->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004060 case DataType::Type::kInt32: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004061 DCHECK_EQ(EAX, first.AsRegister<Register>());
4062 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00004063
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004064 if (second.IsConstant()) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01004065 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004066
4067 if (imm == 0) {
4068 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
4069 } else if (imm == 1 || imm == -1) {
4070 DivRemOneOrMinusOne(instruction);
Shalini Salomi Bodapatia66784b2018-11-06 13:05:44 +05304071 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
4072 if (is_div) {
4073 DivByPowerOfTwo(instruction->AsDiv());
4074 } else {
4075 RemByPowerOfTwo(instruction->AsRem());
4076 }
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004077 } else {
4078 DCHECK(imm <= -2 || imm >= 2);
4079 GenerateDivRemWithAnyConstant(instruction);
4080 }
4081 } else {
Vladimir Marko174b2e22017-10-12 13:34:49 +01004082 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) DivRemMinusOneSlowPathX86(
David Srbecky9cd6d372016-02-09 15:24:47 +00004083 instruction, out.AsRegister<Register>(), is_div);
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004084 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00004085
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004086 Register second_reg = second.AsRegister<Register>();
4087 // 0x80000000/-1 triggers an arithmetic exception!
4088 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
4089 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00004090
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004091 __ cmpl(second_reg, Immediate(-1));
4092 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00004093
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004094 // edx:eax <- sign-extended of eax
4095 __ cdq();
4096 // eax = quotient, edx = remainder
4097 __ idivl(second_reg);
4098 __ Bind(slow_path->GetExitLabel());
4099 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004100 break;
4101 }
4102
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004103 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004104 InvokeRuntimeCallingConvention calling_convention;
4105 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4106 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4107 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4108 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4109 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
4110 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
4111
4112 if (is_div) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01004113 codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004114 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004115 } else {
Serban Constantinescuba45db02016-07-12 22:53:02 +01004116 codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004117 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004118 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004119 break;
4120 }
4121
4122 default:
4123 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
4124 }
4125}
4126
Calin Juravle7c4954d2014-10-28 16:57:40 +00004127void LocationsBuilderX86::VisitDiv(HDiv* div) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004128 LocationSummary::CallKind call_kind = (div->GetResultType() == DataType::Type::kInt64)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004129 ? LocationSummary::kCallOnMainOnly
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004130 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01004131 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(div, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004132
Calin Juravle7c4954d2014-10-28 16:57:40 +00004133 switch (div->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004134 case DataType::Type::kInt32: {
Calin Juravled0d48522014-11-04 16:40:20 +00004135 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004136 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00004137 locations->SetOut(Location::SameAsFirstInput());
4138 // Intel uses edx:eax as the dividend.
4139 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004140 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
4141 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
4142 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01004143 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004144 locations->AddTemp(Location::RequiresRegister());
4145 }
Calin Juravled0d48522014-11-04 16:40:20 +00004146 break;
4147 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004148 case DataType::Type::kInt64: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004149 InvokeRuntimeCallingConvention calling_convention;
4150 locations->SetInAt(0, Location::RegisterPairLocation(
4151 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4152 locations->SetInAt(1, Location::RegisterPairLocation(
4153 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4154 // Runtime helper puts the result in EAX, EDX.
4155 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00004156 break;
4157 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004158 case DataType::Type::kFloat32:
4159 case DataType::Type::kFloat64: {
Calin Juravle7c4954d2014-10-28 16:57:40 +00004160 locations->SetInAt(0, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00004161 if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4162 DCHECK(div->InputAt(1)->IsEmittedAtUseSite());
Nicolas Geoffray7770a3e2016-02-03 10:13:41 +00004163 } else if (div->InputAt(1)->IsConstant()) {
4164 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00004165 } else {
4166 locations->SetInAt(1, Location::Any());
4167 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004168 locations->SetOut(Location::SameAsFirstInput());
4169 break;
4170 }
4171
4172 default:
4173 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4174 }
4175}
4176
4177void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
4178 LocationSummary* locations = div->GetLocations();
4179 Location first = locations->InAt(0);
4180 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00004181
4182 switch (div->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004183 case DataType::Type::kInt32:
4184 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004185 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00004186 break;
4187 }
4188
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004189 case DataType::Type::kFloat32: {
Mark Mendell0616ae02015-04-17 12:49:27 -04004190 if (second.IsFpuRegister()) {
4191 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
4192 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4193 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00004194 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04004195 __ divss(first.AsFpuRegister<XmmRegister>(),
4196 codegen_->LiteralFloatAddress(
4197 const_area->GetConstant()->AsFloatConstant()->GetValue(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00004198 const_area->GetBaseMethodAddress(),
Mark Mendell0616ae02015-04-17 12:49:27 -04004199 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
4200 } else {
4201 DCHECK(second.IsStackSlot());
4202 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
4203 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004204 break;
4205 }
4206
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004207 case DataType::Type::kFloat64: {
Mark Mendell0616ae02015-04-17 12:49:27 -04004208 if (second.IsFpuRegister()) {
4209 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
4210 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
4211 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
David Brazdilb3e773e2016-01-26 11:28:37 +00004212 DCHECK(const_area->IsEmittedAtUseSite());
Mark Mendell0616ae02015-04-17 12:49:27 -04004213 __ divsd(first.AsFpuRegister<XmmRegister>(),
4214 codegen_->LiteralDoubleAddress(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00004215 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
4216 const_area->GetBaseMethodAddress(),
4217 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
Mark Mendell0616ae02015-04-17 12:49:27 -04004218 } else {
4219 DCHECK(second.IsDoubleStackSlot());
4220 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
4221 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004222 break;
4223 }
4224
4225 default:
4226 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4227 }
4228}
4229
Calin Juravlebacfec32014-11-14 15:54:36 +00004230void LocationsBuilderX86::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004231 DataType::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004232
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004233 LocationSummary::CallKind call_kind = (rem->GetResultType() == DataType::Type::kInt64)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004234 ? LocationSummary::kCallOnMainOnly
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004235 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01004236 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00004237
Calin Juravled2ec87d2014-12-08 14:24:46 +00004238 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004239 case DataType::Type::kInt32: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004240 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004241 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00004242 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004243 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
4244 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
4245 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01004246 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01004247 locations->AddTemp(Location::RequiresRegister());
4248 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004249 break;
4250 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004251 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004252 InvokeRuntimeCallingConvention calling_convention;
4253 locations->SetInAt(0, Location::RegisterPairLocation(
4254 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4255 locations->SetInAt(1, Location::RegisterPairLocation(
4256 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4257 // Runtime helper puts the result in EAX, EDX.
4258 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
4259 break;
4260 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004261 case DataType::Type::kFloat64:
4262 case DataType::Type::kFloat32: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05004263 locations->SetInAt(0, Location::Any());
4264 locations->SetInAt(1, Location::Any());
4265 locations->SetOut(Location::RequiresFpuRegister());
4266 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00004267 break;
4268 }
4269
4270 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004271 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004272 }
4273}
4274
4275void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004276 DataType::Type type = rem->GetResultType();
Calin Juravlebacfec32014-11-14 15:54:36 +00004277 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004278 case DataType::Type::kInt32:
4279 case DataType::Type::kInt64: {
Calin Juravlebacfec32014-11-14 15:54:36 +00004280 GenerateDivRemIntegral(rem);
4281 break;
4282 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004283 case DataType::Type::kFloat32:
4284 case DataType::Type::kFloat64: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05004285 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00004286 break;
4287 }
4288 default:
4289 LOG(FATAL) << "Unexpected rem type " << type;
4290 }
4291}
4292
Aart Bik1f8d51b2018-02-15 10:42:37 -08004293static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) {
4294 LocationSummary* locations = new (allocator) LocationSummary(minmax);
4295 switch (minmax->GetResultType()) {
4296 case DataType::Type::kInt32:
4297 locations->SetInAt(0, Location::RequiresRegister());
4298 locations->SetInAt(1, Location::RequiresRegister());
4299 locations->SetOut(Location::SameAsFirstInput());
4300 break;
4301 case DataType::Type::kInt64:
4302 locations->SetInAt(0, Location::RequiresRegister());
4303 locations->SetInAt(1, Location::RequiresRegister());
4304 locations->SetOut(Location::SameAsFirstInput());
4305 // Register to use to perform a long subtract to set cc.
4306 locations->AddTemp(Location::RequiresRegister());
4307 break;
4308 case DataType::Type::kFloat32:
4309 locations->SetInAt(0, Location::RequiresFpuRegister());
4310 locations->SetInAt(1, Location::RequiresFpuRegister());
4311 locations->SetOut(Location::SameAsFirstInput());
4312 locations->AddTemp(Location::RequiresRegister());
4313 break;
4314 case DataType::Type::kFloat64:
4315 locations->SetInAt(0, Location::RequiresFpuRegister());
4316 locations->SetInAt(1, Location::RequiresFpuRegister());
4317 locations->SetOut(Location::SameAsFirstInput());
4318 break;
4319 default:
4320 LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType();
4321 }
4322}
4323
Aart Bik351df3e2018-03-07 11:54:57 -08004324void InstructionCodeGeneratorX86::GenerateMinMaxInt(LocationSummary* locations,
4325 bool is_min,
4326 DataType::Type type) {
Aart Bik1f8d51b2018-02-15 10:42:37 -08004327 Location op1_loc = locations->InAt(0);
4328 Location op2_loc = locations->InAt(1);
4329
4330 // Shortcut for same input locations.
4331 if (op1_loc.Equals(op2_loc)) {
4332 // Can return immediately, as op1_loc == out_loc.
4333 // Note: if we ever support separate registers, e.g., output into memory, we need to check for
4334 // a copy here.
4335 DCHECK(locations->Out().Equals(op1_loc));
4336 return;
4337 }
4338
4339 if (type == DataType::Type::kInt64) {
4340 // Need to perform a subtract to get the sign right.
4341 // op1 is already in the same location as the output.
4342 Location output = locations->Out();
4343 Register output_lo = output.AsRegisterPairLow<Register>();
4344 Register output_hi = output.AsRegisterPairHigh<Register>();
4345
4346 Register op2_lo = op2_loc.AsRegisterPairLow<Register>();
4347 Register op2_hi = op2_loc.AsRegisterPairHigh<Register>();
4348
4349 // The comparison is performed by subtracting the second operand from
4350 // the first operand and then setting the status flags in the same
4351 // manner as the SUB instruction."
4352 __ cmpl(output_lo, op2_lo);
4353
4354 // Now use a temp and the borrow to finish the subtraction of op2_hi.
4355 Register temp = locations->GetTemp(0).AsRegister<Register>();
4356 __ movl(temp, output_hi);
4357 __ sbbl(temp, op2_hi);
4358
4359 // Now the condition code is correct.
4360 Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess;
4361 __ cmovl(cond, output_lo, op2_lo);
4362 __ cmovl(cond, output_hi, op2_hi);
4363 } else {
4364 DCHECK_EQ(type, DataType::Type::kInt32);
4365 Register out = locations->Out().AsRegister<Register>();
4366 Register op2 = op2_loc.AsRegister<Register>();
4367
4368 // (out := op1)
4369 // out <=? op2
4370 // if out is min jmp done
4371 // out := op2
4372 // done:
4373
4374 __ cmpl(out, op2);
4375 Condition cond = is_min ? Condition::kGreater : Condition::kLess;
4376 __ cmovl(cond, out, op2);
4377 }
4378}
4379
4380void InstructionCodeGeneratorX86::GenerateMinMaxFP(LocationSummary* locations,
4381 bool is_min,
4382 DataType::Type type) {
4383 Location op1_loc = locations->InAt(0);
4384 Location op2_loc = locations->InAt(1);
4385 Location out_loc = locations->Out();
4386 XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
4387
4388 // Shortcut for same input locations.
4389 if (op1_loc.Equals(op2_loc)) {
4390 DCHECK(out_loc.Equals(op1_loc));
4391 return;
4392 }
4393
4394 // (out := op1)
4395 // out <=? op2
4396 // if Nan jmp Nan_label
4397 // if out is min jmp done
4398 // if op2 is min jmp op2_label
4399 // handle -0/+0
4400 // jmp done
4401 // Nan_label:
4402 // out := NaN
4403 // op2_label:
4404 // out := op2
4405 // done:
4406 //
4407 // This removes one jmp, but needs to copy one input (op1) to out.
4408 //
4409 // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
4410
4411 XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
4412
4413 NearLabel nan, done, op2_label;
4414 if (type == DataType::Type::kFloat64) {
4415 __ ucomisd(out, op2);
4416 } else {
4417 DCHECK_EQ(type, DataType::Type::kFloat32);
4418 __ ucomiss(out, op2);
4419 }
4420
4421 __ j(Condition::kParityEven, &nan);
4422
4423 __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
4424 __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
4425
4426 // Handle 0.0/-0.0.
4427 if (is_min) {
4428 if (type == DataType::Type::kFloat64) {
4429 __ orpd(out, op2);
4430 } else {
4431 __ orps(out, op2);
4432 }
4433 } else {
4434 if (type == DataType::Type::kFloat64) {
4435 __ andpd(out, op2);
4436 } else {
4437 __ andps(out, op2);
4438 }
4439 }
4440 __ jmp(&done);
4441
4442 // NaN handling.
4443 __ Bind(&nan);
4444 if (type == DataType::Type::kFloat64) {
4445 // TODO: Use a constant from the constant table (requires extra input).
4446 __ LoadLongConstant(out, kDoubleNaN);
4447 } else {
4448 Register constant = locations->GetTemp(0).AsRegister<Register>();
4449 __ movl(constant, Immediate(kFloatNaN));
4450 __ movd(out, constant);
4451 }
4452 __ jmp(&done);
4453
4454 // out := op2;
4455 __ Bind(&op2_label);
4456 if (type == DataType::Type::kFloat64) {
4457 __ movsd(out, op2);
4458 } else {
4459 __ movss(out, op2);
4460 }
4461
4462 // Done.
4463 __ Bind(&done);
4464}
4465
Aart Bik351df3e2018-03-07 11:54:57 -08004466void InstructionCodeGeneratorX86::GenerateMinMax(HBinaryOperation* minmax, bool is_min) {
4467 DataType::Type type = minmax->GetResultType();
4468 switch (type) {
4469 case DataType::Type::kInt32:
4470 case DataType::Type::kInt64:
4471 GenerateMinMaxInt(minmax->GetLocations(), is_min, type);
4472 break;
4473 case DataType::Type::kFloat32:
4474 case DataType::Type::kFloat64:
4475 GenerateMinMaxFP(minmax->GetLocations(), is_min, type);
4476 break;
4477 default:
4478 LOG(FATAL) << "Unexpected type for HMinMax " << type;
4479 }
4480}
4481
Aart Bik1f8d51b2018-02-15 10:42:37 -08004482void LocationsBuilderX86::VisitMin(HMin* min) {
4483 CreateMinMaxLocations(GetGraph()->GetAllocator(), min);
4484}
4485
4486void InstructionCodeGeneratorX86::VisitMin(HMin* min) {
Aart Bik351df3e2018-03-07 11:54:57 -08004487 GenerateMinMax(min, /*is_min*/ true);
Aart Bik1f8d51b2018-02-15 10:42:37 -08004488}
4489
4490void LocationsBuilderX86::VisitMax(HMax* max) {
4491 CreateMinMaxLocations(GetGraph()->GetAllocator(), max);
4492}
4493
4494void InstructionCodeGeneratorX86::VisitMax(HMax* max) {
Aart Bik351df3e2018-03-07 11:54:57 -08004495 GenerateMinMax(max, /*is_min*/ false);
Aart Bik1f8d51b2018-02-15 10:42:37 -08004496}
4497
Aart Bik3dad3412018-02-28 12:01:46 -08004498void LocationsBuilderX86::VisitAbs(HAbs* abs) {
4499 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs);
4500 switch (abs->GetResultType()) {
4501 case DataType::Type::kInt32:
4502 locations->SetInAt(0, Location::RegisterLocation(EAX));
4503 locations->SetOut(Location::SameAsFirstInput());
4504 locations->AddTemp(Location::RegisterLocation(EDX));
4505 break;
4506 case DataType::Type::kInt64:
4507 locations->SetInAt(0, Location::RequiresRegister());
4508 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4509 locations->AddTemp(Location::RequiresRegister());
4510 break;
4511 case DataType::Type::kFloat32:
4512 locations->SetInAt(0, Location::RequiresFpuRegister());
4513 locations->SetOut(Location::SameAsFirstInput());
4514 locations->AddTemp(Location::RequiresFpuRegister());
4515 locations->AddTemp(Location::RequiresRegister());
4516 break;
4517 case DataType::Type::kFloat64:
4518 locations->SetInAt(0, Location::RequiresFpuRegister());
4519 locations->SetOut(Location::SameAsFirstInput());
4520 locations->AddTemp(Location::RequiresFpuRegister());
4521 break;
4522 default:
4523 LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4524 }
4525}
4526
4527void InstructionCodeGeneratorX86::VisitAbs(HAbs* abs) {
4528 LocationSummary* locations = abs->GetLocations();
4529 switch (abs->GetResultType()) {
4530 case DataType::Type::kInt32: {
4531 Register out = locations->Out().AsRegister<Register>();
4532 DCHECK_EQ(out, EAX);
4533 Register temp = locations->GetTemp(0).AsRegister<Register>();
4534 DCHECK_EQ(temp, EDX);
4535 // Sign extend EAX into EDX.
4536 __ cdq();
4537 // XOR EAX with sign.
4538 __ xorl(EAX, EDX);
4539 // Subtract out sign to correct.
4540 __ subl(EAX, EDX);
4541 // The result is in EAX.
4542 break;
4543 }
4544 case DataType::Type::kInt64: {
4545 Location input = locations->InAt(0);
4546 Register input_lo = input.AsRegisterPairLow<Register>();
4547 Register input_hi = input.AsRegisterPairHigh<Register>();
4548 Location output = locations->Out();
4549 Register output_lo = output.AsRegisterPairLow<Register>();
4550 Register output_hi = output.AsRegisterPairHigh<Register>();
4551 Register temp = locations->GetTemp(0).AsRegister<Register>();
4552 // Compute the sign into the temporary.
4553 __ movl(temp, input_hi);
4554 __ sarl(temp, Immediate(31));
4555 // Store the sign into the output.
4556 __ movl(output_lo, temp);
4557 __ movl(output_hi, temp);
4558 // XOR the input to the output.
4559 __ xorl(output_lo, input_lo);
4560 __ xorl(output_hi, input_hi);
4561 // Subtract the sign.
4562 __ subl(output_lo, temp);
4563 __ sbbl(output_hi, temp);
4564 break;
4565 }
4566 case DataType::Type::kFloat32: {
4567 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4568 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4569 Register constant = locations->GetTemp(1).AsRegister<Register>();
4570 __ movl(constant, Immediate(INT32_C(0x7FFFFFFF)));
4571 __ movd(temp, constant);
4572 __ andps(out, temp);
4573 break;
4574 }
4575 case DataType::Type::kFloat64: {
4576 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4577 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4578 // TODO: Use a constant from the constant table (requires extra input).
4579 __ LoadLongConstant(temp, INT64_C(0x7FFFFFFFFFFFFFFF));
4580 __ andpd(out, temp);
4581 break;
4582 }
4583 default:
4584 LOG(FATAL) << "Unexpected type for HAbs " << abs->GetResultType();
4585 }
4586}
4587
Calin Juravled0d48522014-11-04 16:40:20 +00004588void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004589 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004590 switch (instruction->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004591 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004592 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004593 case DataType::Type::kInt8:
4594 case DataType::Type::kUint16:
4595 case DataType::Type::kInt16:
4596 case DataType::Type::kInt32: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004597 locations->SetInAt(0, Location::Any());
4598 break;
4599 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004600 case DataType::Type::kInt64: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004601 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
4602 if (!instruction->IsConstant()) {
4603 locations->AddTemp(Location::RequiresRegister());
4604 }
4605 break;
4606 }
4607 default:
4608 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4609 }
Calin Juravled0d48522014-11-04 16:40:20 +00004610}
4611
4612void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01004613 SlowPathCode* slow_path =
4614 new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004615 codegen_->AddSlowPath(slow_path);
4616
4617 LocationSummary* locations = instruction->GetLocations();
4618 Location value = locations->InAt(0);
4619
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004620 switch (instruction->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004621 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004622 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004623 case DataType::Type::kInt8:
4624 case DataType::Type::kUint16:
4625 case DataType::Type::kInt16:
4626 case DataType::Type::kInt32: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004627 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004628 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004629 __ j(kEqual, slow_path->GetEntryLabel());
4630 } else if (value.IsStackSlot()) {
4631 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
4632 __ j(kEqual, slow_path->GetEntryLabel());
4633 } else {
4634 DCHECK(value.IsConstant()) << value;
4635 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01004636 __ jmp(slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004637 }
4638 }
4639 break;
Calin Juravled0d48522014-11-04 16:40:20 +00004640 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004641 case DataType::Type::kInt64: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004642 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004643 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004644 __ movl(temp, value.AsRegisterPairLow<Register>());
4645 __ orl(temp, value.AsRegisterPairHigh<Register>());
4646 __ j(kEqual, slow_path->GetEntryLabel());
4647 } else {
4648 DCHECK(value.IsConstant()) << value;
4649 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4650 __ jmp(slow_path->GetEntryLabel());
4651 }
4652 }
4653 break;
4654 }
4655 default:
4656 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00004657 }
Calin Juravled0d48522014-11-04 16:40:20 +00004658}
4659
Calin Juravle9aec02f2014-11-18 23:06:35 +00004660void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
4661 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4662
4663 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004664 new (GetGraph()->GetAllocator()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004665
4666 switch (op->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004667 case DataType::Type::kInt32:
4668 case DataType::Type::kInt64: {
Mark P Mendell73945692015-04-29 14:56:17 +00004669 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00004670 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00004671 // The shift count needs to be in CL or a constant.
4672 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00004673 locations->SetOut(Location::SameAsFirstInput());
4674 break;
4675 }
4676 default:
4677 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
4678 }
4679}
4680
4681void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
4682 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4683
4684 LocationSummary* locations = op->GetLocations();
4685 Location first = locations->InAt(0);
4686 Location second = locations->InAt(1);
4687 DCHECK(first.Equals(locations->Out()));
4688
4689 switch (op->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004690 case DataType::Type::kInt32: {
Mark P Mendell73945692015-04-29 14:56:17 +00004691 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004692 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004693 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004694 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004695 DCHECK_EQ(ECX, second_reg);
4696 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004697 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004698 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004699 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004700 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004701 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004702 }
4703 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004704 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance;
Mark P Mendell73945692015-04-29 14:56:17 +00004705 if (shift == 0) {
4706 return;
4707 }
4708 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004709 if (op->IsShl()) {
4710 __ shll(first_reg, imm);
4711 } else if (op->IsShr()) {
4712 __ sarl(first_reg, imm);
4713 } else {
4714 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004715 }
4716 }
4717 break;
4718 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004719 case DataType::Type::kInt64: {
Mark P Mendell73945692015-04-29 14:56:17 +00004720 if (second.IsRegister()) {
4721 Register second_reg = second.AsRegister<Register>();
4722 DCHECK_EQ(ECX, second_reg);
4723 if (op->IsShl()) {
4724 GenerateShlLong(first, second_reg);
4725 } else if (op->IsShr()) {
4726 GenerateShrLong(first, second_reg);
4727 } else {
4728 GenerateUShrLong(first, second_reg);
4729 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004730 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00004731 // Shift by a constant.
Roland Levillain5b5b9312016-03-22 14:57:31 +00004732 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance;
Mark P Mendell73945692015-04-29 14:56:17 +00004733 // Nothing to do if the shift is 0, as the input is already the output.
4734 if (shift != 0) {
4735 if (op->IsShl()) {
4736 GenerateShlLong(first, shift);
4737 } else if (op->IsShr()) {
4738 GenerateShrLong(first, shift);
4739 } else {
4740 GenerateUShrLong(first, shift);
4741 }
4742 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00004743 }
4744 break;
4745 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004746 default:
4747 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
4748 }
4749}
4750
Mark P Mendell73945692015-04-29 14:56:17 +00004751void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
4752 Register low = loc.AsRegisterPairLow<Register>();
4753 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04004754 if (shift == 1) {
4755 // This is just an addition.
4756 __ addl(low, low);
4757 __ adcl(high, high);
4758 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00004759 // Shift by 32 is easy. High gets low, and low gets 0.
4760 codegen_->EmitParallelMoves(
4761 loc.ToLow(),
4762 loc.ToHigh(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004763 DataType::Type::kInt32,
Mark P Mendell73945692015-04-29 14:56:17 +00004764 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
4765 loc.ToLow(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004766 DataType::Type::kInt32);
Mark P Mendell73945692015-04-29 14:56:17 +00004767 } else if (shift > 32) {
4768 // Low part becomes 0. High part is low part << (shift-32).
4769 __ movl(high, low);
4770 __ shll(high, Immediate(shift - 32));
4771 __ xorl(low, low);
4772 } else {
4773 // Between 1 and 31.
4774 __ shld(high, low, Immediate(shift));
4775 __ shll(low, Immediate(shift));
4776 }
4777}
4778
Calin Juravle9aec02f2014-11-18 23:06:35 +00004779void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004780 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00004781 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
4782 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
4783 __ testl(shifter, Immediate(32));
4784 __ j(kEqual, &done);
4785 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
4786 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
4787 __ Bind(&done);
4788}
4789
Mark P Mendell73945692015-04-29 14:56:17 +00004790void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
4791 Register low = loc.AsRegisterPairLow<Register>();
4792 Register high = loc.AsRegisterPairHigh<Register>();
4793 if (shift == 32) {
4794 // Need to copy the sign.
4795 DCHECK_NE(low, high);
4796 __ movl(low, high);
4797 __ sarl(high, Immediate(31));
4798 } else if (shift > 32) {
4799 DCHECK_NE(low, high);
4800 // High part becomes sign. Low part is shifted by shift - 32.
4801 __ movl(low, high);
4802 __ sarl(high, Immediate(31));
4803 __ sarl(low, Immediate(shift - 32));
4804 } else {
4805 // Between 1 and 31.
4806 __ shrd(low, high, Immediate(shift));
4807 __ sarl(high, Immediate(shift));
4808 }
4809}
4810
Calin Juravle9aec02f2014-11-18 23:06:35 +00004811void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004812 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00004813 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
4814 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
4815 __ testl(shifter, Immediate(32));
4816 __ j(kEqual, &done);
4817 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
4818 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
4819 __ Bind(&done);
4820}
4821
Mark P Mendell73945692015-04-29 14:56:17 +00004822void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
4823 Register low = loc.AsRegisterPairLow<Register>();
4824 Register high = loc.AsRegisterPairHigh<Register>();
4825 if (shift == 32) {
4826 // Shift by 32 is easy. Low gets high, and high gets 0.
4827 codegen_->EmitParallelMoves(
4828 loc.ToHigh(),
4829 loc.ToLow(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004830 DataType::Type::kInt32,
Mark P Mendell73945692015-04-29 14:56:17 +00004831 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
4832 loc.ToHigh(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004833 DataType::Type::kInt32);
Mark P Mendell73945692015-04-29 14:56:17 +00004834 } else if (shift > 32) {
4835 // Low part is high >> (shift - 32). High part becomes 0.
4836 __ movl(low, high);
4837 __ shrl(low, Immediate(shift - 32));
4838 __ xorl(high, high);
4839 } else {
4840 // Between 1 and 31.
4841 __ shrd(low, high, Immediate(shift));
4842 __ shrl(high, Immediate(shift));
4843 }
4844}
4845
Calin Juravle9aec02f2014-11-18 23:06:35 +00004846void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04004847 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00004848 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
4849 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
4850 __ testl(shifter, Immediate(32));
4851 __ j(kEqual, &done);
4852 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
4853 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
4854 __ Bind(&done);
4855}
4856
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004857void LocationsBuilderX86::VisitRor(HRor* ror) {
4858 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004859 new (GetGraph()->GetAllocator()) LocationSummary(ror, LocationSummary::kNoCall);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004860
4861 switch (ror->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004862 case DataType::Type::kInt64:
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004863 // Add the temporary needed.
4864 locations->AddTemp(Location::RequiresRegister());
4865 FALLTHROUGH_INTENDED;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004866 case DataType::Type::kInt32:
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004867 locations->SetInAt(0, Location::RequiresRegister());
4868 // The shift count needs to be in CL (unless it is a constant).
4869 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, ror->InputAt(1)));
4870 locations->SetOut(Location::SameAsFirstInput());
4871 break;
4872 default:
4873 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4874 UNREACHABLE();
4875 }
4876}
4877
4878void InstructionCodeGeneratorX86::VisitRor(HRor* ror) {
4879 LocationSummary* locations = ror->GetLocations();
4880 Location first = locations->InAt(0);
4881 Location second = locations->InAt(1);
4882
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004883 if (ror->GetResultType() == DataType::Type::kInt32) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004884 Register first_reg = first.AsRegister<Register>();
4885 if (second.IsRegister()) {
4886 Register second_reg = second.AsRegister<Register>();
4887 __ rorl(first_reg, second_reg);
4888 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004889 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftDistance);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004890 __ rorl(first_reg, imm);
4891 }
4892 return;
4893 }
4894
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004895 DCHECK_EQ(ror->GetResultType(), DataType::Type::kInt64);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004896 Register first_reg_lo = first.AsRegisterPairLow<Register>();
4897 Register first_reg_hi = first.AsRegisterPairHigh<Register>();
4898 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
4899 if (second.IsRegister()) {
4900 Register second_reg = second.AsRegister<Register>();
4901 DCHECK_EQ(second_reg, ECX);
4902 __ movl(temp_reg, first_reg_hi);
4903 __ shrd(first_reg_hi, first_reg_lo, second_reg);
4904 __ shrd(first_reg_lo, temp_reg, second_reg);
4905 __ movl(temp_reg, first_reg_hi);
4906 __ testl(second_reg, Immediate(32));
4907 __ cmovl(kNotEqual, first_reg_hi, first_reg_lo);
4908 __ cmovl(kNotEqual, first_reg_lo, temp_reg);
4909 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004910 int32_t shift_amt = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004911 if (shift_amt == 0) {
4912 // Already fine.
4913 return;
4914 }
4915 if (shift_amt == 32) {
4916 // Just swap.
4917 __ movl(temp_reg, first_reg_lo);
4918 __ movl(first_reg_lo, first_reg_hi);
4919 __ movl(first_reg_hi, temp_reg);
4920 return;
4921 }
4922
4923 Immediate imm(shift_amt);
4924 // Save the constents of the low value.
4925 __ movl(temp_reg, first_reg_lo);
4926
4927 // Shift right into low, feeding bits from high.
4928 __ shrd(first_reg_lo, first_reg_hi, imm);
4929
4930 // Shift right into high, feeding bits from the original low.
4931 __ shrd(first_reg_hi, temp_reg, imm);
4932
4933 // Swap if needed.
4934 if (shift_amt > 32) {
4935 __ movl(temp_reg, first_reg_lo);
4936 __ movl(first_reg_lo, first_reg_hi);
4937 __ movl(first_reg_hi, temp_reg);
4938 }
4939 }
4940}
4941
Calin Juravle9aec02f2014-11-18 23:06:35 +00004942void LocationsBuilderX86::VisitShl(HShl* shl) {
4943 HandleShift(shl);
4944}
4945
4946void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
4947 HandleShift(shl);
4948}
4949
4950void LocationsBuilderX86::VisitShr(HShr* shr) {
4951 HandleShift(shr);
4952}
4953
4954void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
4955 HandleShift(shr);
4956}
4957
4958void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
4959 HandleShift(ushr);
4960}
4961
4962void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
4963 HandleShift(ushr);
4964}
4965
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004966void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01004967 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
4968 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004969 locations->SetOut(Location::RegisterLocation(EAX));
Alex Lightd109e302018-06-27 10:25:41 -07004970 InvokeRuntimeCallingConvention calling_convention;
4971 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004972}
4973
4974void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
Alex Lightd109e302018-06-27 10:25:41 -07004975 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
4976 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
4977 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004978}
4979
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004980void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01004981 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
4982 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004983 locations->SetOut(Location::RegisterLocation(EAX));
4984 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004985 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4986 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004987}
4988
4989void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
Vladimir Markob5461632018-10-15 14:24:21 +01004990 // Note: if heap poisoning is enabled, the entry point takes care of poisoning the reference.
4991 QuickEntrypointEnum entrypoint = CodeGenerator::GetArrayAllocationEntrypoint(instruction);
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00004992 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004993 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004994 DCHECK(!codegen_->IsLeafMethod());
4995}
4996
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004997void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004998 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004999 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005000 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5001 if (location.IsStackSlot()) {
5002 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5003 } else if (location.IsDoubleStackSlot()) {
5004 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005005 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005006 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005007}
5008
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005009void InstructionCodeGeneratorX86::VisitParameterValue(
5010 HParameterValue* instruction ATTRIBUTE_UNUSED) {
5011}
5012
5013void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
5014 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005015 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005016 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5017}
5018
5019void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005020}
5021
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005022void LocationsBuilderX86::VisitClassTableGet(HClassTableGet* instruction) {
5023 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005024 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005025 locations->SetInAt(0, Location::RequiresRegister());
5026 locations->SetOut(Location::RequiresRegister());
5027}
5028
5029void InstructionCodeGeneratorX86::VisitClassTableGet(HClassTableGet* instruction) {
5030 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00005031 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01005032 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005033 instruction->GetIndex(), kX86PointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01005034 __ movl(locations->Out().AsRegister<Register>(),
5035 Address(locations->InAt(0).AsRegister<Register>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005036 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01005037 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00005038 instruction->GetIndex(), kX86PointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01005039 __ movl(locations->Out().AsRegister<Register>(),
5040 Address(locations->InAt(0).AsRegister<Register>(),
5041 mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
5042 // temp = temp->GetImtEntryAt(method_offset);
5043 __ movl(locations->Out().AsRegister<Register>(),
5044 Address(locations->Out().AsRegister<Register>(), method_offset));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005045 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005046}
5047
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005048void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005049 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005050 new (GetGraph()->GetAllocator()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01005051 locations->SetInAt(0, Location::RequiresRegister());
5052 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005053}
5054
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005055void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
5056 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01005057 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01005058 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01005059 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00005060 switch (not_->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005061 case DataType::Type::kInt32:
Roland Levillain271ab9c2014-11-27 15:23:57 +00005062 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005063 break;
5064
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005065 case DataType::Type::kInt64:
Roland Levillain70566432014-10-24 16:20:17 +01005066 __ notl(out.AsRegisterPairLow<Register>());
5067 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005068 break;
5069
5070 default:
5071 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
5072 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005073}
5074
David Brazdil66d126e2015-04-03 16:02:44 +01005075void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
5076 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005077 new (GetGraph()->GetAllocator()) LocationSummary(bool_not, LocationSummary::kNoCall);
David Brazdil66d126e2015-04-03 16:02:44 +01005078 locations->SetInAt(0, Location::RequiresRegister());
5079 locations->SetOut(Location::SameAsFirstInput());
5080}
5081
5082void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01005083 LocationSummary* locations = bool_not->GetLocations();
5084 Location in = locations->InAt(0);
5085 Location out = locations->Out();
5086 DCHECK(in.Equals(out));
5087 __ xorl(out.AsRegister<Register>(), Immediate(1));
5088}
5089
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005090void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005091 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005092 new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00005093 switch (compare->InputAt(0)->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005094 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005095 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005096 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005097 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005098 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005099 case DataType::Type::kInt32:
5100 case DataType::Type::kInt64: {
Calin Juravleddb7df22014-11-25 20:56:51 +00005101 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00005102 locations->SetInAt(1, Location::Any());
5103 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5104 break;
5105 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005106 case DataType::Type::kFloat32:
5107 case DataType::Type::kFloat64: {
Calin Juravleddb7df22014-11-25 20:56:51 +00005108 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00005109 if (compare->InputAt(1)->IsX86LoadFromConstantTable()) {
5110 DCHECK(compare->InputAt(1)->IsEmittedAtUseSite());
5111 } else if (compare->InputAt(1)->IsConstant()) {
5112 locations->SetInAt(1, Location::RequiresFpuRegister());
5113 } else {
5114 locations->SetInAt(1, Location::Any());
5115 }
Calin Juravleddb7df22014-11-25 20:56:51 +00005116 locations->SetOut(Location::RequiresRegister());
5117 break;
5118 }
5119 default:
5120 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
5121 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005122}
5123
5124void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005125 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005126 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00005127 Location left = locations->InAt(0);
5128 Location right = locations->InAt(1);
5129
Mark Mendell0c9497d2015-08-21 09:30:05 -04005130 NearLabel less, greater, done;
Aart Bika19616e2016-02-01 18:57:58 -08005131 Condition less_cond = kLess;
5132
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005133 switch (compare->InputAt(0)->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005134 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005135 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005136 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005137 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005138 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005139 case DataType::Type::kInt32: {
Roland Levillain0b671c02016-08-19 12:02:34 +01005140 codegen_->GenerateIntCompare(left, right);
Aart Bika19616e2016-02-01 18:57:58 -08005141 break;
5142 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005143 case DataType::Type::kInt64: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005144 Register left_low = left.AsRegisterPairLow<Register>();
5145 Register left_high = left.AsRegisterPairHigh<Register>();
5146 int32_t val_low = 0;
5147 int32_t val_high = 0;
5148 bool right_is_const = false;
5149
5150 if (right.IsConstant()) {
5151 DCHECK(right.GetConstant()->IsLongConstant());
5152 right_is_const = true;
5153 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
5154 val_low = Low32Bits(val);
5155 val_high = High32Bits(val);
5156 }
5157
Calin Juravleddb7df22014-11-25 20:56:51 +00005158 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005159 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005160 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005161 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005162 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005163 DCHECK(right_is_const) << right;
Aart Bika19616e2016-02-01 18:57:58 -08005164 codegen_->Compare32BitValue(left_high, val_high);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005165 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005166 __ j(kLess, &less); // Signed compare.
5167 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005168 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005169 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005170 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005171 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005172 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005173 DCHECK(right_is_const) << right;
Aart Bika19616e2016-02-01 18:57:58 -08005174 codegen_->Compare32BitValue(left_low, val_low);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005175 }
Aart Bika19616e2016-02-01 18:57:58 -08005176 less_cond = kBelow; // for CF (unsigned).
Calin Juravleddb7df22014-11-25 20:56:51 +00005177 break;
5178 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005179 case DataType::Type::kFloat32: {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00005180 GenerateFPCompare(left, right, compare, false);
Calin Juravleddb7df22014-11-25 20:56:51 +00005181 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08005182 less_cond = kBelow; // for CF (floats).
Calin Juravleddb7df22014-11-25 20:56:51 +00005183 break;
5184 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005185 case DataType::Type::kFloat64: {
Mark P Mendell2f10a5f2016-01-25 14:47:50 +00005186 GenerateFPCompare(left, right, compare, true);
Calin Juravleddb7df22014-11-25 20:56:51 +00005187 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Aart Bika19616e2016-02-01 18:57:58 -08005188 less_cond = kBelow; // for CF (floats).
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005189 break;
5190 }
5191 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00005192 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005193 }
Aart Bika19616e2016-02-01 18:57:58 -08005194
Calin Juravleddb7df22014-11-25 20:56:51 +00005195 __ movl(out, Immediate(0));
5196 __ j(kEqual, &done);
Aart Bika19616e2016-02-01 18:57:58 -08005197 __ j(less_cond, &less);
Calin Juravleddb7df22014-11-25 20:56:51 +00005198
5199 __ Bind(&greater);
5200 __ movl(out, Immediate(1));
5201 __ jmp(&done);
5202
5203 __ Bind(&less);
5204 __ movl(out, Immediate(-1));
5205
5206 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005207}
5208
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005209void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005210 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005211 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005212 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01005213 locations->SetInAt(i, Location::Any());
5214 }
5215 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005216}
5217
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005218void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005219 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005220}
5221
Roland Levillain7c1559a2015-12-15 10:55:36 +00005222void CodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
Calin Juravle52c48962014-12-16 17:02:57 +00005223 /*
5224 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
5225 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
5226 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
5227 */
5228 switch (kind) {
5229 case MemBarrierKind::kAnyAny: {
Mark P Mendell17077d82015-12-16 19:15:59 +00005230 MemoryFence();
Calin Juravle52c48962014-12-16 17:02:57 +00005231 break;
5232 }
5233 case MemBarrierKind::kAnyStore:
5234 case MemBarrierKind::kLoadAny:
5235 case MemBarrierKind::kStoreStore: {
5236 // nop
5237 break;
5238 }
Mark Mendell7aa04a12016-01-27 22:39:07 -05005239 case MemBarrierKind::kNTStoreStore:
5240 // Non-Temporal Store/Store needs an explicit fence.
Andreas Gampe3db70682018-12-26 15:12:03 -08005241 MemoryFence(/* non-temporal= */ true);
Mark Mendell7aa04a12016-01-27 22:39:07 -05005242 break;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005243 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005244}
5245
Vladimir Markodc151b22015-10-15 18:02:30 +01005246HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
5247 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffraybdb2ecc2018-09-18 14:33:55 +01005248 ArtMethod* method ATTRIBUTE_UNUSED) {
Nicolas Geoffray133719e2017-01-22 15:44:39 +00005249 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01005250}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005251
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005252Register CodeGeneratorX86::GetInvokeExtraParameter(HInvoke* invoke, Register temp) {
5253 if (invoke->IsInvokeStaticOrDirect()) {
5254 return GetInvokeStaticOrDirectExtraParameter(invoke->AsInvokeStaticOrDirect(), temp);
5255 }
5256 DCHECK(invoke->IsInvokeInterface());
5257 Location location =
5258 invoke->GetLocations()->InAt(invoke->AsInvokeInterface()->GetSpecialInputIndex());
5259 return location.AsRegister<Register>();
5260}
5261
Vladimir Marko0f7dca42015-11-02 14:36:43 +00005262Register CodeGeneratorX86::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
5263 Register temp) {
Vladimir Markoc53c0792015-11-19 15:48:33 +00005264 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko0f7dca42015-11-02 14:36:43 +00005265 if (!invoke->GetLocations()->Intrinsified()) {
5266 return location.AsRegister<Register>();
5267 }
5268 // For intrinsics we allow any location, so it may be on the stack.
5269 if (!location.IsRegister()) {
5270 __ movl(temp, Address(ESP, location.GetStackIndex()));
5271 return temp;
5272 }
5273 // For register locations, check if the register was saved. If so, get it from the stack.
5274 // Note: There is a chance that the register was saved but not overwritten, so we could
5275 // save one load. However, since this is just an intrinsic slow path we prefer this
5276 // simple and more robust approach rather that trying to determine if that's the case.
5277 SlowPathCode* slow_path = GetCurrentSlowPath();
Vladimir Marko4ee8e292017-06-02 15:39:30 +00005278 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
5279 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
5280 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
5281 __ movl(temp, Address(ESP, stack_offset));
5282 return temp;
Vladimir Marko0f7dca42015-11-02 14:36:43 +00005283 }
5284 return location.AsRegister<Register>();
5285}
5286
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005287void CodeGeneratorX86::LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke) {
5288 switch (load_kind) {
5289 case MethodLoadKind::kBootImageLinkTimePcRelative: {
5290 DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5291 Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5292 __ leal(temp.AsRegister<Register>(),
5293 Address(base_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5294 RecordBootImageMethodPatch(invoke);
5295 break;
5296 }
5297 case MethodLoadKind::kBootImageRelRo: {
5298 size_t index = invoke->IsInvokeInterface()
5299 ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5300 : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
5301 Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5302 __ movl(temp.AsRegister<Register>(), Address(base_reg, kPlaceholder32BitOffset));
5303 RecordBootImageRelRoPatch(
5304 invoke->InputAt(index)->AsX86ComputeBaseMethodAddress(),
5305 GetBootImageOffset(invoke));
5306 break;
5307 }
5308 case MethodLoadKind::kBssEntry: {
5309 Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5310 __ movl(temp.AsRegister<Register>(), Address(base_reg, kPlaceholder32BitOffset));
5311 RecordMethodBssEntryPatch(invoke);
5312 // No need for memory fence, thanks to the x86 memory model.
5313 break;
5314 }
5315 case MethodLoadKind::kJitDirectAddress: {
5316 __ movl(temp.AsRegister<Register>(),
5317 Immediate(reinterpret_cast32<uint32_t>(invoke->GetResolvedMethod())));
5318 break;
5319 }
5320 case MethodLoadKind::kRuntimeCall: {
5321 // Test situation, don't do anything.
5322 break;
5323 }
5324 default: {
5325 LOG(FATAL) << "Load kind should have already been handled " << load_kind;
5326 UNREACHABLE();
5327 }
5328 }
5329}
5330
Vladimir Markoe7197bf2017-06-02 17:00:23 +01005331void CodeGeneratorX86::GenerateStaticOrDirectCall(
5332 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Vladimir Marko58155012015-08-19 12:49:41 +00005333 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
5334 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01005335 case MethodLoadKind::kStringInit: {
Vladimir Marko58155012015-08-19 12:49:41 +00005336 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005337 uint32_t offset =
5338 GetThreadOffset<kX86PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
5339 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(offset));
Vladimir Marko58155012015-08-19 12:49:41 +00005340 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005341 }
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005342 case MethodLoadKind::kRecursive: {
Vladimir Marko86c87522020-05-11 16:55:55 +01005343 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00005344 break;
Vladimir Marko65979462017-05-19 17:25:12 +01005345 }
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01005346 case MethodLoadKind::kRuntimeCall: {
Vladimir Markoe7197bf2017-06-02 17:00:23 +01005347 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
5348 return; // No code pointer retrieval; the runtime performs the call directly.
Vladimir Marko9b688a02015-05-06 14:12:42 +01005349 }
Vladimir Markoeb9eb002020-10-02 13:54:19 +01005350 case MethodLoadKind::kBootImageLinkTimePcRelative:
5351 // For kCallCriticalNative we skip loading the method and do the call directly.
5352 if (invoke->GetCodePtrLocation() == CodePtrLocation::kCallCriticalNative) {
5353 break;
5354 }
5355 FALLTHROUGH_INTENDED;
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005356 default: {
5357 LoadMethod(invoke->GetMethodLoadKind(), callee_method, invoke);
5358 }
Vladimir Marko58155012015-08-19 12:49:41 +00005359 }
5360
5361 switch (invoke->GetCodePtrLocation()) {
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01005362 case CodePtrLocation::kCallSelf:
Nicolas Geoffray282795c2021-09-24 18:16:41 +01005363 DCHECK(!GetGraph()->HasShouldDeoptimizeFlag());
Vladimir Marko58155012015-08-19 12:49:41 +00005364 __ call(GetFrameEntryLabel());
Vladimir Marko86c87522020-05-11 16:55:55 +01005365 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Vladimir Marko58155012015-08-19 12:49:41 +00005366 break;
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01005367 case CodePtrLocation::kCallCriticalNative: {
Vladimir Marko86c87522020-05-11 16:55:55 +01005368 size_t out_frame_size =
5369 PrepareCriticalNativeCall<CriticalNativeCallingConventionVisitorX86,
5370 kNativeStackAlignment,
Vladimir Markodec78172020-06-19 15:31:23 +01005371 GetCriticalNativeDirectCallFrameSize>(invoke);
Vladimir Markoeb9eb002020-10-02 13:54:19 +01005372 if (invoke->GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative) {
5373 DCHECK(GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension());
5374 Register base_reg = GetInvokeExtraParameter(invoke, temp.AsRegister<Register>());
5375 __ call(Address(base_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
5376 RecordBootImageJniEntrypointPatch(invoke);
5377 } else {
5378 // (callee_method + offset_of_jni_entry_point)()
5379 __ call(Address(callee_method.AsRegister<Register>(),
5380 ArtMethod::EntryPointFromJniOffset(kX86PointerSize).Int32Value()));
5381 }
Vladimir Marko86c87522020-05-11 16:55:55 +01005382 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
5383 if (out_frame_size == 0u && DataType::IsFloatingPointType(invoke->GetType())) {
5384 // Create space for conversion.
5385 out_frame_size = 8u;
Vladimir Markodec78172020-06-19 15:31:23 +01005386 IncreaseFrame(out_frame_size);
Vladimir Marko86c87522020-05-11 16:55:55 +01005387 }
5388 // Zero-/sign-extend or move the result when needed due to native and managed ABI mismatch.
5389 switch (invoke->GetType()) {
5390 case DataType::Type::kBool:
5391 __ movzxb(EAX, AL);
5392 break;
5393 case DataType::Type::kInt8:
5394 __ movsxb(EAX, AL);
5395 break;
5396 case DataType::Type::kUint16:
5397 __ movzxw(EAX, EAX);
5398 break;
5399 case DataType::Type::kInt16:
5400 __ movsxw(EAX, EAX);
5401 break;
5402 case DataType::Type::kFloat32:
5403 __ fstps(Address(ESP, 0));
5404 __ movss(XMM0, Address(ESP, 0));
5405 break;
5406 case DataType::Type::kFloat64:
5407 __ fstpl(Address(ESP, 0));
5408 __ movsd(XMM0, Address(ESP, 0));
5409 break;
5410 case DataType::Type::kInt32:
5411 case DataType::Type::kInt64:
5412 case DataType::Type::kVoid:
5413 break;
5414 default:
5415 DCHECK(false) << invoke->GetType();
5416 break;
5417 }
5418 if (out_frame_size != 0u) {
Vladimir Markodec78172020-06-19 15:31:23 +01005419 DecreaseFrame(out_frame_size);
Vladimir Marko86c87522020-05-11 16:55:55 +01005420 }
5421 break;
5422 }
Nicolas Geoffray6d69b522020-09-23 14:47:28 +01005423 case CodePtrLocation::kCallArtMethod:
Vladimir Marko58155012015-08-19 12:49:41 +00005424 // (callee_method + offset_of_quick_compiled_code)()
5425 __ call(Address(callee_method.AsRegister<Register>(),
5426 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07005427 kX86PointerSize).Int32Value()));
Vladimir Marko86c87522020-05-11 16:55:55 +01005428 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Vladimir Marko58155012015-08-19 12:49:41 +00005429 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04005430 }
5431
5432 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04005433}
5434
Vladimir Markoe7197bf2017-06-02 17:00:23 +01005435void CodeGeneratorX86::GenerateVirtualCall(
5436 HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005437 Register temp = temp_in.AsRegister<Register>();
5438 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5439 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00005440
5441 // Use the calling convention instead of the location of the receiver, as
5442 // intrinsics may have put the receiver in a different register. In the intrinsics
5443 // slow path, the arguments have been moved to the right place, so here we are
5444 // guaranteed that the receiver is the first register of the calling convention.
5445 InvokeDexCallingConvention calling_convention;
5446 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005447 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain0d5a2812015-11-13 10:07:31 +00005448 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00005449 __ movl(temp, Address(receiver, class_offset));
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005450 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005451 // Instead of simply (possibly) unpoisoning `temp` here, we should
5452 // emit a read barrier for the previous class reference load.
5453 // However this is not required in practice, as this is an
5454 // intermediate/temporary reference and because the current
5455 // concurrent copying collector keeps the from-space memory
5456 // intact/accessible until the end of the marking phase (the
5457 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005458 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye2a3aa92019-11-25 17:52:58 +00005459
5460 MaybeGenerateInlineCacheCheck(invoke, temp);
5461
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005462 // temp = temp->GetMethodAt(method_offset);
5463 __ movl(temp, Address(temp, method_offset));
5464 // call temp->GetEntryPoint();
5465 __ call(Address(
Andreas Gampe542451c2016-07-26 09:02:02 -07005466 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86PointerSize).Int32Value()));
Vladimir Markoe7197bf2017-06-02 17:00:23 +01005467 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005468}
5469
Vladimir Marko6fd16062018-06-26 11:02:04 +01005470void CodeGeneratorX86::RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress* method_address,
5471 uint32_t intrinsic_data) {
Vladimir Marko2d06e022019-07-08 15:45:19 +01005472 boot_image_other_patches_.emplace_back(
Andreas Gampe3db70682018-12-26 15:12:03 -08005473 method_address, /* target_dex_file= */ nullptr, intrinsic_data);
Vladimir Marko2d06e022019-07-08 15:45:19 +01005474 __ Bind(&boot_image_other_patches_.back().label);
Vladimir Marko6fd16062018-06-26 11:02:04 +01005475}
5476
Vladimir Markob066d432018-01-03 13:14:37 +00005477void CodeGeneratorX86::RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
5478 uint32_t boot_image_offset) {
Vladimir Marko2d06e022019-07-08 15:45:19 +01005479 boot_image_other_patches_.emplace_back(
Andreas Gampe3db70682018-12-26 15:12:03 -08005480 method_address, /* target_dex_file= */ nullptr, boot_image_offset);
Vladimir Marko2d06e022019-07-08 15:45:19 +01005481 __ Bind(&boot_image_other_patches_.back().label);
Vladimir Markob066d432018-01-03 13:14:37 +00005482}
5483
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005484void CodeGeneratorX86::RecordBootImageMethodPatch(HInvoke* invoke) {
5485 size_t index = invoke->IsInvokeInterface()
5486 ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5487 : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005488 HX86ComputeBaseMethodAddress* method_address =
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005489 invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005490 boot_image_method_patches_.emplace_back(
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +01005491 method_address,
5492 invoke->GetResolvedMethodReference().dex_file,
5493 invoke->GetResolvedMethodReference().index);
Vladimir Marko65979462017-05-19 17:25:12 +01005494 __ Bind(&boot_image_method_patches_.back().label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005495}
5496
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005497void CodeGeneratorX86::RecordMethodBssEntryPatch(HInvoke* invoke) {
5498 size_t index = invoke->IsInvokeInterface()
5499 ? invoke->AsInvokeInterface()->GetSpecialInputIndex()
5500 : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +01005501 DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005502 HX86ComputeBaseMethodAddress* method_address =
Nicolas Geoffray8d34a182020-09-16 09:46:58 +01005503 invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
Vladimir Marko0eb882b2017-05-15 13:39:18 +01005504 // Add the patch entry and bind its label at the end of the instruction.
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005505 method_bss_entry_patches_.emplace_back(
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +01005506 method_address,
5507 invoke->GetMethodReference().dex_file,
5508 invoke->GetMethodReference().index);
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005509 __ Bind(&method_bss_entry_patches_.back().label);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01005510}
5511
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005512void CodeGeneratorX86::RecordBootImageTypePatch(HLoadClass* load_class) {
5513 HX86ComputeBaseMethodAddress* method_address =
5514 load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
5515 boot_image_type_patches_.emplace_back(
5516 method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00005517 __ Bind(&boot_image_type_patches_.back().label);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005518}
5519
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005520Label* CodeGeneratorX86::NewTypeBssEntryPatch(HLoadClass* load_class) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005521 HX86ComputeBaseMethodAddress* method_address =
Nicolas Geoffray133719e2017-01-22 15:44:39 +00005522 load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
Vladimir Marko8f63f102020-09-28 12:10:28 +01005523 ArenaDeque<X86PcRelativePatchInfo>* patches = nullptr;
5524 switch (load_class->GetLoadKind()) {
5525 case HLoadClass::LoadKind::kBssEntry:
5526 patches = &type_bss_entry_patches_;
5527 break;
5528 case HLoadClass::LoadKind::kBssEntryPublic:
5529 patches = &public_type_bss_entry_patches_;
5530 break;
5531 case HLoadClass::LoadKind::kBssEntryPackage:
5532 patches = &package_type_bss_entry_patches_;
5533 break;
5534 default:
5535 LOG(FATAL) << "Unexpected load kind: " << load_class->GetLoadKind();
5536 UNREACHABLE();
5537 }
5538 patches->emplace_back(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005539 method_address, &load_class->GetDexFile(), load_class->GetTypeIndex().index_);
Vladimir Marko8f63f102020-09-28 12:10:28 +01005540 return &patches->back().label;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005541}
5542
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005543void CodeGeneratorX86::RecordBootImageStringPatch(HLoadString* load_string) {
5544 HX86ComputeBaseMethodAddress* method_address =
5545 load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
5546 boot_image_string_patches_.emplace_back(
5547 method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
5548 __ Bind(&boot_image_string_patches_.back().label);
Vladimir Marko65979462017-05-19 17:25:12 +01005549}
5550
Vladimir Markoaad75c62016-10-03 08:46:48 +00005551Label* CodeGeneratorX86::NewStringBssEntryPatch(HLoadString* load_string) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005552 HX86ComputeBaseMethodAddress* method_address =
Nicolas Geoffray133719e2017-01-22 15:44:39 +00005553 load_string->InputAt(0)->AsX86ComputeBaseMethodAddress();
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01005554 string_bss_entry_patches_.emplace_back(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005555 method_address, &load_string->GetDexFile(), load_string->GetStringIndex().index_);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01005556 return &string_bss_entry_patches_.back().label;
Vladimir Markoaad75c62016-10-03 08:46:48 +00005557}
5558
Vladimir Markoeb9eb002020-10-02 13:54:19 +01005559void CodeGeneratorX86::RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke) {
5560 HX86ComputeBaseMethodAddress* method_address =
5561 invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5562 boot_image_jni_entrypoint_patches_.emplace_back(
5563 method_address,
5564 invoke->GetResolvedMethodReference().dex_file,
5565 invoke->GetResolvedMethodReference().index);
5566 __ Bind(&boot_image_jni_entrypoint_patches_.back().label);
5567}
5568
Vladimir Markoeebb8212018-06-05 14:57:24 +01005569void CodeGeneratorX86::LoadBootImageAddress(Register reg,
Vladimir Marko6fd16062018-06-26 11:02:04 +01005570 uint32_t boot_image_reference,
Vladimir Markoeebb8212018-06-05 14:57:24 +01005571 HInvokeStaticOrDirect* invoke) {
Vladimir Marko6fd16062018-06-26 11:02:04 +01005572 if (GetCompilerOptions().IsBootImage()) {
Vladimir Marko6fd16062018-06-26 11:02:04 +01005573 HX86ComputeBaseMethodAddress* method_address =
5574 invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5575 DCHECK(method_address != nullptr);
5576 Register method_address_reg =
5577 invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00005578 __ leal(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Marko6fd16062018-06-26 11:02:04 +01005579 RecordBootImageIntrinsicPatch(method_address, boot_image_reference);
Vladimir Markoa2da9b92018-10-10 14:21:55 +01005580 } else if (GetCompilerOptions().GetCompilePic()) {
Vladimir Markoeebb8212018-06-05 14:57:24 +01005581 HX86ComputeBaseMethodAddress* method_address =
5582 invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5583 DCHECK(method_address != nullptr);
5584 Register method_address_reg =
5585 invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00005586 __ movl(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Marko6fd16062018-06-26 11:02:04 +01005587 RecordBootImageRelRoPatch(method_address, boot_image_reference);
Vladimir Markoeebb8212018-06-05 14:57:24 +01005588 } else {
Vladimir Marko695348f2020-05-19 14:42:02 +01005589 DCHECK(GetCompilerOptions().IsJitCompiler());
Vladimir Markoeebb8212018-06-05 14:57:24 +01005590 gc::Heap* heap = Runtime::Current()->GetHeap();
5591 DCHECK(!heap->GetBootImageSpaces().empty());
Vladimir Marko6fd16062018-06-26 11:02:04 +01005592 const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_reference;
Vladimir Markoeebb8212018-06-05 14:57:24 +01005593 __ movl(reg, Immediate(dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(address))));
5594 }
5595}
5596
Vladimir Markode91ca92020-10-27 13:41:40 +00005597void CodeGeneratorX86::LoadIntrinsicDeclaringClass(Register reg, HInvokeStaticOrDirect* invoke) {
5598 DCHECK_NE(invoke->GetIntrinsic(), Intrinsics::kNone);
Vladimir Marko6fd16062018-06-26 11:02:04 +01005599 if (GetCompilerOptions().IsBootImage()) {
Vladimir Marko6fd16062018-06-26 11:02:04 +01005600 // Load the class the same way as for HLoadClass::LoadKind::kBootImageLinkTimePcRelative.
Vladimir Marko6fd16062018-06-26 11:02:04 +01005601 HX86ComputeBaseMethodAddress* method_address =
5602 invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
5603 DCHECK(method_address != nullptr);
5604 Register method_address_reg =
5605 invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
Vladimir Markode91ca92020-10-27 13:41:40 +00005606 __ leal(reg, Address(method_address_reg, CodeGeneratorX86::kPlaceholder32BitOffset));
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +01005607 MethodReference target_method = invoke->GetResolvedMethodReference();
Vladimir Marko6fd16062018-06-26 11:02:04 +01005608 dex::TypeIndex type_idx = target_method.dex_file->GetMethodId(target_method.index).class_idx_;
5609 boot_image_type_patches_.emplace_back(method_address, target_method.dex_file, type_idx.index_);
5610 __ Bind(&boot_image_type_patches_.back().label);
5611 } else {
Vladimir Markode91ca92020-10-27 13:41:40 +00005612 uint32_t boot_image_offset = GetBootImageOffsetOfIntrinsicDeclaringClass(invoke);
5613 LoadBootImageAddress(reg, boot_image_offset, invoke);
Vladimir Marko6fd16062018-06-26 11:02:04 +01005614 }
Vladimir Marko6fd16062018-06-26 11:02:04 +01005615}
5616
Vladimir Markoaad75c62016-10-03 08:46:48 +00005617// The label points to the end of the "movl" or another instruction but the literal offset
5618// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
5619constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
5620
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005621template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
Vladimir Markoaad75c62016-10-03 08:46:48 +00005622inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches(
Nicolas Geoffray133719e2017-01-22 15:44:39 +00005623 const ArenaDeque<X86PcRelativePatchInfo>& infos,
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005624 ArenaVector<linker::LinkerPatch>* linker_patches) {
Nicolas Geoffray133719e2017-01-22 15:44:39 +00005625 for (const X86PcRelativePatchInfo& info : infos) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00005626 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005627 linker_patches->push_back(Factory(literal_offset,
5628 info.target_dex_file,
5629 GetMethodAddressOffset(info.method_address),
5630 info.offset_or_index));
Vladimir Markoaad75c62016-10-03 08:46:48 +00005631 }
5632}
5633
Vladimir Marko6fd16062018-06-26 11:02:04 +01005634template <linker::LinkerPatch (*Factory)(size_t, uint32_t, uint32_t)>
5635linker::LinkerPatch NoDexFileAdapter(size_t literal_offset,
5636 const DexFile* target_dex_file,
5637 uint32_t pc_insn_offset,
5638 uint32_t boot_image_offset) {
5639 DCHECK(target_dex_file == nullptr); // Unused for these patches, should be null.
5640 return Factory(literal_offset, pc_insn_offset, boot_image_offset);
Vladimir Markob066d432018-01-03 13:14:37 +00005641}
5642
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005643void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
Vladimir Marko58155012015-08-19 12:49:41 +00005644 DCHECK(linker_patches->empty());
Vladimir Marko0f7dca42015-11-02 14:36:43 +00005645 size_t size =
Vladimir Marko65979462017-05-19 17:25:12 +01005646 boot_image_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01005647 method_bss_entry_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00005648 boot_image_type_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01005649 type_bss_entry_patches_.size() +
Vladimir Marko8f63f102020-09-28 12:10:28 +01005650 public_type_bss_entry_patches_.size() +
5651 package_type_bss_entry_patches_.size() +
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005652 boot_image_string_patches_.size() +
Vladimir Marko6fd16062018-06-26 11:02:04 +01005653 string_bss_entry_patches_.size() +
Vladimir Markoeb9eb002020-10-02 13:54:19 +01005654 boot_image_jni_entrypoint_patches_.size() +
Vladimir Marko2d06e022019-07-08 15:45:19 +01005655 boot_image_other_patches_.size();
Vladimir Marko0f7dca42015-11-02 14:36:43 +00005656 linker_patches->reserve(size);
Vladimir Marko44ca0752019-07-29 10:18:25 +01005657 if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005658 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
5659 boot_image_method_patches_, linker_patches);
5660 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
5661 boot_image_type_patches_, linker_patches);
5662 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00005663 boot_image_string_patches_, linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005664 } else {
Vladimir Marko2d06e022019-07-08 15:45:19 +01005665 DCHECK(boot_image_method_patches_.empty());
Vladimir Markoe47f60c2018-02-21 13:43:28 +00005666 DCHECK(boot_image_type_patches_.empty());
5667 DCHECK(boot_image_string_patches_.empty());
Vladimir Marko2d06e022019-07-08 15:45:19 +01005668 }
5669 if (GetCompilerOptions().IsBootImage()) {
5670 EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::IntrinsicReferencePatch>>(
5671 boot_image_other_patches_, linker_patches);
5672 } else {
5673 EmitPcRelativeLinkerPatches<NoDexFileAdapter<linker::LinkerPatch::DataBimgRelRoPatch>>(
5674 boot_image_other_patches_, linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005675 }
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005676 EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
5677 method_bss_entry_patches_, linker_patches);
5678 EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
5679 type_bss_entry_patches_, linker_patches);
Vladimir Marko8f63f102020-09-28 12:10:28 +01005680 EmitPcRelativeLinkerPatches<linker::LinkerPatch::PublicTypeBssEntryPatch>(
5681 public_type_bss_entry_patches_, linker_patches);
5682 EmitPcRelativeLinkerPatches<linker::LinkerPatch::PackageTypeBssEntryPatch>(
5683 package_type_bss_entry_patches_, linker_patches);
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01005684 EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
5685 string_bss_entry_patches_, linker_patches);
Vladimir Markoeb9eb002020-10-02 13:54:19 +01005686 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeJniEntrypointPatch>(
5687 boot_image_jni_entrypoint_patches_, linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00005688 DCHECK_EQ(size, linker_patches->size());
Vladimir Marko58155012015-08-19 12:49:41 +00005689}
5690
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005691void CodeGeneratorX86::MarkGCCard(Register temp,
5692 Register card,
5693 Register object,
5694 Register value,
5695 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04005696 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005697 if (value_can_be_null) {
5698 __ testl(value, value);
5699 __ j(kEqual, &is_null);
5700 }
Roland Levillainc73f0522018-08-14 15:16:50 +01005701 // Load the address of the card table into `card`.
Andreas Gampe542451c2016-07-26 09:02:02 -07005702 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86PointerSize>().Int32Value()));
Roland Levillainc73f0522018-08-14 15:16:50 +01005703 // Calculate the offset (in the card table) of the card corresponding to
5704 // `object`.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005705 __ movl(temp, object);
5706 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Roland Levillainc73f0522018-08-14 15:16:50 +01005707 // Write the `art::gc::accounting::CardTable::kCardDirty` value into the
5708 // `object`'s card.
5709 //
5710 // Register `card` contains the address of the card table. Note that the card
5711 // table's base is biased during its creation so that it always starts at an
5712 // address whose least-significant byte is equal to `kCardDirty` (see
5713 // art::gc::accounting::CardTable::Create). Therefore the MOVB instruction
5714 // below writes the `kCardDirty` (byte) value into the `object`'s card
5715 // (located at `card + object >> kCardShift`).
5716 //
5717 // This dual use of the value in register `card` (1. to calculate the location
5718 // of the card to mark; and 2. to load the `kCardDirty` value) saves a load
5719 // (no need to explicitly load `kCardDirty` as an immediate value).
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00005720 __ movb(Address(temp, card, TIMES_1, 0),
5721 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005722 if (value_can_be_null) {
5723 __ Bind(&is_null);
5724 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005725}
5726
Calin Juravle52c48962014-12-16 17:02:57 +00005727void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
Alex Light3a73ffb2021-01-25 14:11:05 +00005728 DCHECK(instruction->IsInstanceFieldGet() ||
5729 instruction->IsStaticFieldGet() ||
5730 instruction->IsPredicatedInstanceFieldGet());
Roland Levillain0d5a2812015-11-13 10:07:31 +00005731
5732 bool object_field_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005733 kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
Alex Light3a73ffb2021-01-25 14:11:05 +00005734 bool is_predicated = instruction->IsPredicatedInstanceFieldGet();
Nicolas Geoffray39468442014-09-02 15:17:15 +01005735 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005736 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
5737 kEmitCompilerReadBarrier
5738 ? LocationSummary::kCallOnSlowPath
5739 : LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005740 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005741 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005742 }
Alex Light3a73ffb2021-01-25 14:11:05 +00005743 // receiver_input
5744 locations->SetInAt(is_predicated ? 1 : 0, Location::RequiresRegister());
5745 if (is_predicated) {
5746 if (DataType::IsFloatingPointType(instruction->GetType())) {
5747 locations->SetInAt(0, Location::RequiresFpuRegister());
5748 } else {
5749 locations->SetInAt(0, Location::RequiresRegister());
5750 }
5751 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005752 if (DataType::IsFloatingPointType(instruction->GetType())) {
Alex Light3a73ffb2021-01-25 14:11:05 +00005753 locations->SetOut(is_predicated ? Location::SameAsFirstInput()
5754 : Location::RequiresFpuRegister());
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005755 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00005756 // The output overlaps in case of long: we don't want the low move
5757 // to overwrite the object's location. Likewise, in the case of
5758 // an object field get with read barriers enabled, we do not want
5759 // the move to overwrite the object's location, as we need it to emit
5760 // the read barrier.
Alex Light3a73ffb2021-01-25 14:11:05 +00005761 locations->SetOut(is_predicated ? Location::SameAsFirstInput() : Location::RequiresRegister(),
5762 (object_field_get_with_read_barrier ||
5763 instruction->GetType() == DataType::Type::kInt64 ||
5764 is_predicated)
5765 ? Location::kOutputOverlap
5766 : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005767 }
Calin Juravle52c48962014-12-16 17:02:57 +00005768
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005769 if (field_info.IsVolatile() && (field_info.GetFieldType() == DataType::Type::kInt64)) {
Calin Juravle52c48962014-12-16 17:02:57 +00005770 // Long values can be loaded atomically into an XMM using movsd.
Roland Levillain7c1559a2015-12-15 10:55:36 +00005771 // So we use an XMM register as a temp to achieve atomicity (first
5772 // load the temp into the XMM and then copy the XMM into the
5773 // output, 32 bits at a time).
Calin Juravle52c48962014-12-16 17:02:57 +00005774 locations->AddTemp(Location::RequiresFpuRegister());
5775 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005776}
5777
Calin Juravle52c48962014-12-16 17:02:57 +00005778void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
5779 const FieldInfo& field_info) {
Alex Light3a73ffb2021-01-25 14:11:05 +00005780 DCHECK(instruction->IsInstanceFieldGet() ||
5781 instruction->IsStaticFieldGet() ||
5782 instruction->IsPredicatedInstanceFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005783
Calin Juravle52c48962014-12-16 17:02:57 +00005784 LocationSummary* locations = instruction->GetLocations();
Alex Light3a73ffb2021-01-25 14:11:05 +00005785 Location base_loc = locations->InAt(instruction->IsPredicatedInstanceFieldGet() ? 1 : 0);
Roland Levillain0d5a2812015-11-13 10:07:31 +00005786 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00005787 Location out = locations->Out();
5788 bool is_volatile = field_info.IsVolatile();
Vladimir Marko61b92282017-10-11 13:23:17 +01005789 DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
5790 DataType::Type load_type = instruction->GetType();
Calin Juravle52c48962014-12-16 17:02:57 +00005791 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5792
Ulya Trafimovich322eced2021-06-02 15:39:36 +01005793 if (load_type == DataType::Type::kReference) {
5794 // /* HeapReference<Object> */ out = *(base + offset)
5795 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5796 // Note that a potential implicit null check is handled in this
5797 // CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier call.
5798 codegen_->GenerateFieldLoadWithBakerReadBarrier(
5799 instruction, out, base, offset, /* needs_null_check= */ true);
Calin Juravle52c48962014-12-16 17:02:57 +00005800 if (is_volatile) {
Ulya Trafimovich322eced2021-06-02 15:39:36 +01005801 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005802 }
Roland Levillain7c1559a2015-12-15 10:55:36 +00005803 } else {
Ulya Trafimovich322eced2021-06-02 15:39:36 +01005804 __ movl(out.AsRegister<Register>(), Address(base, offset));
5805 codegen_->MaybeRecordImplicitNullCheck(instruction);
5806 if (is_volatile) {
5807 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5808 }
5809 // If read barriers are enabled, emit read barriers other than
5810 // Baker's using a slow path (and also unpoison the loaded
5811 // reference, if heap poisoning is enabled).
5812 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5813 }
5814 } else {
5815 Address src(base, offset);
5816 XmmRegister temp = (load_type == DataType::Type::kInt64 && is_volatile)
5817 ? locations->GetTemp(0).AsFpuRegister<XmmRegister>()
5818 : kNoXmmRegister;
5819 codegen_->LoadFromMemoryNoBarrier(load_type, out, src, instruction, temp, is_volatile);
5820 if (is_volatile) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00005821 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5822 }
Roland Levillain4d027112015-07-01 15:41:14 +01005823 }
Calin Juravle52c48962014-12-16 17:02:57 +00005824}
5825
5826void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5827 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5828
5829 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01005830 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle52c48962014-12-16 17:02:57 +00005831 locations->SetInAt(0, Location::RequiresRegister());
5832 bool is_volatile = field_info.IsVolatile();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005833 DataType::Type field_type = field_info.GetFieldType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005834 bool is_byte_type = DataType::Size(field_type) == 1u;
Calin Juravle52c48962014-12-16 17:02:57 +00005835
5836 // The register allocator does not support multiple
5837 // inputs that die at entry with one in a specific register.
5838 if (is_byte_type) {
5839 // Ensure the value is in a byte register.
5840 locations->SetInAt(1, Location::RegisterLocation(EAX));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005841 } else if (DataType::IsFloatingPointType(field_type)) {
5842 if (is_volatile && field_type == DataType::Type::kFloat64) {
Mark Mendell81489372015-11-04 11:30:41 -05005843 // In order to satisfy the semantics of volatile, this must be a single instruction store.
5844 locations->SetInAt(1, Location::RequiresFpuRegister());
5845 } else {
5846 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1)));
5847 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005848 } else if (is_volatile && field_type == DataType::Type::kInt64) {
Mark Mendell81489372015-11-04 11:30:41 -05005849 // In order to satisfy the semantics of volatile, this must be a single instruction store.
Calin Juravle52c48962014-12-16 17:02:57 +00005850 locations->SetInAt(1, Location::RequiresRegister());
Mark Mendell81489372015-11-04 11:30:41 -05005851
Calin Juravle52c48962014-12-16 17:02:57 +00005852 // 64bits value can be atomically written to an address with movsd and an XMM register.
5853 // We need two XMM registers because there's no easier way to (bit) copy a register pair
5854 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
5855 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
5856 // isolated cases when we need this it isn't worth adding the extra complexity.
5857 locations->AddTemp(Location::RequiresFpuRegister());
5858 locations->AddTemp(Location::RequiresFpuRegister());
Mark Mendell81489372015-11-04 11:30:41 -05005859 } else {
5860 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5861
5862 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5863 // Temporary registers for the write barrier.
5864 locations->AddTemp(Location::RequiresRegister()); // May be used for reference poisoning too.
5865 // Ensure the card is in a byte register.
5866 locations->AddTemp(Location::RegisterLocation(ECX));
5867 }
Calin Juravle52c48962014-12-16 17:02:57 +00005868 }
5869}
5870
5871void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Andra Danciucde98192020-09-13 12:32:09 +00005872 uint32_t value_index,
5873 DataType::Type field_type,
5874 Address field_addr,
5875 Register base,
5876 bool is_volatile,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005877 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00005878 LocationSummary* locations = instruction->GetLocations();
Andra Danciucde98192020-09-13 12:32:09 +00005879 Location value = locations->InAt(value_index);
Roland Levillain4d027112015-07-01 15:41:14 +01005880 bool needs_write_barrier =
Andra Danciucde98192020-09-13 12:32:09 +00005881 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(value_index));
Calin Juravle52c48962014-12-16 17:02:57 +00005882
5883 if (is_volatile) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00005884 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00005885 }
5886
Mark Mendell81489372015-11-04 11:30:41 -05005887 bool maybe_record_implicit_null_check_done = false;
5888
Calin Juravle52c48962014-12-16 17:02:57 +00005889 switch (field_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005890 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005891 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005892 case DataType::Type::kInt8: {
Andra Danciucde98192020-09-13 12:32:09 +00005893 if (value.IsConstant()) {
5894 __ movb(field_addr, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
5895 } else {
5896 __ movb(field_addr, value.AsRegister<ByteRegister>());
5897 }
Calin Juravle52c48962014-12-16 17:02:57 +00005898 break;
5899 }
5900
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01005901 case DataType::Type::kUint16:
5902 case DataType::Type::kInt16: {
Mark Mendell81489372015-11-04 11:30:41 -05005903 if (value.IsConstant()) {
Andra Danciucde98192020-09-13 12:32:09 +00005904 __ movw(field_addr, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Mark Mendell81489372015-11-04 11:30:41 -05005905 } else {
Andra Danciucde98192020-09-13 12:32:09 +00005906 __ movw(field_addr, value.AsRegister<Register>());
Mark Mendell81489372015-11-04 11:30:41 -05005907 }
Calin Juravle52c48962014-12-16 17:02:57 +00005908 break;
5909 }
5910
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005911 case DataType::Type::kInt32:
5912 case DataType::Type::kReference: {
Roland Levillain4d027112015-07-01 15:41:14 +01005913 if (kPoisonHeapReferences && needs_write_barrier) {
5914 // Note that in the case where `value` is a null reference,
5915 // we do not enter this block, as the reference does not
5916 // need poisoning.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005917 DCHECK_EQ(field_type, DataType::Type::kReference);
Roland Levillain4d027112015-07-01 15:41:14 +01005918 Register temp = locations->GetTemp(0).AsRegister<Register>();
5919 __ movl(temp, value.AsRegister<Register>());
5920 __ PoisonHeapReference(temp);
Andra Danciucde98192020-09-13 12:32:09 +00005921 __ movl(field_addr, temp);
Mark Mendell81489372015-11-04 11:30:41 -05005922 } else if (value.IsConstant()) {
5923 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Andra Danciucde98192020-09-13 12:32:09 +00005924 __ movl(field_addr, Immediate(v));
Roland Levillain4d027112015-07-01 15:41:14 +01005925 } else {
Nicolas Geoffray03971632016-03-17 10:44:24 +00005926 DCHECK(value.IsRegister()) << value;
Andra Danciucde98192020-09-13 12:32:09 +00005927 __ movl(field_addr, value.AsRegister<Register>());
Roland Levillain4d027112015-07-01 15:41:14 +01005928 }
Calin Juravle52c48962014-12-16 17:02:57 +00005929 break;
5930 }
5931
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005932 case DataType::Type::kInt64: {
Calin Juravle52c48962014-12-16 17:02:57 +00005933 if (is_volatile) {
5934 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
5935 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
5936 __ movd(temp1, value.AsRegisterPairLow<Register>());
5937 __ movd(temp2, value.AsRegisterPairHigh<Register>());
5938 __ punpckldq(temp1, temp2);
Andra Danciucde98192020-09-13 12:32:09 +00005939 __ movsd(field_addr, temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00005940 codegen_->MaybeRecordImplicitNullCheck(instruction);
Mark Mendell81489372015-11-04 11:30:41 -05005941 } else if (value.IsConstant()) {
5942 int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant());
Andra Danciucde98192020-09-13 12:32:09 +00005943 __ movl(field_addr, Immediate(Low32Bits(v)));
Mark Mendell81489372015-11-04 11:30:41 -05005944 codegen_->MaybeRecordImplicitNullCheck(instruction);
Ulya Trafimovich893e2ed2021-06-10 16:18:12 +01005945 __ movl(Address::displace(field_addr, kX86WordSize), Immediate(High32Bits(v)));
Calin Juravle52c48962014-12-16 17:02:57 +00005946 } else {
Andra Danciucde98192020-09-13 12:32:09 +00005947 __ movl(field_addr, value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00005948 codegen_->MaybeRecordImplicitNullCheck(instruction);
Ulya Trafimovich893e2ed2021-06-10 16:18:12 +01005949 __ movl(Address::displace(field_addr, kX86WordSize), value.AsRegisterPairHigh<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00005950 }
Mark Mendell81489372015-11-04 11:30:41 -05005951 maybe_record_implicit_null_check_done = true;
Calin Juravle52c48962014-12-16 17:02:57 +00005952 break;
5953 }
5954
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005955 case DataType::Type::kFloat32: {
Mark Mendell81489372015-11-04 11:30:41 -05005956 if (value.IsConstant()) {
5957 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
Andra Danciucde98192020-09-13 12:32:09 +00005958 __ movl(field_addr, Immediate(v));
Mark Mendell81489372015-11-04 11:30:41 -05005959 } else {
Andra Danciucde98192020-09-13 12:32:09 +00005960 __ movss(field_addr, value.AsFpuRegister<XmmRegister>());
Mark Mendell81489372015-11-04 11:30:41 -05005961 }
Calin Juravle52c48962014-12-16 17:02:57 +00005962 break;
5963 }
5964
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005965 case DataType::Type::kFloat64: {
Mark Mendell81489372015-11-04 11:30:41 -05005966 if (value.IsConstant()) {
Andra Danciuc992e422020-09-16 08:12:02 +00005967 DCHECK(!is_volatile);
Mark Mendell81489372015-11-04 11:30:41 -05005968 int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant());
Andra Danciucde98192020-09-13 12:32:09 +00005969 __ movl(field_addr, Immediate(Low32Bits(v)));
Mark Mendell81489372015-11-04 11:30:41 -05005970 codegen_->MaybeRecordImplicitNullCheck(instruction);
Ulya Trafimovich893e2ed2021-06-10 16:18:12 +01005971 __ movl(Address::displace(field_addr, kX86WordSize), Immediate(High32Bits(v)));
Mark Mendell81489372015-11-04 11:30:41 -05005972 maybe_record_implicit_null_check_done = true;
5973 } else {
Andra Danciucde98192020-09-13 12:32:09 +00005974 __ movsd(field_addr, value.AsFpuRegister<XmmRegister>());
Mark Mendell81489372015-11-04 11:30:41 -05005975 }
Calin Juravle52c48962014-12-16 17:02:57 +00005976 break;
5977 }
5978
Aart Bik66c158e2018-01-31 12:55:04 -08005979 case DataType::Type::kUint32:
5980 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005981 case DataType::Type::kVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00005982 LOG(FATAL) << "Unreachable type " << field_type;
5983 UNREACHABLE();
5984 }
5985
Mark Mendell81489372015-11-04 11:30:41 -05005986 if (!maybe_record_implicit_null_check_done) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005987 codegen_->MaybeRecordImplicitNullCheck(instruction);
5988 }
5989
Roland Levillain4d027112015-07-01 15:41:14 +01005990 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005991 Register temp = locations->GetTemp(0).AsRegister<Register>();
5992 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005993 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00005994 }
5995
Calin Juravle52c48962014-12-16 17:02:57 +00005996 if (is_volatile) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00005997 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005998 }
5999}
6000
Andra Danciucde98192020-09-13 12:32:09 +00006001void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
6002 const FieldInfo& field_info,
6003 bool value_can_be_null) {
6004 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
6005
6006 LocationSummary* locations = instruction->GetLocations();
6007 Register base = locations->InAt(0).AsRegister<Register>();
6008 bool is_volatile = field_info.IsVolatile();
6009 DataType::Type field_type = field_info.GetFieldType();
6010 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alex Light3a73ffb2021-01-25 14:11:05 +00006011 bool is_predicated =
6012 instruction->IsInstanceFieldSet() && instruction->AsInstanceFieldSet()->GetIsPredicatedSet();
Andra Danciucde98192020-09-13 12:32:09 +00006013
6014 Address field_addr(base, offset);
6015
Alex Light3a73ffb2021-01-25 14:11:05 +00006016 NearLabel pred_is_null;
6017 if (is_predicated) {
6018 __ testl(base, base);
6019 __ j(kEqual, &pred_is_null);
6020 }
6021
Andra Danciucde98192020-09-13 12:32:09 +00006022 HandleFieldSet(instruction,
6023 /* value_index= */ 1,
6024 field_type,
6025 field_addr,
6026 base,
6027 is_volatile,
6028 value_can_be_null);
Alex Light3a73ffb2021-01-25 14:11:05 +00006029
6030 if (is_predicated) {
6031 __ Bind(&pred_is_null);
6032 }
Andra Danciucde98192020-09-13 12:32:09 +00006033}
6034
Calin Juravle52c48962014-12-16 17:02:57 +00006035void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6036 HandleFieldGet(instruction, instruction->GetFieldInfo());
6037}
6038
6039void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6040 HandleFieldGet(instruction, instruction->GetFieldInfo());
6041}
6042
6043void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6044 HandleFieldSet(instruction, instruction->GetFieldInfo());
6045}
6046
6047void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006048 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00006049}
6050
6051void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6052 HandleFieldSet(instruction, instruction->GetFieldInfo());
6053}
6054
6055void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006056 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00006057}
6058
Alex Light3a73ffb2021-01-25 14:11:05 +00006059void LocationsBuilderX86::VisitPredicatedInstanceFieldGet(
6060 HPredicatedInstanceFieldGet* instruction) {
6061 HandleFieldGet(instruction, instruction->GetFieldInfo());
6062}
6063
Calin Juravle52c48962014-12-16 17:02:57 +00006064void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6065 HandleFieldGet(instruction, instruction->GetFieldInfo());
6066}
6067
Alex Light3a73ffb2021-01-25 14:11:05 +00006068void InstructionCodeGeneratorX86::VisitPredicatedInstanceFieldGet(
6069 HPredicatedInstanceFieldGet* instruction) {
6070 NearLabel finish;
6071 LocationSummary* locations = instruction->GetLocations();
6072 Register recv = locations->InAt(1).AsRegister<Register>();
6073 __ testl(recv, recv);
6074 __ j(kZero, &finish);
6075 HandleFieldGet(instruction, instruction->GetFieldInfo());
6076 __ Bind(&finish);
6077}
Calin Juravle52c48962014-12-16 17:02:57 +00006078void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6079 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006080}
6081
Vladimir Marko552a1342017-10-31 10:56:47 +00006082void LocationsBuilderX86::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6083 codegen_->CreateStringBuilderAppendLocations(instruction, Location::RegisterLocation(EAX));
6084}
6085
6086void InstructionCodeGeneratorX86::VisitStringBuilderAppend(HStringBuilderAppend* instruction) {
6087 __ movl(EAX, Immediate(instruction->GetFormat()->GetValue()));
6088 codegen_->InvokeRuntime(kQuickStringBuilderAppend, instruction, instruction->GetDexPc());
6089}
6090
Calin Juravlee460d1d2015-09-29 04:52:17 +01006091void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
6092 HUnresolvedInstanceFieldGet* instruction) {
6093 FieldAccessCallingConventionX86 calling_convention;
6094 codegen_->CreateUnresolvedFieldLocationSummary(
6095 instruction, instruction->GetFieldType(), calling_convention);
6096}
6097
6098void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
6099 HUnresolvedInstanceFieldGet* instruction) {
6100 FieldAccessCallingConventionX86 calling_convention;
6101 codegen_->GenerateUnresolvedFieldAccess(instruction,
6102 instruction->GetFieldType(),
6103 instruction->GetFieldIndex(),
6104 instruction->GetDexPc(),
6105 calling_convention);
6106}
6107
6108void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
6109 HUnresolvedInstanceFieldSet* instruction) {
6110 FieldAccessCallingConventionX86 calling_convention;
6111 codegen_->CreateUnresolvedFieldLocationSummary(
6112 instruction, instruction->GetFieldType(), calling_convention);
6113}
6114
6115void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
6116 HUnresolvedInstanceFieldSet* instruction) {
6117 FieldAccessCallingConventionX86 calling_convention;
6118 codegen_->GenerateUnresolvedFieldAccess(instruction,
6119 instruction->GetFieldType(),
6120 instruction->GetFieldIndex(),
6121 instruction->GetDexPc(),
6122 calling_convention);
6123}
6124
6125void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
6126 HUnresolvedStaticFieldGet* instruction) {
6127 FieldAccessCallingConventionX86 calling_convention;
6128 codegen_->CreateUnresolvedFieldLocationSummary(
6129 instruction, instruction->GetFieldType(), calling_convention);
6130}
6131
6132void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
6133 HUnresolvedStaticFieldGet* instruction) {
6134 FieldAccessCallingConventionX86 calling_convention;
6135 codegen_->GenerateUnresolvedFieldAccess(instruction,
6136 instruction->GetFieldType(),
6137 instruction->GetFieldIndex(),
6138 instruction->GetDexPc(),
6139 calling_convention);
6140}
6141
6142void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
6143 HUnresolvedStaticFieldSet* instruction) {
6144 FieldAccessCallingConventionX86 calling_convention;
6145 codegen_->CreateUnresolvedFieldLocationSummary(
6146 instruction, instruction->GetFieldType(), calling_convention);
6147}
6148
6149void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
6150 HUnresolvedStaticFieldSet* instruction) {
6151 FieldAccessCallingConventionX86 calling_convention;
6152 codegen_->GenerateUnresolvedFieldAccess(instruction,
6153 instruction->GetFieldType(),
6154 instruction->GetFieldIndex(),
6155 instruction->GetDexPc(),
6156 calling_convention);
6157}
6158
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006159void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006160 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
6161 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
6162 ? Location::RequiresRegister()
6163 : Location::Any();
6164 locations->SetInAt(0, loc);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006165}
6166
Calin Juravle2ae48182016-03-16 14:05:09 +00006167void CodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
6168 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006169 return;
6170 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006171 LocationSummary* locations = instruction->GetLocations();
6172 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00006173
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006174 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
Calin Juravle2ae48182016-03-16 14:05:09 +00006175 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006176}
6177
Calin Juravle2ae48182016-03-16 14:05:09 +00006178void CodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01006179 SlowPathCode* slow_path = new (GetScopedAllocator()) NullCheckSlowPathX86(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00006180 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006181
6182 LocationSummary* locations = instruction->GetLocations();
6183 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006184
6185 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04006186 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01006187 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006188 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01006189 } else {
6190 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00006191 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01006192 __ jmp(slow_path->GetEntryLabel());
6193 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006194 }
6195 __ j(kEqual, slow_path->GetEntryLabel());
6196}
6197
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006198void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00006199 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006200}
6201
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006202void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006203 bool object_array_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006204 kEmitCompilerReadBarrier && (instruction->GetType() == DataType::Type::kReference);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006205 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01006206 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
6207 object_array_get_with_read_barrier
6208 ? LocationSummary::kCallOnSlowPath
6209 : LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01006210 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006211 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006212 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006213 locations->SetInAt(0, Location::RequiresRegister());
6214 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006215 if (DataType::IsFloatingPointType(instruction->GetType())) {
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006216 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6217 } else {
Roland Levillain0d5a2812015-11-13 10:07:31 +00006218 // The output overlaps in case of long: we don't want the low move
6219 // to overwrite the array's location. Likewise, in the case of an
6220 // object array get with read barriers enabled, we do not want the
6221 // move to overwrite the array's location, as we need it to emit
6222 // the read barrier.
6223 locations->SetOut(
6224 Location::RequiresRegister(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006225 (instruction->GetType() == DataType::Type::kInt64 || object_array_get_with_read_barrier)
6226 ? Location::kOutputOverlap
6227 : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006228 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006229}
6230
6231void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
6232 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006233 Location obj_loc = locations->InAt(0);
6234 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006235 Location index = locations->InAt(1);
Roland Levillain7c1559a2015-12-15 10:55:36 +00006236 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01006237 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006238
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006239 DataType::Type type = instruction->GetType();
Ulya Trafimovich322eced2021-06-02 15:39:36 +01006240 if (type == DataType::Type::kReference) {
6241 static_assert(
6242 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6243 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6244 // /* HeapReference<Object> */ out =
6245 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
6246 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
6247 // Note that a potential implicit null check is handled in this
6248 // CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier call.
6249 codegen_->GenerateArrayLoadWithBakerReadBarrier(
6250 instruction, out_loc, obj, data_offset, index, /* needs_null_check= */ true);
6251 } else {
Roland Levillain7c1559a2015-12-15 10:55:36 +00006252 Register out = out_loc.AsRegister<Register>();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006253 __ movl(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006254 codegen_->MaybeRecordImplicitNullCheck(instruction);
Ulya Trafimovich322eced2021-06-02 15:39:36 +01006255 // If read barriers are enabled, emit read barriers other than
6256 // Baker's using a slow path (and also unpoison the loaded
6257 // reference, if heap poisoning is enabled).
6258 if (index.IsConstant()) {
6259 uint32_t offset =
6260 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6261 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
6262 } else {
6263 codegen_->MaybeGenerateReadBarrierSlow(
6264 instruction, out_loc, out_loc, obj_loc, data_offset, index);
6265 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006266 }
Ulya Trafimovich322eced2021-06-02 15:39:36 +01006267 } else if (type == DataType::Type::kUint16
6268 && mirror::kUseStringCompression
6269 && instruction->IsStringCharAt()) {
6270 // Branch cases into compressed and uncompressed for each index's type.
6271 Register out = out_loc.AsRegister<Register>();
6272 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
6273 NearLabel done, not_compressed;
6274 __ testb(Address(obj, count_offset), Immediate(1));
Calin Juravle77520bc2015-01-12 18:45:46 +00006275 codegen_->MaybeRecordImplicitNullCheck(instruction);
Ulya Trafimovich322eced2021-06-02 15:39:36 +01006276 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6277 "Expecting 0=compressed, 1=uncompressed");
6278 __ j(kNotZero, &not_compressed);
6279 __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
6280 __ jmp(&done);
6281 __ Bind(&not_compressed);
6282 __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
6283 __ Bind(&done);
6284 } else {
Ulya Trafimovichc8451cb2021-06-02 17:35:16 +01006285 ScaleFactor scale = CodeGenerator::ScaleFactorForType(type);
6286 Address src = CodeGeneratorX86::ArrayAddress(obj, index, scale, data_offset);
Ulya Trafimovich322eced2021-06-02 15:39:36 +01006287 codegen_->LoadFromMemoryNoBarrier(type, out_loc, src, instruction);
Calin Juravle77520bc2015-01-12 18:45:46 +00006288 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006289}
6290
6291void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006292 DataType::Type value_type = instruction->GetComponentType();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006293
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006294 bool needs_write_barrier =
6295 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006296 bool needs_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006297
Vladimir Markoca6fff82017-10-03 14:49:14 +01006298 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Nicolas Geoffray39468442014-09-02 15:17:15 +01006299 instruction,
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006300 needs_type_check ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006301
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006302 bool is_byte_type = DataType::Size(value_type) == 1u;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006303 // We need the inputs to be different than the output in case of long operation.
6304 // In case of a byte operation, the register allocator does not support multiple
6305 // inputs that die at entry with one in a specific register.
6306 locations->SetInAt(0, Location::RequiresRegister());
6307 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6308 if (is_byte_type) {
6309 // Ensure the value is in a byte register.
6310 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006311 } else if (DataType::IsFloatingPointType(value_type)) {
Mark Mendell81489372015-11-04 11:30:41 -05006312 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006313 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006314 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
6315 }
6316 if (needs_write_barrier) {
6317 // Temporary registers for the write barrier.
6318 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
6319 // Ensure the card is in a byte register.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00006320 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006321 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006322}
6323
6324void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
6325 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00006326 Location array_loc = locations->InAt(0);
6327 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006328 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01006329 Location value = locations->InAt(2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006330 DataType::Type value_type = instruction->GetComponentType();
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006331 bool needs_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006332 bool needs_write_barrier =
6333 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006334
6335 switch (value_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006336 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006337 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006338 case DataType::Type::kInt8: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006339 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006340 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_1, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006341 if (value.IsRegister()) {
6342 __ movb(address, value.AsRegister<ByteRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006343 } else {
Nicolas Geoffray78612082017-07-24 14:18:53 +01006344 __ movb(address, Immediate(CodeGenerator::GetInt8ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006345 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006346 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006347 break;
6348 }
6349
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006350 case DataType::Type::kUint16:
6351 case DataType::Type::kInt16: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006352 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006353 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_2, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006354 if (value.IsRegister()) {
6355 __ movw(address, value.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006356 } else {
Nicolas Geoffray78612082017-07-24 14:18:53 +01006357 __ movw(address, Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006358 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006359 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006360 break;
6361 }
6362
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006363 case DataType::Type::kReference: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006364 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006365 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
Roland Levillain0d5a2812015-11-13 10:07:31 +00006366
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006367 if (!value.IsRegister()) {
6368 // Just setting null.
6369 DCHECK(instruction->InputAt(2)->IsNullConstant());
6370 DCHECK(value.IsConstant()) << value;
6371 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00006372 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006373 DCHECK(!needs_write_barrier);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006374 DCHECK(!needs_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006375 break;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006376 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006377
6378 DCHECK(needs_write_barrier);
6379 Register register_value = value.AsRegister<Register>();
Roland Levillain16d9f942016-08-25 17:27:56 +01006380 Location temp_loc = locations->GetTemp(0);
6381 Register temp = temp_loc.AsRegister<Register>();
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006382
6383 bool can_value_be_null = instruction->GetValueCanBeNull();
6384 NearLabel do_store;
6385 if (can_value_be_null) {
6386 __ testl(register_value, register_value);
6387 __ j(kEqual, &do_store);
6388 }
6389
6390 SlowPathCode* slow_path = nullptr;
6391 if (needs_type_check) {
Vladimir Marko0dda8c82019-05-16 12:47:40 +00006392 slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathX86(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006393 codegen_->AddSlowPath(slow_path);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006394
6395 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6396 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6397 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006398
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006399 // Note that when Baker read barriers are enabled, the type
6400 // checks are performed without read barriers. This is fine,
6401 // even in the case where a class object is in the from-space
6402 // after the flip, as a comparison involving such a type would
6403 // not produce a false positive; it may of course produce a
6404 // false negative, in which case we would take the ArraySet
6405 // slow path.
Roland Levillain16d9f942016-08-25 17:27:56 +01006406
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006407 // /* HeapReference<Class> */ temp = array->klass_
6408 __ movl(temp, Address(array, class_offset));
6409 codegen_->MaybeRecordImplicitNullCheck(instruction);
6410 __ MaybeUnpoisonHeapReference(temp);
Roland Levillain16d9f942016-08-25 17:27:56 +01006411
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006412 // /* HeapReference<Class> */ temp = temp->component_type_
6413 __ movl(temp, Address(temp, component_offset));
6414 // If heap poisoning is enabled, no need to unpoison `temp`
6415 // nor the object reference in `register_value->klass`, as
6416 // we are comparing two poisoned references.
6417 __ cmpl(temp, Address(register_value, class_offset));
Roland Levillain16d9f942016-08-25 17:27:56 +01006418
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006419 if (instruction->StaticTypeOfArrayIsObjectArray()) {
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006420 NearLabel do_put;
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006421 __ j(kEqual, &do_put);
6422 // If heap poisoning is enabled, the `temp` reference has
6423 // not been unpoisoned yet; unpoison it now.
Roland Levillain0d5a2812015-11-13 10:07:31 +00006424 __ MaybeUnpoisonHeapReference(temp);
6425
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006426 // If heap poisoning is enabled, no need to unpoison the
6427 // heap reference loaded below, as it is only used for a
6428 // comparison with null.
6429 __ cmpl(Address(temp, super_offset), Immediate(0));
6430 __ j(kNotEqual, slow_path->GetEntryLabel());
6431 __ Bind(&do_put);
6432 } else {
6433 __ j(kNotEqual, slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006434 }
Vladimir Marko0dda8c82019-05-16 12:47:40 +00006435 }
6436
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006437 Register card = locations->GetTemp(1).AsRegister<Register>();
6438 codegen_->MarkGCCard(
6439 temp, card, array, value.AsRegister<Register>(), /* value_can_be_null= */ false);
6440
6441 if (can_value_be_null) {
6442 DCHECK(do_store.IsLinked());
6443 __ Bind(&do_store);
6444 }
6445
6446 Register source = register_value;
Vladimir Marko0dda8c82019-05-16 12:47:40 +00006447 if (kPoisonHeapReferences) {
6448 __ movl(temp, register_value);
6449 __ PoisonHeapReference(temp);
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006450 source = temp;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006451 }
6452
Vladimir Marko8fa839c2019-05-16 12:50:47 +00006453 __ movl(address, source);
6454
6455 if (can_value_be_null || !needs_type_check) {
6456 codegen_->MaybeRecordImplicitNullCheck(instruction);
6457 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006458
Vladimir Marko0dda8c82019-05-16 12:47:40 +00006459 if (slow_path != nullptr) {
6460 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006461 }
6462
6463 break;
6464 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00006465
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006466 case DataType::Type::kInt32: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006467 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006468 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006469 if (value.IsRegister()) {
6470 __ movl(address, value.AsRegister<Register>());
6471 } else {
6472 DCHECK(value.IsConstant()) << value;
6473 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
6474 __ movl(address, Immediate(v));
6475 }
6476 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006477 break;
6478 }
6479
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006480 case DataType::Type::kInt64: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006481 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006482 if (value.IsRegisterPair()) {
6483 __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset),
6484 value.AsRegisterPairLow<Register>());
6485 codegen_->MaybeRecordImplicitNullCheck(instruction);
6486 __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset + kX86WordSize),
6487 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006488 } else {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006489 DCHECK(value.IsConstant());
6490 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
6491 __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset),
6492 Immediate(Low32Bits(val)));
6493 codegen_->MaybeRecordImplicitNullCheck(instruction);
6494 __ movl(CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, data_offset + kX86WordSize),
6495 Immediate(High32Bits(val)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006496 }
6497 break;
6498 }
6499
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006500 case DataType::Type::kFloat32: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006501 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006502 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_4, offset);
Mark Mendell81489372015-11-04 11:30:41 -05006503 if (value.IsFpuRegister()) {
6504 __ movss(address, value.AsFpuRegister<XmmRegister>());
6505 } else {
6506 DCHECK(value.IsConstant());
6507 int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue());
6508 __ movl(address, Immediate(v));
6509 }
6510 codegen_->MaybeRecordImplicitNullCheck(instruction);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006511 break;
6512 }
6513
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006514 case DataType::Type::kFloat64: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006515 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006516 Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, offset);
Mark Mendell81489372015-11-04 11:30:41 -05006517 if (value.IsFpuRegister()) {
6518 __ movsd(address, value.AsFpuRegister<XmmRegister>());
6519 } else {
6520 DCHECK(value.IsConstant());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006521 Address address_hi =
6522 CodeGeneratorX86::ArrayAddress(array, index, TIMES_8, offset + kX86WordSize);
Mark Mendell81489372015-11-04 11:30:41 -05006523 int64_t v = bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue());
6524 __ movl(address, Immediate(Low32Bits(v)));
6525 codegen_->MaybeRecordImplicitNullCheck(instruction);
6526 __ movl(address_hi, Immediate(High32Bits(v)));
6527 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05006528 break;
6529 }
6530
Aart Bik66c158e2018-01-31 12:55:04 -08006531 case DataType::Type::kUint32:
6532 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006533 case DataType::Type::kVoid:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006534 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07006535 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006536 }
6537}
6538
6539void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006540 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006541 locations->SetInAt(0, Location::RequiresRegister());
Mark Mendellee8d9712016-07-12 11:13:15 -04006542 if (!instruction->IsEmittedAtUseSite()) {
6543 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6544 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006545}
6546
6547void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
Mark Mendellee8d9712016-07-12 11:13:15 -04006548 if (instruction->IsEmittedAtUseSite()) {
6549 return;
6550 }
6551
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006552 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01006553 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00006554 Register obj = locations->InAt(0).AsRegister<Register>();
6555 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006556 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00006557 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo4877b792016-09-08 19:49:13 -07006558 // Mask out most significant bit in case the array is String's array of char.
6559 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006560 __ shrl(out, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07006561 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006562}
6563
6564void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006565 RegisterSet caller_saves = RegisterSet::Empty();
6566 InvokeRuntimeCallingConvention calling_convention;
6567 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6568 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6569 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Mark Mendellf60c90b2015-03-04 15:12:59 -05006570 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendellee8d9712016-07-12 11:13:15 -04006571 HInstruction* length = instruction->InputAt(1);
6572 if (!length->IsEmittedAtUseSite()) {
6573 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6574 }
jessicahandojo4877b792016-09-08 19:49:13 -07006575 // Need register to see array's length.
6576 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
6577 locations->AddTemp(Location::RequiresRegister());
6578 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006579}
6580
6581void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
jessicahandojo4877b792016-09-08 19:49:13 -07006582 const bool is_string_compressed_char_at =
6583 mirror::kUseStringCompression && instruction->IsStringCharAt();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006584 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05006585 Location index_loc = locations->InAt(0);
6586 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07006587 SlowPathCode* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01006588 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006589
Mark Mendell99dbd682015-04-22 16:18:52 -04006590 if (length_loc.IsConstant()) {
6591 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
6592 if (index_loc.IsConstant()) {
6593 // BCE will remove the bounds check if we are guarenteed to pass.
6594 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
6595 if (index < 0 || index >= length) {
6596 codegen_->AddSlowPath(slow_path);
6597 __ jmp(slow_path->GetEntryLabel());
6598 } else {
6599 // Some optimization after BCE may have generated this, and we should not
6600 // generate a bounds check if it is a valid range.
6601 }
6602 return;
6603 }
6604
6605 // We have to reverse the jump condition because the length is the constant.
6606 Register index_reg = index_loc.AsRegister<Register>();
6607 __ cmpl(index_reg, Immediate(length));
6608 codegen_->AddSlowPath(slow_path);
6609 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05006610 } else {
Mark Mendellee8d9712016-07-12 11:13:15 -04006611 HInstruction* array_length = instruction->InputAt(1);
6612 if (array_length->IsEmittedAtUseSite()) {
6613 // Address the length field in the array.
6614 DCHECK(array_length->IsArrayLength());
6615 uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
6616 Location array_loc = array_length->GetLocations()->InAt(0);
6617 Address array_len(array_loc.AsRegister<Register>(), len_offset);
jessicahandojo4877b792016-09-08 19:49:13 -07006618 if (is_string_compressed_char_at) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006619 // TODO: if index_loc.IsConstant(), compare twice the index (to compensate for
6620 // the string compression flag) with the in-memory length and avoid the temporary.
jessicahandojo4877b792016-09-08 19:49:13 -07006621 Register length_reg = locations->GetTemp(0).AsRegister<Register>();
6622 __ movl(length_reg, array_len);
6623 codegen_->MaybeRecordImplicitNullCheck(array_length);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006624 __ shrl(length_reg, Immediate(1));
jessicahandojo4877b792016-09-08 19:49:13 -07006625 codegen_->GenerateIntCompare(length_reg, index_loc);
Mark Mendellee8d9712016-07-12 11:13:15 -04006626 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07006627 // Checking bounds for general case:
6628 // Array of char or string's array with feature compression off.
6629 if (index_loc.IsConstant()) {
6630 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
6631 __ cmpl(array_len, Immediate(value));
6632 } else {
6633 __ cmpl(array_len, index_loc.AsRegister<Register>());
6634 }
6635 codegen_->MaybeRecordImplicitNullCheck(array_length);
Mark Mendellee8d9712016-07-12 11:13:15 -04006636 }
Mark Mendell99dbd682015-04-22 16:18:52 -04006637 } else {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01006638 codegen_->GenerateIntCompare(length_loc, index_loc);
Mark Mendell99dbd682015-04-22 16:18:52 -04006639 }
6640 codegen_->AddSlowPath(slow_path);
6641 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05006642 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006643}
6644
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006645void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006646 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006647}
6648
6649void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Vladimir Markobea75ff2017-10-11 20:39:54 +01006650 if (instruction->GetNext()->IsSuspendCheck() &&
6651 instruction->GetBlock()->GetLoopInformation() != nullptr) {
6652 HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
6653 // The back edge will generate the suspend check.
6654 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
6655 }
6656
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006657 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6658}
6659
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006660void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006661 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
6662 instruction, LocationSummary::kCallOnSlowPath);
Aart Bikb13c65b2017-03-21 20:14:07 -07006663 // In suspend check slow path, usually there are no caller-save registers at all.
6664 // If SIMD instructions are present, however, we force spilling all live SIMD
6665 // registers in full width (since the runtime only saves/restores lower part).
Aart Bik5576f372017-03-23 16:17:37 -07006666 locations->SetCustomSlowPathCallerSaves(
6667 GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006668}
6669
6670void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006671 HBasicBlock* block = instruction->GetBlock();
6672 if (block->GetLoopInformation() != nullptr) {
6673 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6674 // The back edge will generate the suspend check.
6675 return;
6676 }
6677 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6678 // The goto will generate the suspend check.
6679 return;
6680 }
6681 GenerateSuspendCheck(instruction, nullptr);
6682}
6683
6684void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
6685 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006686 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006687 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
6688 if (slow_path == nullptr) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01006689 slow_path =
6690 new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006691 instruction->SetSlowPath(slow_path);
6692 codegen_->AddSlowPath(slow_path);
6693 if (successor != nullptr) {
6694 DCHECK(successor->IsLoopHeader());
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006695 }
6696 } else {
6697 DCHECK_EQ(slow_path->GetSuccessor(), successor);
6698 }
6699
Andreas Gampe542451c2016-07-26 09:02:02 -07006700 __ fs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>().Int32Value()),
Roland Levillain7c1559a2015-12-15 10:55:36 +00006701 Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006702 if (successor == nullptr) {
6703 __ j(kNotEqual, slow_path->GetEntryLabel());
6704 __ Bind(slow_path->GetReturnLabel());
6705 } else {
6706 __ j(kEqual, codegen_->GetLabelOf(successor));
6707 __ jmp(slow_path->GetEntryLabel());
6708 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006709}
6710
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006711X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
6712 return codegen_->GetAssembler();
6713}
6714
Aart Bikcfe50bb2017-12-12 14:54:12 -08006715void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src, int number_of_words) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006716 ScratchRegisterScope ensure_scratch(
6717 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
6718 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
6719 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05006720
Aart Bikcfe50bb2017-12-12 14:54:12 -08006721 // Now that temp register is available (possibly spilled), move blocks of memory.
6722 for (int i = 0; i < number_of_words; i++) {
6723 __ movl(temp_reg, Address(ESP, src + stack_offset));
6724 __ movl(Address(ESP, dst + stack_offset), temp_reg);
6725 stack_offset += kX86WordSize;
6726 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006727}
6728
6729void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006730 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006731 Location source = move->GetSource();
6732 Location destination = move->GetDestination();
6733
6734 if (source.IsRegister()) {
6735 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006736 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006737 } else if (destination.IsFpuRegister()) {
6738 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006739 } else {
6740 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006741 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006742 }
David Brazdil74eb1b22015-12-14 11:44:01 +00006743 } else if (source.IsRegisterPair()) {
Vladimir Marko86c87522020-05-11 16:55:55 +01006744 if (destination.IsRegisterPair()) {
6745 __ movl(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6746 DCHECK_NE(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
6747 __ movl(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
6748 } else if (destination.IsFpuRegister()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006749 size_t elem_size = DataType::Size(DataType::Type::kInt32);
Vladimir Markodec78172020-06-19 15:31:23 +01006750 // Push the 2 source registers to the stack.
Vladimir Marko86c87522020-05-11 16:55:55 +01006751 __ pushl(source.AsRegisterPairHigh<Register>());
6752 __ cfi().AdjustCFAOffset(elem_size);
6753 __ pushl(source.AsRegisterPairLow<Register>());
6754 __ cfi().AdjustCFAOffset(elem_size);
6755 // Load the destination register.
David Brazdil74eb1b22015-12-14 11:44:01 +00006756 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
6757 // And remove the temporary stack space we allocated.
Vladimir Markodec78172020-06-19 15:31:23 +01006758 codegen_->DecreaseFrame(2 * elem_size);
Vladimir Marko86c87522020-05-11 16:55:55 +01006759 } else {
6760 DCHECK(destination.IsDoubleStackSlot());
6761 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
6762 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
6763 source.AsRegisterPairHigh<Register>());
6764 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05006765 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006766 if (destination.IsRegister()) {
6767 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
6768 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05006769 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006770 } else if (destination.IsRegisterPair()) {
Vladimir Marko86c87522020-05-11 16:55:55 +01006771 size_t elem_size = DataType::Size(DataType::Type::kInt32);
6772 // Create stack space for 2 elements.
Vladimir Markodec78172020-06-19 15:31:23 +01006773 codegen_->IncreaseFrame(2 * elem_size);
Vladimir Marko86c87522020-05-11 16:55:55 +01006774 // Store the source register.
6775 __ movsd(Address(ESP, 0), source.AsFpuRegister<XmmRegister>());
6776 // And pop the values into destination registers.
6777 __ popl(destination.AsRegisterPairLow<Register>());
6778 __ cfi().AdjustCFAOffset(-elem_size);
6779 __ popl(destination.AsRegisterPairHigh<Register>());
6780 __ cfi().AdjustCFAOffset(-elem_size);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006781 } else if (destination.IsStackSlot()) {
6782 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07006783 } else if (destination.IsDoubleStackSlot()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05006784 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Aart Bik5576f372017-03-23 16:17:37 -07006785 } else {
6786 DCHECK(destination.IsSIMDStackSlot());
6787 __ movups(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05006788 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006789 } else if (source.IsStackSlot()) {
6790 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006791 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05006792 } else if (destination.IsFpuRegister()) {
6793 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006794 } else {
6795 DCHECK(destination.IsStackSlot());
Aart Bikcfe50bb2017-12-12 14:54:12 -08006796 MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006797 }
6798 } else if (source.IsDoubleStackSlot()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006799 if (destination.IsRegisterPair()) {
6800 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
6801 __ movl(destination.AsRegisterPairHigh<Register>(),
6802 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
6803 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05006804 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
6805 } else {
6806 DCHECK(destination.IsDoubleStackSlot()) << destination;
Aart Bikcfe50bb2017-12-12 14:54:12 -08006807 MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006808 }
Aart Bik5576f372017-03-23 16:17:37 -07006809 } else if (source.IsSIMDStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08006810 if (destination.IsFpuRegister()) {
6811 __ movups(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
6812 } else {
6813 DCHECK(destination.IsSIMDStackSlot());
6814 MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
6815 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006816 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05006817 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00006818 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05006819 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006820 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05006821 if (value == 0) {
6822 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
6823 } else {
6824 __ movl(destination.AsRegister<Register>(), Immediate(value));
6825 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05006826 } else {
6827 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05006828 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05006829 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006830 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006831 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00006832 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006833 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006834 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006835 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
6836 if (value == 0) {
6837 // Easy handling of 0.0.
6838 __ xorps(dest, dest);
6839 } else {
6840 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006841 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
6842 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
6843 __ movl(temp, Immediate(value));
6844 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04006845 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05006846 } else {
6847 DCHECK(destination.IsStackSlot()) << destination;
6848 __ movl(Address(ESP, destination.GetStackIndex()), imm);
6849 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006850 } else if (constant->IsLongConstant()) {
6851 int64_t value = constant->AsLongConstant()->GetValue();
6852 int32_t low_value = Low32Bits(value);
6853 int32_t high_value = High32Bits(value);
6854 Immediate low(low_value);
6855 Immediate high(high_value);
6856 if (destination.IsDoubleStackSlot()) {
6857 __ movl(Address(ESP, destination.GetStackIndex()), low);
6858 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
6859 } else {
6860 __ movl(destination.AsRegisterPairLow<Register>(), low);
6861 __ movl(destination.AsRegisterPairHigh<Register>(), high);
6862 }
6863 } else {
6864 DCHECK(constant->IsDoubleConstant());
6865 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00006866 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006867 int32_t low_value = Low32Bits(value);
6868 int32_t high_value = High32Bits(value);
6869 Immediate low(low_value);
6870 Immediate high(high_value);
6871 if (destination.IsFpuRegister()) {
6872 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
6873 if (value == 0) {
6874 // Easy handling of 0.0.
6875 __ xorpd(dest, dest);
6876 } else {
6877 __ pushl(high);
Vladimir Marko86c87522020-05-11 16:55:55 +01006878 __ cfi().AdjustCFAOffset(4);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006879 __ pushl(low);
Vladimir Marko86c87522020-05-11 16:55:55 +01006880 __ cfi().AdjustCFAOffset(4);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006881 __ movsd(dest, Address(ESP, 0));
Vladimir Markodec78172020-06-19 15:31:23 +01006882 codegen_->DecreaseFrame(8);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006883 }
6884 } else {
6885 DCHECK(destination.IsDoubleStackSlot()) << destination;
6886 __ movl(Address(ESP, destination.GetStackIndex()), low);
6887 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
6888 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006889 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006890 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00006891 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006892 }
6893}
6894
Mark Mendella5c19ce2015-04-01 12:51:05 -04006895void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006896 Register suggested_scratch = reg == EAX ? EBX : EAX;
6897 ScratchRegisterScope ensure_scratch(
6898 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
6899
6900 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
6901 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
6902 __ movl(Address(ESP, mem + stack_offset), reg);
6903 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006904}
6905
Mark Mendell7c8d0092015-01-26 11:21:33 -05006906void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006907 ScratchRegisterScope ensure_scratch(
6908 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
6909
6910 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
6911 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
6912 __ movl(temp_reg, Address(ESP, mem + stack_offset));
6913 __ movss(Address(ESP, mem + stack_offset), reg);
6914 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006915}
6916
Aart Bikcfe50bb2017-12-12 14:54:12 -08006917void ParallelMoveResolverX86::Exchange128(XmmRegister reg, int mem) {
6918 size_t extra_slot = 4 * kX86WordSize;
Vladimir Markodec78172020-06-19 15:31:23 +01006919 codegen_->IncreaseFrame(extra_slot);
Aart Bikcfe50bb2017-12-12 14:54:12 -08006920 __ movups(Address(ESP, 0), XmmRegister(reg));
6921 ExchangeMemory(0, mem + extra_slot, 4);
6922 __ movups(XmmRegister(reg), Address(ESP, 0));
Vladimir Markodec78172020-06-19 15:31:23 +01006923 codegen_->DecreaseFrame(extra_slot);
Aart Bikcfe50bb2017-12-12 14:54:12 -08006924}
6925
6926void ParallelMoveResolverX86::ExchangeMemory(int mem1, int mem2, int number_of_words) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006927 ScratchRegisterScope ensure_scratch1(
6928 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006929
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006930 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
6931 ScratchRegisterScope ensure_scratch2(
6932 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006933
Guillaume Sancheze14590b2015-04-15 18:57:27 +00006934 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
6935 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
Aart Bikcfe50bb2017-12-12 14:54:12 -08006936
6937 // Now that temp registers are available (possibly spilled), exchange blocks of memory.
6938 for (int i = 0; i < number_of_words; i++) {
6939 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
6940 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
6941 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
6942 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
6943 stack_offset += kX86WordSize;
6944 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006945}
6946
6947void ParallelMoveResolverX86::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006948 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006949 Location source = move->GetSource();
6950 Location destination = move->GetDestination();
6951
6952 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04006953 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
6954 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
6955 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
6956 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
6957 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006958 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006959 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006960 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006961 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01006962 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08006963 ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
Mark Mendell7c8d0092015-01-26 11:21:33 -05006964 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
6965 // Use XOR Swap algorithm to avoid a temporary.
6966 DCHECK_NE(source.reg(), destination.reg());
6967 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
6968 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
6969 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
6970 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
6971 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
6972 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
6973 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00006974 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
6975 // Take advantage of the 16 bytes in the XMM register.
6976 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
6977 Address stack(ESP, destination.GetStackIndex());
6978 // Load the double into the high doubleword.
6979 __ movhpd(reg, stack);
6980
6981 // Store the low double into the destination.
6982 __ movsd(stack, reg);
6983
6984 // Move the high double to the low double.
6985 __ psrldq(reg, Immediate(8));
6986 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
6987 // Take advantage of the 16 bytes in the XMM register.
6988 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
6989 Address stack(ESP, source.GetStackIndex());
6990 // Load the double into the high doubleword.
6991 __ movhpd(reg, stack);
6992
6993 // Store the low double into the destination.
6994 __ movsd(stack, reg);
6995
6996 // Move the high double to the low double.
6997 __ psrldq(reg, Immediate(8));
6998 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
Aart Bikcfe50bb2017-12-12 14:54:12 -08006999 ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
7000 } else if (source.IsSIMDStackSlot() && destination.IsSIMDStackSlot()) {
7001 ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
7002 } else if (source.IsFpuRegister() && destination.IsSIMDStackSlot()) {
7003 Exchange128(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
7004 } else if (destination.IsFpuRegister() && source.IsSIMDStackSlot()) {
7005 Exchange128(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01007006 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05007007 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01007008 }
7009}
7010
7011void ParallelMoveResolverX86::SpillScratch(int reg) {
7012 __ pushl(static_cast<Register>(reg));
7013}
7014
7015void ParallelMoveResolverX86::RestoreScratch(int reg) {
7016 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01007017}
7018
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007019HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind(
7020 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007021 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007022 case HLoadClass::LoadKind::kInvalid:
7023 LOG(FATAL) << "UNREACHABLE";
7024 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007025 case HLoadClass::LoadKind::kReferrersClass:
7026 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007027 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007028 case HLoadClass::LoadKind::kBootImageRelRo:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007029 case HLoadClass::LoadKind::kBssEntry:
Vladimir Marko8f63f102020-09-28 12:10:28 +01007030 case HLoadClass::LoadKind::kBssEntryPublic:
7031 case HLoadClass::LoadKind::kBssEntryPackage:
Vladimir Marko695348f2020-05-19 14:42:02 +01007032 DCHECK(!GetCompilerOptions().IsJitCompiler());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007033 break;
Vladimir Marko8e524ad2018-07-13 10:27:43 +01007034 case HLoadClass::LoadKind::kJitBootImageAddress:
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007035 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko695348f2020-05-19 14:42:02 +01007036 DCHECK(GetCompilerOptions().IsJitCompiler());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007037 break;
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007038 case HLoadClass::LoadKind::kRuntimeCall:
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007039 break;
7040 }
7041 return desired_class_load_kind;
7042}
7043
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007044void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00007045 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007046 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007047 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00007048 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007049 cls,
7050 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00007051 Location::RegisterLocation(EAX));
Vladimir Markoea4c1262017-02-06 19:59:33 +00007052 DCHECK_EQ(calling_convention.GetRegisterAt(0), EAX);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007053 return;
7054 }
Vladimir Marko8f63f102020-09-28 12:10:28 +01007055 DCHECK_EQ(cls->NeedsAccessCheck(),
7056 load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
7057 load_kind == HLoadClass::LoadKind::kBssEntryPackage);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007058
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007059 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
7060 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007061 ? LocationSummary::kCallOnSlowPath
7062 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01007063 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007064 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007065 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007066 }
7067
Vladimir Marko8f63f102020-09-28 12:10:28 +01007068 if (load_kind == HLoadClass::LoadKind::kReferrersClass || cls->HasPcRelativeLoadKind()) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007069 locations->SetInAt(0, Location::RequiresRegister());
7070 }
7071 locations->SetOut(Location::RequiresRegister());
Vladimir Marko8f63f102020-09-28 12:10:28 +01007072 if (call_kind == LocationSummary::kCallOnSlowPath && cls->HasPcRelativeLoadKind()) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007073 if (!kUseReadBarrier || kUseBakerReadBarrier) {
7074 // Rely on the type resolution and/or initialization to save everything.
Vladimir Marko3232dbb2018-07-25 15:42:46 +01007075 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007076 } else {
7077 // For non-Baker read barrier we have a temp-clobbering call.
7078 }
7079 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007080}
7081
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007082Label* CodeGeneratorX86::NewJitRootClassPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01007083 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007084 Handle<mirror::Class> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01007085 ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007086 // Add a patch entry and return the label.
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007087 jit_class_patches_.emplace_back(&dex_file, type_index.index_);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007088 PatchInfo<Label>* info = &jit_class_patches_.back();
7089 return &info->label;
7090}
7091
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007092// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7093// move.
7094void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00007095 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007096 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00007097 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01007098 return;
7099 }
Vladimir Marko8f63f102020-09-28 12:10:28 +01007100 DCHECK_EQ(cls->NeedsAccessCheck(),
7101 load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
7102 load_kind == HLoadClass::LoadKind::kBssEntryPackage);
Calin Juravle580b6092015-10-06 17:35:58 +01007103
Vladimir Marko41559982017-01-06 14:04:23 +00007104 LocationSummary* locations = cls->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007105 Location out_loc = locations->Out();
7106 Register out = out_loc.AsRegister<Register>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007107
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007108 bool generate_null_check = false;
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007109 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
7110 ? kWithoutReadBarrier
7111 : kCompilerReadBarrierOption;
Vladimir Marko41559982017-01-06 14:04:23 +00007112 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007113 case HLoadClass::LoadKind::kReferrersClass: {
7114 DCHECK(!cls->CanCallRuntime());
7115 DCHECK(!cls->MustGenerateClinitCheck());
7116 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7117 Register current_method = locations->InAt(0).AsRegister<Register>();
7118 GenerateGcRootFieldLoad(
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007119 cls,
7120 out_loc,
7121 Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
Andreas Gampe3db70682018-12-26 15:12:03 -08007122 /* fixup_label= */ nullptr,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007123 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007124 break;
7125 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007126 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko44ca0752019-07-29 10:18:25 +01007127 DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
7128 codegen_->GetCompilerOptions().IsBootImageExtension());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007129 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007130 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007131 __ leal(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007132 codegen_->RecordBootImageTypePatch(cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007133 break;
7134 }
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007135 case HLoadClass::LoadKind::kBootImageRelRo: {
Vladimir Marko94ec2db2017-09-06 17:21:03 +01007136 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7137 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007138 __ movl(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007139 codegen_->RecordBootImageRelRoPatch(cls->InputAt(0)->AsX86ComputeBaseMethodAddress(),
Vladimir Markode91ca92020-10-27 13:41:40 +00007140 CodeGenerator::GetBootImageOffset(cls));
Vladimir Marko94ec2db2017-09-06 17:21:03 +01007141 break;
7142 }
Vladimir Marko8f63f102020-09-28 12:10:28 +01007143 case HLoadClass::LoadKind::kBssEntry:
7144 case HLoadClass::LoadKind::kBssEntryPublic:
7145 case HLoadClass::LoadKind::kBssEntryPackage: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007146 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007147 Address address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007148 Label* fixup_label = codegen_->NewTypeBssEntryPatch(cls);
7149 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
Vladimir Markod5fd5c32019-07-02 14:46:32 +01007150 // No need for memory fence, thanks to the x86 memory model.
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007151 generate_null_check = true;
7152 break;
7153 }
Vladimir Marko8e524ad2018-07-13 10:27:43 +01007154 case HLoadClass::LoadKind::kJitBootImageAddress: {
7155 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
7156 uint32_t address = reinterpret_cast32<uint32_t>(cls->GetClass().Get());
7157 DCHECK_NE(address, 0u);
7158 __ movl(out, Immediate(address));
7159 break;
7160 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007161 case HLoadClass::LoadKind::kJitTableAddress: {
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007162 Address address = Address::Absolute(CodeGeneratorX86::kPlaceholder32BitOffset);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007163 Label* fixup_label = codegen_->NewJitRootClassPatch(
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007164 cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007165 // /* GcRoot<mirror::Class> */ out = *address
Vladimir Markoea4c1262017-02-06 19:59:33 +00007166 GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007167 break;
7168 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007169 case HLoadClass::LoadKind::kRuntimeCall:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007170 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00007171 LOG(FATAL) << "UNREACHABLE";
7172 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007173 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007174
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007175 if (generate_null_check || cls->MustGenerateClinitCheck()) {
7176 DCHECK(cls->CanCallRuntime());
Vladimir Markoa9f303c2018-07-20 16:43:56 +01007177 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86(cls, cls);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007178 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00007179
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007180 if (generate_null_check) {
7181 __ testl(out, out);
7182 __ j(kEqual, slow_path->GetEntryLabel());
7183 }
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00007184
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007185 if (cls->MustGenerateClinitCheck()) {
7186 GenerateClassInitializationCheck(slow_path, out);
7187 } else {
7188 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007189 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007190 }
7191}
7192
Orion Hodsondbaa5c72018-05-10 08:22:46 +01007193void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
7194 InvokeRuntimeCallingConvention calling_convention;
7195 Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
7196 CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
7197}
7198
7199void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
7200 codegen_->GenerateLoadMethodHandleRuntimeCall(load);
7201}
7202
Orion Hodson18259d72018-04-12 11:18:23 +01007203void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
7204 InvokeRuntimeCallingConvention calling_convention;
7205 Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
7206 CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
7207}
7208
7209void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) {
7210 codegen_->GenerateLoadMethodTypeRuntimeCall(load);
7211}
7212
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007213void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
7214 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01007215 new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007216 locations->SetInAt(0, Location::RequiresRegister());
7217 if (check->HasUses()) {
7218 locations->SetOut(Location::SameAsFirstInput());
7219 }
Vladimir Marko3232dbb2018-07-25 15:42:46 +01007220 // Rely on the type initialization to save everything we need.
7221 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007222}
7223
7224void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007225 // We assume the class to not be null.
Vladimir Markoa9f303c2018-07-20 16:43:56 +01007226 SlowPathCode* slow_path =
7227 new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86(check->GetLoadClass(), check);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007228 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00007229 GenerateClassInitializationCheck(slow_path,
7230 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007231}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007232
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007233void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07007234 SlowPathCode* slow_path, Register class_reg) {
Vladimir Markodc682aa2018-01-04 18:42:57 +00007235 constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
7236 const size_t status_byte_offset =
7237 mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
Vladimir Markobf121912019-06-04 13:49:05 +01007238 constexpr uint32_t shifted_visibly_initialized_value =
7239 enum_cast<uint32_t>(ClassStatus::kVisiblyInitialized) << (status_lsb_position % kBitsPerByte);
Vladimir Markodc682aa2018-01-04 18:42:57 +00007240
Vladimir Markobf121912019-06-04 13:49:05 +01007241 __ cmpb(Address(class_reg, status_byte_offset), Immediate(shifted_visibly_initialized_value));
Vladimir Marko2c64a832018-01-04 11:31:56 +00007242 __ j(kBelow, slow_path->GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007243 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007244}
7245
Vladimir Marko175e7862018-03-27 09:03:13 +00007246void InstructionCodeGeneratorX86::GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
7247 Register temp) {
7248 uint32_t path_to_root = check->GetBitstringPathToRoot();
7249 uint32_t mask = check->GetBitstringMask();
7250 DCHECK(IsPowerOfTwo(mask + 1));
7251 size_t mask_bits = WhichPowerOf2(mask + 1);
7252
7253 if (mask_bits == 16u) {
7254 // Compare the bitstring in memory.
7255 __ cmpw(Address(temp, mirror::Class::StatusOffset()), Immediate(path_to_root));
7256 } else {
7257 // /* uint32_t */ temp = temp->status_
7258 __ movl(temp, Address(temp, mirror::Class::StatusOffset()));
7259 // Compare the bitstring bits using SUB.
7260 __ subl(temp, Immediate(path_to_root));
7261 // Shift out bits that do not contribute to the comparison.
7262 __ shll(temp, Immediate(32u - mask_bits));
7263 }
7264}
7265
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007266HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
7267 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007268 switch (desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007269 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007270 case HLoadString::LoadKind::kBootImageRelRo:
Vladimir Markoaad75c62016-10-03 08:46:48 +00007271 case HLoadString::LoadKind::kBssEntry:
Vladimir Marko695348f2020-05-19 14:42:02 +01007272 DCHECK(!GetCompilerOptions().IsJitCompiler());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007273 break;
Vladimir Marko8e524ad2018-07-13 10:27:43 +01007274 case HLoadString::LoadKind::kJitBootImageAddress:
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007275 case HLoadString::LoadKind::kJitTableAddress:
Vladimir Marko695348f2020-05-19 14:42:02 +01007276 DCHECK(GetCompilerOptions().IsJitCompiler());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007277 break;
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007278 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007279 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007280 }
7281 return desired_string_load_kind;
7282}
7283
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007284void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007285 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Vladimir Markoca6fff82017-10-03 14:49:14 +01007286 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007287 HLoadString::LoadKind load_kind = load->GetLoadKind();
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007288 if (load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative ||
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007289 load_kind == HLoadString::LoadKind::kBootImageRelRo ||
Vladimir Markoaad75c62016-10-03 08:46:48 +00007290 load_kind == HLoadString::LoadKind::kBssEntry) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007291 locations->SetInAt(0, Location::RequiresRegister());
7292 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007293 if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
Christina Wadsworth175d09b2016-08-31 16:26:01 -07007294 locations->SetOut(Location::RegisterLocation(EAX));
7295 } else {
7296 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007297 if (load_kind == HLoadString::LoadKind::kBssEntry) {
7298 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007299 // Rely on the pResolveString to save everything.
Vladimir Marko3232dbb2018-07-25 15:42:46 +01007300 locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007301 } else {
7302 // For non-Baker read barrier we have a temp-clobbering call.
7303 }
7304 }
Christina Wadsworth175d09b2016-08-31 16:26:01 -07007305 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007306}
7307
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007308Label* CodeGeneratorX86::NewJitRootStringPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01007309 dex::StringIndex string_index,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007310 Handle<mirror::String> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01007311 ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007312 // Add a patch entry and return the label.
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007313 jit_string_patches_.emplace_back(&dex_file, string_index.index_);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007314 PatchInfo<Label>* info = &jit_string_patches_.back();
7315 return &info->label;
7316}
7317
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007318// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7319// move.
7320void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01007321 LocationSummary* locations = load->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007322 Location out_loc = locations->Out();
7323 Register out = out_loc.AsRegister<Register>();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007324
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007325 switch (load->GetLoadKind()) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007326 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko44ca0752019-07-29 10:18:25 +01007327 DCHECK(codegen_->GetCompilerOptions().IsBootImage() ||
7328 codegen_->GetCompilerOptions().IsBootImageExtension());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007329 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007330 __ leal(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007331 codegen_->RecordBootImageStringPatch(load);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01007332 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007333 }
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007334 case HLoadString::LoadKind::kBootImageRelRo: {
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01007335 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7336 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007337 __ movl(out, Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset));
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007338 codegen_->RecordBootImageRelRoPatch(load->InputAt(0)->AsX86ComputeBaseMethodAddress(),
Vladimir Markode91ca92020-10-27 13:41:40 +00007339 CodeGenerator::GetBootImageOffset(load));
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01007340 return;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007341 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007342 case HLoadString::LoadKind::kBssEntry: {
7343 Register method_address = locations->InAt(0).AsRegister<Register>();
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007344 Address address = Address(method_address, CodeGeneratorX86::kPlaceholder32BitOffset);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007345 Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007346 // /* GcRoot<mirror::String> */ out = *address /* PC-relative */
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007347 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
Vladimir Markod5fd5c32019-07-02 14:46:32 +01007348 // No need for memory fence, thanks to the x86 memory model.
Vladimir Marko174b2e22017-10-12 13:34:49 +01007349 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadStringSlowPathX86(load);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007350 codegen_->AddSlowPath(slow_path);
7351 __ testl(out, out);
7352 __ j(kEqual, slow_path->GetEntryLabel());
7353 __ Bind(slow_path->GetExitLabel());
7354 return;
7355 }
Vladimir Marko8e524ad2018-07-13 10:27:43 +01007356 case HLoadString::LoadKind::kJitBootImageAddress: {
7357 uint32_t address = reinterpret_cast32<uint32_t>(load->GetString().Get());
7358 DCHECK_NE(address, 0u);
7359 __ movl(out, Immediate(address));
7360 return;
7361 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007362 case HLoadString::LoadKind::kJitTableAddress: {
Vladimir Marko4ef451a2020-07-23 09:54:27 +00007363 Address address = Address::Absolute(CodeGeneratorX86::kPlaceholder32BitOffset);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007364 Label* fixup_label = codegen_->NewJitRootStringPatch(
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007365 load->GetDexFile(), load->GetStringIndex(), load->GetString());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007366 // /* GcRoot<mirror::String> */ out = *address
7367 GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
7368 return;
7369 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007370 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07007371 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007372 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007373
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07007374 // TODO: Re-add the compiler code to do string dex cache lookup again.
Christina Wadsworth175d09b2016-08-31 16:26:01 -07007375 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007376 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007377 __ movl(calling_convention.GetRegisterAt(0), Immediate(load->GetStringIndex().index_));
Christina Wadsworth175d09b2016-08-31 16:26:01 -07007378 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7379 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007380}
7381
David Brazdilcb1c0552015-08-04 16:22:25 +01007382static Address GetExceptionTlsAddress() {
Andreas Gampe542451c2016-07-26 09:02:02 -07007383 return Address::Absolute(Thread::ExceptionOffset<kX86PointerSize>().Int32Value());
David Brazdilcb1c0552015-08-04 16:22:25 +01007384}
7385
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007386void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
7387 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01007388 new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007389 locations->SetOut(Location::RequiresRegister());
7390}
7391
7392void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01007393 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
7394}
7395
7396void LocationsBuilderX86::VisitClearException(HClearException* clear) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007397 new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
David Brazdilcb1c0552015-08-04 16:22:25 +01007398}
7399
7400void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
7401 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007402}
7403
7404void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007405 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
7406 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007407 InvokeRuntimeCallingConvention calling_convention;
7408 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7409}
7410
7411void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01007412 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007413 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007414}
7415
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007416// Temp is used for read barrier.
7417static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7418 if (kEmitCompilerReadBarrier &&
Vladimir Marko953437b2016-08-24 08:30:46 +00007419 !kUseBakerReadBarrier &&
7420 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
Roland Levillain7c1559a2015-12-15 10:55:36 +00007421 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007422 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7423 return 1;
7424 }
7425 return 0;
7426}
7427
Vladimir Marko9f8d3122018-04-06 13:47:59 +01007428// Interface case has 2 temps, one for holding the number of interfaces, one for the current
7429// interface pointer, the current interface is compared in memory.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007430// The other checks have one temp for loading the object's class.
7431static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
Vladimir Markoe619f6c2017-12-12 16:00:01 +00007432 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007433 return 2;
7434 }
7435 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillain7c1559a2015-12-15 10:55:36 +00007436}
7437
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007438void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007439 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain0d5a2812015-11-13 10:07:31 +00007440 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01007441 bool baker_read_barrier_slow_path = false;
Roland Levillain0d5a2812015-11-13 10:07:31 +00007442 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007443 case TypeCheckKind::kExactCheck:
7444 case TypeCheckKind::kAbstractClassCheck:
7445 case TypeCheckKind::kClassHierarchyCheck:
Vladimir Marko87584542017-12-12 17:47:52 +00007446 case TypeCheckKind::kArrayObjectCheck: {
7447 bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
7448 call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
7449 baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007450 break;
Vladimir Marko87584542017-12-12 17:47:52 +00007451 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007452 case TypeCheckKind::kArrayCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00007453 case TypeCheckKind::kUnresolvedCheck:
7454 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007455 call_kind = LocationSummary::kCallOnSlowPath;
7456 break;
Vladimir Marko175e7862018-03-27 09:03:13 +00007457 case TypeCheckKind::kBitstringCheck:
7458 break;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007459 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007460
Vladimir Markoca6fff82017-10-03 14:49:14 +01007461 LocationSummary* locations =
7462 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01007463 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007464 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007465 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007466 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00007467 if (type_check_kind == TypeCheckKind::kBitstringCheck) {
7468 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
7469 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
7470 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
7471 } else {
7472 locations->SetInAt(1, Location::Any());
7473 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007474 // Note that TypeCheckSlowPathX86 uses this "out" register too.
7475 locations->SetOut(Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007476 // When read barriers are enabled, we need a temporary register for some cases.
7477 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007478}
7479
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007480void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00007481 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007482 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007483 Location obj_loc = locations->InAt(0);
7484 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007485 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007486 Location out_loc = locations->Out();
7487 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007488 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7489 DCHECK_LE(num_temps, 1u);
7490 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007491 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007492 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7493 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7494 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07007495 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007496 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007497
7498 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007499 // Avoid null check if we know obj is not null.
7500 if (instruction->MustDoNullCheck()) {
7501 __ testl(obj, obj);
7502 __ j(kEqual, &zero);
7503 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007504
Roland Levillain7c1559a2015-12-15 10:55:36 +00007505 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007506 case TypeCheckKind::kExactCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00007507 ReadBarrierOption read_barrier_option =
7508 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007509 // /* HeapReference<Class> */ out = obj->klass_
7510 GenerateReferenceLoadTwoRegisters(instruction,
7511 out_loc,
7512 obj_loc,
7513 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00007514 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007515 if (cls.IsRegister()) {
7516 __ cmpl(out, cls.AsRegister<Register>());
7517 } else {
7518 DCHECK(cls.IsStackSlot()) << cls;
7519 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7520 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007521
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007522 // Classes must be equal for the instanceof to succeed.
7523 __ j(kNotEqual, &zero);
7524 __ movl(out, Immediate(1));
7525 __ jmp(&done);
7526 break;
7527 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007528
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007529 case TypeCheckKind::kAbstractClassCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00007530 ReadBarrierOption read_barrier_option =
7531 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007532 // /* HeapReference<Class> */ out = obj->klass_
7533 GenerateReferenceLoadTwoRegisters(instruction,
7534 out_loc,
7535 obj_loc,
7536 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00007537 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007538 // If the class is abstract, we eagerly fetch the super class of the
7539 // object to avoid doing a comparison we know will fail.
7540 NearLabel loop;
7541 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007542 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007543 GenerateReferenceLoadOneRegister(instruction,
7544 out_loc,
7545 super_offset,
7546 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00007547 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007548 __ testl(out, out);
7549 // If `out` is null, we use it for the result, and jump to `done`.
7550 __ j(kEqual, &done);
7551 if (cls.IsRegister()) {
7552 __ cmpl(out, cls.AsRegister<Register>());
7553 } else {
7554 DCHECK(cls.IsStackSlot()) << cls;
7555 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7556 }
7557 __ j(kNotEqual, &loop);
7558 __ movl(out, Immediate(1));
7559 if (zero.IsLinked()) {
7560 __ jmp(&done);
7561 }
7562 break;
7563 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007564
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007565 case TypeCheckKind::kClassHierarchyCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00007566 ReadBarrierOption read_barrier_option =
7567 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007568 // /* HeapReference<Class> */ out = obj->klass_
7569 GenerateReferenceLoadTwoRegisters(instruction,
7570 out_loc,
7571 obj_loc,
7572 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00007573 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007574 // Walk over the class hierarchy to find a match.
7575 NearLabel loop, success;
7576 __ Bind(&loop);
7577 if (cls.IsRegister()) {
7578 __ cmpl(out, cls.AsRegister<Register>());
7579 } else {
7580 DCHECK(cls.IsStackSlot()) << cls;
7581 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7582 }
7583 __ j(kEqual, &success);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007584 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007585 GenerateReferenceLoadOneRegister(instruction,
7586 out_loc,
7587 super_offset,
7588 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00007589 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007590 __ testl(out, out);
7591 __ j(kNotEqual, &loop);
7592 // If `out` is null, we use it for the result, and jump to `done`.
7593 __ jmp(&done);
7594 __ Bind(&success);
7595 __ movl(out, Immediate(1));
7596 if (zero.IsLinked()) {
7597 __ jmp(&done);
7598 }
7599 break;
7600 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007601
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007602 case TypeCheckKind::kArrayObjectCheck: {
Vladimir Marko87584542017-12-12 17:47:52 +00007603 ReadBarrierOption read_barrier_option =
7604 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007605 // /* HeapReference<Class> */ out = obj->klass_
7606 GenerateReferenceLoadTwoRegisters(instruction,
7607 out_loc,
7608 obj_loc,
7609 class_offset,
Vladimir Marko87584542017-12-12 17:47:52 +00007610 read_barrier_option);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007611 // Do an exact check.
7612 NearLabel exact_check;
7613 if (cls.IsRegister()) {
7614 __ cmpl(out, cls.AsRegister<Register>());
7615 } else {
7616 DCHECK(cls.IsStackSlot()) << cls;
7617 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7618 }
7619 __ j(kEqual, &exact_check);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007620 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00007621 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007622 GenerateReferenceLoadOneRegister(instruction,
7623 out_loc,
7624 component_offset,
7625 maybe_temp_loc,
Vladimir Marko87584542017-12-12 17:47:52 +00007626 read_barrier_option);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007627 __ testl(out, out);
7628 // If `out` is null, we use it for the result, and jump to `done`.
7629 __ j(kEqual, &done);
7630 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
7631 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007632 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007633 __ movl(out, Immediate(1));
7634 __ jmp(&done);
7635 break;
7636 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007637
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007638 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007639 // No read barrier since the slow path will retry upon failure.
7640 // /* HeapReference<Class> */ out = obj->klass_
7641 GenerateReferenceLoadTwoRegisters(instruction,
7642 out_loc,
7643 obj_loc,
7644 class_offset,
7645 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007646 if (cls.IsRegister()) {
7647 __ cmpl(out, cls.AsRegister<Register>());
7648 } else {
7649 DCHECK(cls.IsStackSlot()) << cls;
7650 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
7651 }
7652 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007653 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
Andreas Gampe3db70682018-12-26 15:12:03 -08007654 instruction, /* is_fatal= */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007655 codegen_->AddSlowPath(slow_path);
7656 __ j(kNotEqual, slow_path->GetEntryLabel());
7657 __ movl(out, Immediate(1));
7658 if (zero.IsLinked()) {
7659 __ jmp(&done);
7660 }
7661 break;
7662 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007663
Calin Juravle98893e12015-10-02 21:05:03 +01007664 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain0d5a2812015-11-13 10:07:31 +00007665 case TypeCheckKind::kInterfaceCheck: {
7666 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007667 // into the slow path for the unresolved and interface check
Roland Levillain0d5a2812015-11-13 10:07:31 +00007668 // cases.
7669 //
7670 // We cannot directly call the InstanceofNonTrivial runtime
7671 // entry point without resorting to a type checking slow path
7672 // here (i.e. by calling InvokeRuntime directly), as it would
7673 // require to assign fixed registers for the inputs of this
7674 // HInstanceOf instruction (following the runtime calling
7675 // convention), which might be cluttered by the potential first
7676 // read barrier emission at the beginning of this method.
Roland Levillain7c1559a2015-12-15 10:55:36 +00007677 //
7678 // TODO: Introduce a new runtime entry point taking the object
7679 // to test (instead of its class) as argument, and let it deal
7680 // with the read barrier issues. This will let us refactor this
7681 // case of the `switch` code as it was previously (with a direct
7682 // call to the runtime not using a type checking slow path).
7683 // This should also be beneficial for the other cases above.
Roland Levillain0d5a2812015-11-13 10:07:31 +00007684 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007685 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
Andreas Gampe3db70682018-12-26 15:12:03 -08007686 instruction, /* is_fatal= */ false);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007687 codegen_->AddSlowPath(slow_path);
7688 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007689 if (zero.IsLinked()) {
7690 __ jmp(&done);
7691 }
7692 break;
7693 }
Vladimir Marko175e7862018-03-27 09:03:13 +00007694
7695 case TypeCheckKind::kBitstringCheck: {
7696 // /* HeapReference<Class> */ temp = obj->klass_
7697 GenerateReferenceLoadTwoRegisters(instruction,
7698 out_loc,
7699 obj_loc,
7700 class_offset,
7701 kWithoutReadBarrier);
7702
7703 GenerateBitstringTypeCheckCompare(instruction, out);
7704 __ j(kNotEqual, &zero);
7705 __ movl(out, Immediate(1));
7706 __ jmp(&done);
7707 break;
7708 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007709 }
7710
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007711 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007712 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007713 __ xorl(out, out);
7714 }
7715
7716 if (done.IsLinked()) {
7717 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007718 }
7719
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007720 if (slow_path != nullptr) {
7721 __ Bind(slow_path->GetExitLabel());
7722 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007723}
7724
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007725void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00007726 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko87584542017-12-12 17:47:52 +00007727 LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
Vladimir Markoca6fff82017-10-03 14:49:14 +01007728 LocationSummary* locations =
7729 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007730 locations->SetInAt(0, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007731 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7732 // Require a register for the interface check since there is a loop that compares the class to
7733 // a memory address.
7734 locations->SetInAt(1, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00007735 } else if (type_check_kind == TypeCheckKind::kBitstringCheck) {
7736 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
7737 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
7738 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007739 } else {
7740 locations->SetInAt(1, Location::Any());
7741 }
Vladimir Marko9f8d3122018-04-06 13:47:59 +01007742 // Add temps for read barriers and other uses. One is used by TypeCheckSlowPathX86.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007743 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
7744}
7745
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007746void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00007747 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007748 LocationSummary* locations = instruction->GetLocations();
Roland Levillain0d5a2812015-11-13 10:07:31 +00007749 Location obj_loc = locations->InAt(0);
7750 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007751 Location cls = locations->InAt(1);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007752 Location temp_loc = locations->GetTemp(0);
7753 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007754 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7755 DCHECK_GE(num_temps, 1u);
7756 DCHECK_LE(num_temps, 2u);
7757 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7758 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7759 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7760 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7761 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7762 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7763 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7764 const uint32_t object_array_data_offset =
7765 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007766
Vladimir Marko87584542017-12-12 17:47:52 +00007767 bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007768 SlowPathCode* type_check_slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01007769 new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
7770 instruction, is_type_check_slow_path_fatal);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007771 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007772
Roland Levillain0d5a2812015-11-13 10:07:31 +00007773 NearLabel done;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007774 // Avoid null check if we know obj is not null.
7775 if (instruction->MustDoNullCheck()) {
7776 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007777 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007778 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007779
Roland Levillain0d5a2812015-11-13 10:07:31 +00007780 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007781 case TypeCheckKind::kExactCheck:
7782 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007783 // /* HeapReference<Class> */ temp = obj->klass_
7784 GenerateReferenceLoadTwoRegisters(instruction,
7785 temp_loc,
7786 obj_loc,
7787 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007788 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007789
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007790 if (cls.IsRegister()) {
7791 __ cmpl(temp, cls.AsRegister<Register>());
7792 } else {
7793 DCHECK(cls.IsStackSlot()) << cls;
7794 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
7795 }
7796 // Jump to slow path for throwing the exception or doing a
7797 // more involved array check.
Roland Levillain0d5a2812015-11-13 10:07:31 +00007798 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007799 break;
7800 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007801
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007802 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007803 // /* HeapReference<Class> */ temp = obj->klass_
7804 GenerateReferenceLoadTwoRegisters(instruction,
7805 temp_loc,
7806 obj_loc,
7807 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007808 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007809
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007810 // If the class is abstract, we eagerly fetch the super class of the
7811 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007812 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007813 __ Bind(&loop);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007814 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007815 GenerateReferenceLoadOneRegister(instruction,
7816 temp_loc,
7817 super_offset,
7818 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007819 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007820
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007821 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7822 // exception.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007823 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007824 __ j(kZero, type_check_slow_path->GetEntryLabel());
Roland Levillain0d5a2812015-11-13 10:07:31 +00007825
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007826 // Otherwise, compare the classes
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007827 if (cls.IsRegister()) {
7828 __ cmpl(temp, cls.AsRegister<Register>());
7829 } else {
7830 DCHECK(cls.IsStackSlot()) << cls;
7831 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
7832 }
7833 __ j(kNotEqual, &loop);
7834 break;
7835 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007836
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007837 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007838 // /* HeapReference<Class> */ temp = obj->klass_
7839 GenerateReferenceLoadTwoRegisters(instruction,
7840 temp_loc,
7841 obj_loc,
7842 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007843 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007844
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007845 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007846 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007847 __ Bind(&loop);
7848 if (cls.IsRegister()) {
7849 __ cmpl(temp, cls.AsRegister<Register>());
7850 } else {
7851 DCHECK(cls.IsStackSlot()) << cls;
7852 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
7853 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007854 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007855
Roland Levillain0d5a2812015-11-13 10:07:31 +00007856 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007857 GenerateReferenceLoadOneRegister(instruction,
7858 temp_loc,
7859 super_offset,
7860 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007861 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007862
7863 // If the class reference currently in `temp` is not null, jump
7864 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007865 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007866 __ j(kNotZero, &loop);
7867 // Otherwise, jump to the slow path to throw the exception.;
Roland Levillain0d5a2812015-11-13 10:07:31 +00007868 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007869 break;
7870 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007871
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007872 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007873 // /* HeapReference<Class> */ temp = obj->klass_
7874 GenerateReferenceLoadTwoRegisters(instruction,
7875 temp_loc,
7876 obj_loc,
7877 class_offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007878 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007879
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007880 // Do an exact check.
7881 if (cls.IsRegister()) {
7882 __ cmpl(temp, cls.AsRegister<Register>());
7883 } else {
7884 DCHECK(cls.IsStackSlot()) << cls;
7885 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
7886 }
7887 __ j(kEqual, &done);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007888
7889 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain0d5a2812015-11-13 10:07:31 +00007890 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007891 GenerateReferenceLoadOneRegister(instruction,
7892 temp_loc,
7893 component_offset,
7894 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007895 kWithoutReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00007896
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007897 // If the component type is null (i.e. the object not an array), jump to the slow path to
7898 // throw the exception. Otherwise proceed with the check.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007899 __ testl(temp, temp);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007900 __ j(kZero, type_check_slow_path->GetEntryLabel());
Roland Levillain0d5a2812015-11-13 10:07:31 +00007901
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007902 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007903 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007904 break;
7905 }
Roland Levillain0d5a2812015-11-13 10:07:31 +00007906
Calin Juravle98893e12015-10-02 21:05:03 +01007907 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007908 // We always go into the type check slow path for the unresolved check case.
Roland Levillain0d5a2812015-11-13 10:07:31 +00007909 // We cannot directly call the CheckCast runtime entry point
7910 // without resorting to a type checking slow path here (i.e. by
7911 // calling InvokeRuntime directly), as it would require to
7912 // assign fixed registers for the inputs of this HInstanceOf
7913 // instruction (following the runtime calling convention), which
7914 // might be cluttered by the potential first read barrier
7915 // emission at the beginning of this method.
7916 __ jmp(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007917 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007918
7919 case TypeCheckKind::kInterfaceCheck: {
Vladimir Markoe619f6c2017-12-12 16:00:01 +00007920 // Fast path for the interface check. Try to avoid read barriers to improve the fast path.
7921 // We can not get false positives by doing this.
7922 // /* HeapReference<Class> */ temp = obj->klass_
7923 GenerateReferenceLoadTwoRegisters(instruction,
7924 temp_loc,
7925 obj_loc,
7926 class_offset,
7927 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007928
Vladimir Markoe619f6c2017-12-12 16:00:01 +00007929 // /* HeapReference<Class> */ temp = temp->iftable_
7930 GenerateReferenceLoadTwoRegisters(instruction,
7931 temp_loc,
7932 temp_loc,
7933 iftable_offset,
7934 kWithoutReadBarrier);
7935 // Iftable is never null.
7936 __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
7937 // Maybe poison the `cls` for direct comparison with memory.
7938 __ MaybePoisonHeapReference(cls.AsRegister<Register>());
7939 // Loop through the iftable and check if any class matches.
7940 NearLabel start_loop;
7941 __ Bind(&start_loop);
7942 // Need to subtract first to handle the empty array case.
7943 __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2));
7944 __ j(kNegative, type_check_slow_path->GetEntryLabel());
7945 // Go to next interface if the classes do not match.
7946 __ cmpl(cls.AsRegister<Register>(),
7947 CodeGeneratorX86::ArrayAddress(temp,
7948 maybe_temp2_loc,
7949 TIMES_4,
7950 object_array_data_offset));
7951 __ j(kNotEqual, &start_loop);
7952 // If `cls` was poisoned above, unpoison it.
7953 __ MaybeUnpoisonHeapReference(cls.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007954 break;
7955 }
Vladimir Marko175e7862018-03-27 09:03:13 +00007956
7957 case TypeCheckKind::kBitstringCheck: {
7958 // /* HeapReference<Class> */ temp = obj->klass_
7959 GenerateReferenceLoadTwoRegisters(instruction,
7960 temp_loc,
7961 obj_loc,
7962 class_offset,
7963 kWithoutReadBarrier);
7964
7965 GenerateBitstringTypeCheckCompare(instruction, temp);
7966 __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
7967 break;
7968 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007969 }
7970 __ Bind(&done);
7971
Roland Levillain0d5a2812015-11-13 10:07:31 +00007972 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007973}
7974
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007975void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007976 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
7977 instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007978 InvokeRuntimeCallingConvention calling_convention;
7979 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7980}
7981
7982void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescuba45db02016-07-12 22:53:02 +01007983 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject
7984 : kQuickUnlockObject,
Alexandre Rames8158f282015-08-07 10:26:17 +01007985 instruction,
Serban Constantinescuba45db02016-07-12 22:53:02 +01007986 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007987 if (instruction->IsEnter()) {
7988 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7989 } else {
7990 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7991 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007992}
7993
Shalini Salomi Bodapatidd121f62018-10-26 15:03:53 +05307994void LocationsBuilderX86::VisitX86AndNot(HX86AndNot* instruction) {
7995 DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
7996 DCHECK(DataType::IsIntOrLongType(instruction->GetType())) << instruction->GetType();
7997 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
7998 locations->SetInAt(0, Location::RequiresRegister());
7999 locations->SetInAt(1, Location::RequiresRegister());
8000 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8001}
8002
8003void InstructionCodeGeneratorX86::VisitX86AndNot(HX86AndNot* instruction) {
8004 LocationSummary* locations = instruction->GetLocations();
8005 Location first = locations->InAt(0);
8006 Location second = locations->InAt(1);
8007 Location dest = locations->Out();
8008 if (instruction->GetResultType() == DataType::Type::kInt32) {
8009 __ andn(dest.AsRegister<Register>(),
8010 first.AsRegister<Register>(),
8011 second.AsRegister<Register>());
8012 } else {
8013 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
8014 __ andn(dest.AsRegisterPairLow<Register>(),
8015 first.AsRegisterPairLow<Register>(),
8016 second.AsRegisterPairLow<Register>());
8017 __ andn(dest.AsRegisterPairHigh<Register>(),
8018 first.AsRegisterPairHigh<Register>(),
8019 second.AsRegisterPairHigh<Register>());
8020 }
8021}
8022
8023void LocationsBuilderX86::VisitX86MaskOrResetLeastSetBit(HX86MaskOrResetLeastSetBit* instruction) {
8024 DCHECK(codegen_->GetInstructionSetFeatures().HasAVX2());
8025 DCHECK(instruction->GetType() == DataType::Type::kInt32) << instruction->GetType();
8026 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
8027 locations->SetInAt(0, Location::RequiresRegister());
8028 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8029}
8030
8031void InstructionCodeGeneratorX86::VisitX86MaskOrResetLeastSetBit(
8032 HX86MaskOrResetLeastSetBit* instruction) {
8033 LocationSummary* locations = instruction->GetLocations();
8034 Location src = locations->InAt(0);
8035 Location dest = locations->Out();
8036 DCHECK(instruction->GetResultType() == DataType::Type::kInt32);
8037 switch (instruction->GetOpKind()) {
8038 case HInstruction::kAnd:
8039 __ blsr(dest.AsRegister<Register>(), src.AsRegister<Register>());
8040 break;
8041 case HInstruction::kXor:
8042 __ blsmsk(dest.AsRegister<Register>(), src.AsRegister<Register>());
8043 break;
8044 default:
8045 LOG(FATAL) << "Unreachable";
8046 }
8047}
8048
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008049void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
8050void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
8051void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
8052
8053void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
8054 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008055 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008056 DCHECK(instruction->GetResultType() == DataType::Type::kInt32
8057 || instruction->GetResultType() == DataType::Type::kInt64);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008058 locations->SetInAt(0, Location::RequiresRegister());
8059 locations->SetInAt(1, Location::Any());
8060 locations->SetOut(Location::SameAsFirstInput());
8061}
8062
8063void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
8064 HandleBitwiseOperation(instruction);
8065}
8066
8067void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
8068 HandleBitwiseOperation(instruction);
8069}
8070
8071void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
8072 HandleBitwiseOperation(instruction);
8073}
8074
8075void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
8076 LocationSummary* locations = instruction->GetLocations();
8077 Location first = locations->InAt(0);
8078 Location second = locations->InAt(1);
8079 DCHECK(first.Equals(locations->Out()));
8080
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008081 if (instruction->GetResultType() == DataType::Type::kInt32) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008082 if (second.IsRegister()) {
8083 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00008084 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008085 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00008086 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008087 } else {
8088 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00008089 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008090 }
8091 } else if (second.IsConstant()) {
8092 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00008093 __ andl(first.AsRegister<Register>(),
8094 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008095 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00008096 __ orl(first.AsRegister<Register>(),
8097 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008098 } else {
8099 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00008100 __ xorl(first.AsRegister<Register>(),
8101 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008102 }
8103 } else {
8104 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00008105 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008106 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00008107 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008108 } else {
8109 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00008110 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008111 }
8112 }
8113 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008114 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008115 if (second.IsRegisterPair()) {
8116 if (instruction->IsAnd()) {
8117 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8118 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8119 } else if (instruction->IsOr()) {
8120 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8121 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8122 } else {
8123 DCHECK(instruction->IsXor());
8124 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
8125 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
8126 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008127 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008128 if (instruction->IsAnd()) {
8129 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8130 __ andl(first.AsRegisterPairHigh<Register>(),
8131 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8132 } else if (instruction->IsOr()) {
8133 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8134 __ orl(first.AsRegisterPairHigh<Register>(),
8135 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8136 } else {
8137 DCHECK(instruction->IsXor());
8138 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
8139 __ xorl(first.AsRegisterPairHigh<Register>(),
8140 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
8141 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008142 } else {
8143 DCHECK(second.IsConstant()) << second;
8144 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04008145 int32_t low_value = Low32Bits(value);
8146 int32_t high_value = High32Bits(value);
8147 Immediate low(low_value);
8148 Immediate high(high_value);
8149 Register first_low = first.AsRegisterPairLow<Register>();
8150 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008151 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04008152 if (low_value == 0) {
8153 __ xorl(first_low, first_low);
8154 } else if (low_value != -1) {
8155 __ andl(first_low, low);
8156 }
8157 if (high_value == 0) {
8158 __ xorl(first_high, first_high);
8159 } else if (high_value != -1) {
8160 __ andl(first_high, high);
8161 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008162 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04008163 if (low_value != 0) {
8164 __ orl(first_low, low);
8165 }
8166 if (high_value != 0) {
8167 __ orl(first_high, high);
8168 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008169 } else {
8170 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04008171 if (low_value != 0) {
8172 __ xorl(first_low, low);
8173 }
8174 if (high_value != 0) {
8175 __ xorl(first_high, high);
8176 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00008177 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008178 }
8179 }
8180}
8181
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008182void InstructionCodeGeneratorX86::GenerateReferenceLoadOneRegister(
8183 HInstruction* instruction,
8184 Location out,
8185 uint32_t offset,
8186 Location maybe_temp,
8187 ReadBarrierOption read_barrier_option) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00008188 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008189 if (read_barrier_option == kWithReadBarrier) {
8190 CHECK(kEmitCompilerReadBarrier);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008191 if (kUseBakerReadBarrier) {
8192 // Load with fast path based Baker's read barrier.
8193 // /* HeapReference<Object> */ out = *(out + offset)
8194 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08008195 instruction, out, out_reg, offset, /* needs_null_check= */ false);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008196 } else {
8197 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008198 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillain7c1559a2015-12-15 10:55:36 +00008199 // in the following move operation, as we will need it for the
8200 // read barrier below.
Vladimir Marko953437b2016-08-24 08:30:46 +00008201 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008202 __ movl(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008203 // /* HeapReference<Object> */ out = *(out + offset)
8204 __ movl(out_reg, Address(out_reg, offset));
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008205 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008206 }
8207 } else {
8208 // Plain load with no read barrier.
8209 // /* HeapReference<Object> */ out = *(out + offset)
8210 __ movl(out_reg, Address(out_reg, offset));
8211 __ MaybeUnpoisonHeapReference(out_reg);
8212 }
8213}
8214
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008215void InstructionCodeGeneratorX86::GenerateReferenceLoadTwoRegisters(
8216 HInstruction* instruction,
8217 Location out,
8218 Location obj,
8219 uint32_t offset,
8220 ReadBarrierOption read_barrier_option) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00008221 Register out_reg = out.AsRegister<Register>();
8222 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008223 if (read_barrier_option == kWithReadBarrier) {
8224 CHECK(kEmitCompilerReadBarrier);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008225 if (kUseBakerReadBarrier) {
8226 // Load with fast path based Baker's read barrier.
8227 // /* HeapReference<Object> */ out = *(obj + offset)
8228 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Andreas Gampe3db70682018-12-26 15:12:03 -08008229 instruction, out, obj_reg, offset, /* needs_null_check= */ false);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008230 } else {
8231 // Load with slow path based read barrier.
8232 // /* HeapReference<Object> */ out = *(obj + offset)
8233 __ movl(out_reg, Address(obj_reg, offset));
8234 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
8235 }
8236 } else {
8237 // Plain load with no read barrier.
8238 // /* HeapReference<Object> */ out = *(obj + offset)
8239 __ movl(out_reg, Address(obj_reg, offset));
8240 __ MaybeUnpoisonHeapReference(out_reg);
8241 }
8242}
8243
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008244void InstructionCodeGeneratorX86::GenerateGcRootFieldLoad(
8245 HInstruction* instruction,
8246 Location root,
8247 const Address& address,
8248 Label* fixup_label,
8249 ReadBarrierOption read_barrier_option) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00008250 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008251 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008252 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008253 if (kUseBakerReadBarrier) {
8254 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
8255 // Baker's read barrier are used:
8256 //
Roland Levillaind966ce72017-02-09 16:20:14 +00008257 // root = obj.field;
8258 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8259 // if (temp != null) {
8260 // root = temp(root)
Roland Levillain7c1559a2015-12-15 10:55:36 +00008261 // }
8262
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008263 // /* GcRoot<mirror::Object> */ root = *address
8264 __ movl(root_reg, address);
8265 if (fixup_label != nullptr) {
8266 __ Bind(fixup_label);
8267 }
Roland Levillain7c1559a2015-12-15 10:55:36 +00008268 static_assert(
8269 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
8270 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
8271 "have different sizes.");
8272 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
8273 "art::mirror::CompressedReference<mirror::Object> and int32_t "
8274 "have different sizes.");
8275
Vladimir Marko953437b2016-08-24 08:30:46 +00008276 // Slow path marking the GC root `root`.
Vladimir Marko174b2e22017-10-12 13:34:49 +01008277 SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) ReadBarrierMarkSlowPathX86(
Andreas Gampe3db70682018-12-26 15:12:03 -08008278 instruction, root, /* unpoison_ref_before_marking= */ false);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008279 codegen_->AddSlowPath(slow_path);
8280
Roland Levillaind966ce72017-02-09 16:20:14 +00008281 // Test the entrypoint (`Thread::Current()->pReadBarrierMarkReg ## root.reg()`).
8282 const int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +01008283 Thread::ReadBarrierMarkEntryPointsOffset<kX86PointerSize>(root.reg());
Roland Levillaind966ce72017-02-09 16:20:14 +00008284 __ fs()->cmpl(Address::Absolute(entry_point_offset), Immediate(0));
8285 // The entrypoint is null when the GC is not marking.
Roland Levillain7c1559a2015-12-15 10:55:36 +00008286 __ j(kNotEqual, slow_path->GetEntryLabel());
8287 __ Bind(slow_path->GetExitLabel());
8288 } else {
8289 // GC root loaded through a slow path for read barriers other
8290 // than Baker's.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008291 // /* GcRoot<mirror::Object>* */ root = address
8292 __ leal(root_reg, address);
8293 if (fixup_label != nullptr) {
8294 __ Bind(fixup_label);
8295 }
Roland Levillain7c1559a2015-12-15 10:55:36 +00008296 // /* mirror::Object* */ root = root->Read()
8297 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
8298 }
8299 } else {
8300 // Plain GC root load with no read barrier.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008301 // /* GcRoot<mirror::Object> */ root = *address
8302 __ movl(root_reg, address);
8303 if (fixup_label != nullptr) {
8304 __ Bind(fixup_label);
8305 }
Roland Levillaine3f43ac2016-01-19 15:07:47 +00008306 // Note that GC roots are not affected by heap poisoning, thus we
8307 // do not have to unpoison `root_reg` here.
Roland Levillain7c1559a2015-12-15 10:55:36 +00008308 }
8309}
8310
8311void CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
8312 Location ref,
8313 Register obj,
8314 uint32_t offset,
Roland Levillain7c1559a2015-12-15 10:55:36 +00008315 bool needs_null_check) {
8316 DCHECK(kEmitCompilerReadBarrier);
8317 DCHECK(kUseBakerReadBarrier);
8318
8319 // /* HeapReference<Object> */ ref = *(obj + offset)
8320 Address src(obj, offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00008321 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008322}
8323
8324void CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8325 Location ref,
8326 Register obj,
8327 uint32_t data_offset,
8328 Location index,
Roland Levillain7c1559a2015-12-15 10:55:36 +00008329 bool needs_null_check) {
8330 DCHECK(kEmitCompilerReadBarrier);
8331 DCHECK(kUseBakerReadBarrier);
8332
Roland Levillain3d312422016-06-23 13:53:42 +01008333 static_assert(
8334 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8335 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillain7c1559a2015-12-15 10:55:36 +00008336 // /* HeapReference<Object> */ ref =
8337 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008338 Address src = CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset);
Vladimir Marko953437b2016-08-24 08:30:46 +00008339 GenerateReferenceLoadWithBakerReadBarrier(instruction, ref, obj, src, needs_null_check);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008340}
8341
8342void CodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8343 Location ref,
8344 Register obj,
8345 const Address& src,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008346 bool needs_null_check,
8347 bool always_update_field,
8348 Register* temp) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00008349 DCHECK(kEmitCompilerReadBarrier);
8350 DCHECK(kUseBakerReadBarrier);
8351
8352 // In slow path based read barriers, the read barrier call is
8353 // inserted after the original load. However, in fast path based
8354 // Baker's read barriers, we need to perform the load of
8355 // mirror::Object::monitor_ *before* the original reference load.
8356 // This load-load ordering is required by the read barrier.
8357 // The fast path/slow path (for Baker's algorithm) should look like:
8358 //
8359 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8360 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8361 // HeapReference<Object> ref = *src; // Original reference load.
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07008362 // bool is_gray = (rb_state == ReadBarrier::GrayState());
Roland Levillain7c1559a2015-12-15 10:55:36 +00008363 // if (is_gray) {
8364 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
8365 // }
8366 //
8367 // Note: the original implementation in ReadBarrier::Barrier is
8368 // slightly more complex as:
8369 // - it implements the load-load fence using a data dependency on
Roland Levillaine3f43ac2016-01-19 15:07:47 +00008370 // the high-bits of rb_state, which are expected to be all zeroes
8371 // (we use CodeGeneratorX86::GenerateMemoryBarrier instead here,
8372 // which is a no-op thanks to the x86 memory model);
Roland Levillain7c1559a2015-12-15 10:55:36 +00008373 // - it performs additional checks that we do not do here for
8374 // performance reasons.
8375
8376 Register ref_reg = ref.AsRegister<Register>();
Roland Levillain7c1559a2015-12-15 10:55:36 +00008377 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
8378
Vladimir Marko953437b2016-08-24 08:30:46 +00008379 // Given the numeric representation, it's enough to check the low bit of the rb_state.
Roland Levillain14e5a292018-06-28 12:00:56 +01008380 static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07008381 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
Vladimir Marko953437b2016-08-24 08:30:46 +00008382 constexpr uint32_t gray_byte_position = LockWord::kReadBarrierStateShift / kBitsPerByte;
8383 constexpr uint32_t gray_bit_position = LockWord::kReadBarrierStateShift % kBitsPerByte;
8384 constexpr int32_t test_value = static_cast<int8_t>(1 << gray_bit_position);
8385
Hiroshi Yamauchi12b58b22016-11-01 11:55:29 -07008386 // if (rb_state == ReadBarrier::GrayState())
Vladimir Marko953437b2016-08-24 08:30:46 +00008387 // ref = ReadBarrier::Mark(ref);
8388 // At this point, just do the "if" and make sure that flags are preserved until the branch.
8389 __ testb(Address(obj, monitor_offset + gray_byte_position), Immediate(test_value));
Roland Levillain7c1559a2015-12-15 10:55:36 +00008390 if (needs_null_check) {
8391 MaybeRecordImplicitNullCheck(instruction);
8392 }
Roland Levillain7c1559a2015-12-15 10:55:36 +00008393
8394 // Load fence to prevent load-load reordering.
8395 // Note that this is a no-op, thanks to the x86 memory model.
8396 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
8397
8398 // The actual reference load.
8399 // /* HeapReference<Object> */ ref = *src
Vladimir Marko953437b2016-08-24 08:30:46 +00008400 __ movl(ref_reg, src); // Flags are unaffected.
8401
8402 // Note: Reference unpoisoning modifies the flags, so we need to delay it after the branch.
8403 // Slow path marking the object `ref` when it is gray.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008404 SlowPathCode* slow_path;
8405 if (always_update_field) {
8406 DCHECK(temp != nullptr);
Vladimir Marko174b2e22017-10-12 13:34:49 +01008407 slow_path = new (GetScopedAllocator()) ReadBarrierMarkAndUpdateFieldSlowPathX86(
Andreas Gampe3db70682018-12-26 15:12:03 -08008408 instruction, ref, obj, src, /* unpoison_ref_before_marking= */ true, *temp);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008409 } else {
Vladimir Marko174b2e22017-10-12 13:34:49 +01008410 slow_path = new (GetScopedAllocator()) ReadBarrierMarkSlowPathX86(
Andreas Gampe3db70682018-12-26 15:12:03 -08008411 instruction, ref, /* unpoison_ref_before_marking= */ true);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008412 }
Vladimir Marko953437b2016-08-24 08:30:46 +00008413 AddSlowPath(slow_path);
8414
8415 // We have done the "if" of the gray bit check above, now branch based on the flags.
8416 __ j(kNotZero, slow_path->GetEntryLabel());
Roland Levillain7c1559a2015-12-15 10:55:36 +00008417
8418 // Object* ref = ref_addr->AsMirrorPtr()
8419 __ MaybeUnpoisonHeapReference(ref_reg);
8420
Roland Levillain7c1559a2015-12-15 10:55:36 +00008421 __ Bind(slow_path->GetExitLabel());
8422}
8423
8424void CodeGeneratorX86::GenerateReadBarrierSlow(HInstruction* instruction,
8425 Location out,
8426 Location ref,
8427 Location obj,
8428 uint32_t offset,
8429 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00008430 DCHECK(kEmitCompilerReadBarrier);
8431
Roland Levillain7c1559a2015-12-15 10:55:36 +00008432 // Insert a slow path based read barrier *after* the reference load.
8433 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00008434 // If heap poisoning is enabled, the unpoisoning of the loaded
8435 // reference will be carried out by the runtime within the slow
8436 // path.
8437 //
8438 // Note that `ref` currently does not get unpoisoned (when heap
8439 // poisoning is enabled), which is alright as the `ref` argument is
8440 // not used by the artReadBarrierSlow entry point.
8441 //
8442 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Vladimir Marko174b2e22017-10-12 13:34:49 +01008443 SlowPathCode* slow_path = new (GetScopedAllocator())
Roland Levillain0d5a2812015-11-13 10:07:31 +00008444 ReadBarrierForHeapReferenceSlowPathX86(instruction, out, ref, obj, offset, index);
8445 AddSlowPath(slow_path);
8446
Roland Levillain0d5a2812015-11-13 10:07:31 +00008447 __ jmp(slow_path->GetEntryLabel());
8448 __ Bind(slow_path->GetExitLabel());
8449}
8450
Roland Levillain7c1559a2015-12-15 10:55:36 +00008451void CodeGeneratorX86::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8452 Location out,
8453 Location ref,
8454 Location obj,
8455 uint32_t offset,
8456 Location index) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00008457 if (kEmitCompilerReadBarrier) {
Roland Levillain7c1559a2015-12-15 10:55:36 +00008458 // Baker's read barriers shall be handled by the fast path
8459 // (CodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier).
8460 DCHECK(!kUseBakerReadBarrier);
Roland Levillain0d5a2812015-11-13 10:07:31 +00008461 // If heap poisoning is enabled, unpoisoning will be taken care of
8462 // by the runtime within the slow path.
Roland Levillain7c1559a2015-12-15 10:55:36 +00008463 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain0d5a2812015-11-13 10:07:31 +00008464 } else if (kPoisonHeapReferences) {
8465 __ UnpoisonHeapReference(out.AsRegister<Register>());
8466 }
8467}
8468
Roland Levillain7c1559a2015-12-15 10:55:36 +00008469void CodeGeneratorX86::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8470 Location out,
8471 Location root) {
Roland Levillain0d5a2812015-11-13 10:07:31 +00008472 DCHECK(kEmitCompilerReadBarrier);
8473
Roland Levillain7c1559a2015-12-15 10:55:36 +00008474 // Insert a slow path based read barrier *after* the GC root load.
8475 //
Roland Levillain0d5a2812015-11-13 10:07:31 +00008476 // Note that GC roots are not affected by heap poisoning, so we do
8477 // not need to do anything special for this here.
8478 SlowPathCode* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01008479 new (GetScopedAllocator()) ReadBarrierForRootSlowPathX86(instruction, out, root);
Roland Levillain0d5a2812015-11-13 10:07:31 +00008480 AddSlowPath(slow_path);
8481
Roland Levillain0d5a2812015-11-13 10:07:31 +00008482 __ jmp(slow_path->GetEntryLabel());
8483 __ Bind(slow_path->GetExitLabel());
8484}
8485
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008486void LocationsBuilderX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008487 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008488 LOG(FATAL) << "Unreachable";
8489}
8490
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008491void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008492 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008493 LOG(FATAL) << "Unreachable";
8494}
8495
Mark Mendellfe57faa2015-09-18 09:26:15 -04008496// Simple implementation of packed switch - generate cascaded compare/jumps.
8497void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8498 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008499 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Mark Mendellfe57faa2015-09-18 09:26:15 -04008500 locations->SetInAt(0, Location::RequiresRegister());
8501}
8502
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008503void InstructionCodeGeneratorX86::GenPackedSwitchWithCompares(Register value_reg,
8504 int32_t lower_bound,
8505 uint32_t num_entries,
8506 HBasicBlock* switch_block,
8507 HBasicBlock* default_block) {
8508 // Figure out the correct compare values and jump conditions.
8509 // Handle the first compare/branch as a special case because it might
8510 // jump to the default case.
8511 DCHECK_GT(num_entries, 2u);
8512 Condition first_condition;
8513 uint32_t index;
8514 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
8515 if (lower_bound != 0) {
8516 first_condition = kLess;
8517 __ cmpl(value_reg, Immediate(lower_bound));
8518 __ j(first_condition, codegen_->GetLabelOf(default_block));
8519 __ j(kEqual, codegen_->GetLabelOf(successors[0]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04008520
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008521 index = 1;
8522 } else {
8523 // Handle all the compare/jumps below.
8524 first_condition = kBelow;
8525 index = 0;
8526 }
8527
8528 // Handle the rest of the compare/jumps.
8529 for (; index + 1 < num_entries; index += 2) {
8530 int32_t compare_to_value = lower_bound + index + 1;
8531 __ cmpl(value_reg, Immediate(compare_to_value));
8532 // Jump to successors[index] if value < case_value[index].
8533 __ j(first_condition, codegen_->GetLabelOf(successors[index]));
8534 // Jump to successors[index + 1] if value == case_value[index + 1].
8535 __ j(kEqual, codegen_->GetLabelOf(successors[index + 1]));
8536 }
8537
8538 if (index != num_entries) {
8539 // There are an odd number of entries. Handle the last one.
8540 DCHECK_EQ(index + 1, num_entries);
8541 __ cmpl(value_reg, Immediate(lower_bound + index));
8542 __ j(kEqual, codegen_->GetLabelOf(successors[index]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04008543 }
8544
8545 // And the default for any other value.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008546 if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
8547 __ jmp(codegen_->GetLabelOf(default_block));
Mark Mendellfe57faa2015-09-18 09:26:15 -04008548 }
8549}
8550
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008551void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8552 int32_t lower_bound = switch_instr->GetStartValue();
8553 uint32_t num_entries = switch_instr->GetNumEntries();
8554 LocationSummary* locations = switch_instr->GetLocations();
8555 Register value_reg = locations->InAt(0).AsRegister<Register>();
8556
8557 GenPackedSwitchWithCompares(value_reg,
8558 lower_bound,
8559 num_entries,
8560 switch_instr->GetBlock(),
8561 switch_instr->GetDefaultBlock());
8562}
8563
Mark Mendell805b3b52015-09-18 14:10:29 -04008564void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
8565 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008566 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Mark Mendell805b3b52015-09-18 14:10:29 -04008567 locations->SetInAt(0, Location::RequiresRegister());
8568
8569 // Constant area pointer.
8570 locations->SetInAt(1, Location::RequiresRegister());
8571
8572 // And the temporary we need.
8573 locations->AddTemp(Location::RequiresRegister());
8574}
8575
8576void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
8577 int32_t lower_bound = switch_instr->GetStartValue();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008578 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendell805b3b52015-09-18 14:10:29 -04008579 LocationSummary* locations = switch_instr->GetLocations();
8580 Register value_reg = locations->InAt(0).AsRegister<Register>();
8581 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8582
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008583 if (num_entries <= kPackedSwitchJumpTableThreshold) {
8584 GenPackedSwitchWithCompares(value_reg,
8585 lower_bound,
8586 num_entries,
8587 switch_instr->GetBlock(),
8588 default_block);
8589 return;
8590 }
8591
Mark Mendell805b3b52015-09-18 14:10:29 -04008592 // Optimizing has a jump area.
8593 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
8594 Register constant_area = locations->InAt(1).AsRegister<Register>();
8595
8596 // Remove the bias, if needed.
8597 if (lower_bound != 0) {
8598 __ leal(temp_reg, Address(value_reg, -lower_bound));
8599 value_reg = temp_reg;
8600 }
8601
8602 // Is the value in range?
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008603 DCHECK_GE(num_entries, 1u);
Mark Mendell805b3b52015-09-18 14:10:29 -04008604 __ cmpl(value_reg, Immediate(num_entries - 1));
8605 __ j(kAbove, codegen_->GetLabelOf(default_block));
8606
8607 // We are in the range of the table.
8608 // Load (target-constant_area) from the jump table, indexing by the value.
8609 __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
8610
8611 // Compute the actual target address by adding in constant_area.
8612 __ addl(temp_reg, constant_area);
8613
8614 // And jump.
8615 __ jmp(temp_reg);
8616}
8617
Mark Mendell0616ae02015-04-17 12:49:27 -04008618void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
8619 HX86ComputeBaseMethodAddress* insn) {
8620 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008621 new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
Mark Mendell0616ae02015-04-17 12:49:27 -04008622 locations->SetOut(Location::RequiresRegister());
8623}
8624
8625void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
8626 HX86ComputeBaseMethodAddress* insn) {
8627 LocationSummary* locations = insn->GetLocations();
8628 Register reg = locations->Out().AsRegister<Register>();
8629
8630 // Generate call to next instruction.
8631 Label next_instruction;
8632 __ call(&next_instruction);
8633 __ Bind(&next_instruction);
8634
8635 // Remember this offset for later use with constant area.
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008636 codegen_->AddMethodAddressOffset(insn, GetAssembler()->CodeSize());
Mark Mendell0616ae02015-04-17 12:49:27 -04008637
8638 // Grab the return address off the stack.
8639 __ popl(reg);
8640}
8641
8642void LocationsBuilderX86::VisitX86LoadFromConstantTable(
8643 HX86LoadFromConstantTable* insn) {
8644 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008645 new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
Mark Mendell0616ae02015-04-17 12:49:27 -04008646
8647 locations->SetInAt(0, Location::RequiresRegister());
8648 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
8649
8650 // If we don't need to be materialized, we only need the inputs to be set.
David Brazdilb3e773e2016-01-26 11:28:37 +00008651 if (insn->IsEmittedAtUseSite()) {
Mark Mendell0616ae02015-04-17 12:49:27 -04008652 return;
8653 }
8654
8655 switch (insn->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008656 case DataType::Type::kFloat32:
8657 case DataType::Type::kFloat64:
Mark Mendell0616ae02015-04-17 12:49:27 -04008658 locations->SetOut(Location::RequiresFpuRegister());
8659 break;
8660
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008661 case DataType::Type::kInt32:
Mark Mendell0616ae02015-04-17 12:49:27 -04008662 locations->SetOut(Location::RequiresRegister());
8663 break;
8664
8665 default:
8666 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
8667 }
8668}
8669
8670void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
David Brazdilb3e773e2016-01-26 11:28:37 +00008671 if (insn->IsEmittedAtUseSite()) {
Mark Mendell0616ae02015-04-17 12:49:27 -04008672 return;
8673 }
8674
8675 LocationSummary* locations = insn->GetLocations();
8676 Location out = locations->Out();
8677 Register const_area = locations->InAt(0).AsRegister<Register>();
8678 HConstant *value = insn->GetConstant();
8679
8680 switch (insn->GetType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008681 case DataType::Type::kFloat32:
Mark Mendell0616ae02015-04-17 12:49:27 -04008682 __ movss(out.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008683 codegen_->LiteralFloatAddress(
8684 value->AsFloatConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
Mark Mendell0616ae02015-04-17 12:49:27 -04008685 break;
8686
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008687 case DataType::Type::kFloat64:
Mark Mendell0616ae02015-04-17 12:49:27 -04008688 __ movsd(out.AsFpuRegister<XmmRegister>(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008689 codegen_->LiteralDoubleAddress(
8690 value->AsDoubleConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
Mark Mendell0616ae02015-04-17 12:49:27 -04008691 break;
8692
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008693 case DataType::Type::kInt32:
Mark Mendell0616ae02015-04-17 12:49:27 -04008694 __ movl(out.AsRegister<Register>(),
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008695 codegen_->LiteralInt32Address(
8696 value->AsIntConstant()->GetValue(), insn->GetBaseMethodAddress(), const_area));
Mark Mendell0616ae02015-04-17 12:49:27 -04008697 break;
8698
8699 default:
8700 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
8701 }
8702}
8703
Mark Mendell0616ae02015-04-17 12:49:27 -04008704/**
8705 * Class to handle late fixup of offsets into constant area.
8706 */
Vladimir Marko5233f932015-09-29 19:01:15 +01008707class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendell0616ae02015-04-17 12:49:27 -04008708 public:
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008709 RIPFixup(CodeGeneratorX86& codegen,
8710 HX86ComputeBaseMethodAddress* base_method_address,
8711 size_t offset)
8712 : codegen_(&codegen),
8713 base_method_address_(base_method_address),
8714 offset_into_constant_area_(offset) {}
Mark Mendell805b3b52015-09-18 14:10:29 -04008715
8716 protected:
8717 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
8718
8719 CodeGeneratorX86* codegen_;
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008720 HX86ComputeBaseMethodAddress* base_method_address_;
Mark Mendell0616ae02015-04-17 12:49:27 -04008721
8722 private:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +01008723 void Process(const MemoryRegion& region, int pos) override {
Mark Mendell0616ae02015-04-17 12:49:27 -04008724 // Patch the correct offset for the instruction. The place to patch is the
8725 // last 4 bytes of the instruction.
8726 // The value to patch is the distance from the offset in the constant area
8727 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
Mark Mendell805b3b52015-09-18 14:10:29 -04008728 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008729 int32_t relative_position =
8730 constant_offset - codegen_->GetMethodAddressOffset(base_method_address_);
Mark Mendell0616ae02015-04-17 12:49:27 -04008731
8732 // Patch in the right value.
8733 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
8734 }
8735
Mark Mendell0616ae02015-04-17 12:49:27 -04008736 // Location in constant area that the fixup refers to.
Mark Mendell805b3b52015-09-18 14:10:29 -04008737 int32_t offset_into_constant_area_;
Mark Mendell0616ae02015-04-17 12:49:27 -04008738};
8739
Mark Mendell805b3b52015-09-18 14:10:29 -04008740/**
8741 * Class to handle late fixup of offsets to a jump table that will be created in the
8742 * constant area.
8743 */
8744class JumpTableRIPFixup : public RIPFixup {
8745 public:
8746 JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008747 : RIPFixup(codegen, switch_instr->GetBaseMethodAddress(), static_cast<size_t>(-1)),
8748 switch_instr_(switch_instr) {}
Mark Mendell805b3b52015-09-18 14:10:29 -04008749
8750 void CreateJumpTable() {
8751 X86Assembler* assembler = codegen_->GetAssembler();
8752
8753 // Ensure that the reference to the jump table has the correct offset.
8754 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
8755 SetOffset(offset_in_constant_table);
8756
8757 // The label values in the jump table are computed relative to the
8758 // instruction addressing the constant area.
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008759 const int32_t relative_offset = codegen_->GetMethodAddressOffset(base_method_address_);
Mark Mendell805b3b52015-09-18 14:10:29 -04008760
8761 // Populate the jump table with the correct values for the jump table.
8762 int32_t num_entries = switch_instr_->GetNumEntries();
8763 HBasicBlock* block = switch_instr_->GetBlock();
8764 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
8765 // The value that we want is the target offset - the position of the table.
8766 for (int32_t i = 0; i < num_entries; i++) {
8767 HBasicBlock* b = successors[i];
8768 Label* l = codegen_->GetLabelOf(b);
8769 DCHECK(l->IsBound());
8770 int32_t offset_to_block = l->Position() - relative_offset;
8771 assembler->AppendInt32(offset_to_block);
8772 }
8773 }
8774
8775 private:
8776 const HX86PackedSwitch* switch_instr_;
8777};
8778
8779void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
8780 // Generate the constant area if needed.
8781 X86Assembler* assembler = GetAssembler();
jaishank20d1c942019-03-08 15:08:17 +05308782
Mark Mendell805b3b52015-09-18 14:10:29 -04008783 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
8784 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
8785 // byte values.
8786 assembler->Align(4, 0);
8787 constant_area_start_ = assembler->CodeSize();
8788
8789 // Populate any jump tables.
Vladimir Marko7d157fc2017-05-10 16:29:23 +01008790 for (JumpTableRIPFixup* jump_table : fixups_to_jump_tables_) {
Mark Mendell805b3b52015-09-18 14:10:29 -04008791 jump_table->CreateJumpTable();
8792 }
8793
8794 // And now add the constant area to the generated code.
8795 assembler->AddConstantArea();
8796 }
8797
8798 // And finish up.
8799 CodeGenerator::Finalize(allocator);
8800}
8801
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008802Address CodeGeneratorX86::LiteralDoubleAddress(double v,
8803 HX86ComputeBaseMethodAddress* method_base,
8804 Register reg) {
8805 AssemblerFixup* fixup =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008806 new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddDouble(v));
Vladimir Marko4ef451a2020-07-23 09:54:27 +00008807 return Address(reg, kPlaceholder32BitOffset, fixup);
Mark Mendell0616ae02015-04-17 12:49:27 -04008808}
8809
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008810Address CodeGeneratorX86::LiteralFloatAddress(float v,
8811 HX86ComputeBaseMethodAddress* method_base,
8812 Register reg) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008813 AssemblerFixup* fixup =
8814 new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddFloat(v));
Vladimir Marko4ef451a2020-07-23 09:54:27 +00008815 return Address(reg, kPlaceholder32BitOffset, fixup);
Mark Mendell0616ae02015-04-17 12:49:27 -04008816}
8817
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008818Address CodeGeneratorX86::LiteralInt32Address(int32_t v,
8819 HX86ComputeBaseMethodAddress* method_base,
8820 Register reg) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008821 AssemblerFixup* fixup =
8822 new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddInt32(v));
Vladimir Marko4ef451a2020-07-23 09:54:27 +00008823 return Address(reg, kPlaceholder32BitOffset, fixup);
Mark Mendell0616ae02015-04-17 12:49:27 -04008824}
8825
Nicolas Geoffray133719e2017-01-22 15:44:39 +00008826Address CodeGeneratorX86::LiteralInt64Address(int64_t v,
8827 HX86ComputeBaseMethodAddress* method_base,
8828 Register reg) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008829 AssemblerFixup* fixup =
8830 new (GetGraph()->GetAllocator()) RIPFixup(*this, method_base, __ AddInt64(v));
Vladimir Marko4ef451a2020-07-23 09:54:27 +00008831 return Address(reg, kPlaceholder32BitOffset, fixup);
Mark Mendell0616ae02015-04-17 12:49:27 -04008832}
8833
Aart Bika19616e2016-02-01 18:57:58 -08008834void CodeGeneratorX86::Load32BitValue(Register dest, int32_t value) {
8835 if (value == 0) {
8836 __ xorl(dest, dest);
8837 } else {
8838 __ movl(dest, Immediate(value));
8839 }
8840}
8841
8842void CodeGeneratorX86::Compare32BitValue(Register dest, int32_t value) {
8843 if (value == 0) {
8844 __ testl(dest, dest);
8845 } else {
8846 __ cmpl(dest, Immediate(value));
8847 }
8848}
8849
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008850void CodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
8851 Register lhs_reg = lhs.AsRegister<Register>();
jessicahandojo4877b792016-09-08 19:49:13 -07008852 GenerateIntCompare(lhs_reg, rhs);
8853}
8854
8855void CodeGeneratorX86::GenerateIntCompare(Register lhs, Location rhs) {
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008856 if (rhs.IsConstant()) {
8857 int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
jessicahandojo4877b792016-09-08 19:49:13 -07008858 Compare32BitValue(lhs, value);
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008859 } else if (rhs.IsStackSlot()) {
jessicahandojo4877b792016-09-08 19:49:13 -07008860 __ cmpl(lhs, Address(ESP, rhs.GetStackIndex()));
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008861 } else {
jessicahandojo4877b792016-09-08 19:49:13 -07008862 __ cmpl(lhs, rhs.AsRegister<Register>());
Vladimir Marko56f4bdd2016-09-16 11:32:36 +01008863 }
8864}
8865
8866Address CodeGeneratorX86::ArrayAddress(Register obj,
8867 Location index,
8868 ScaleFactor scale,
8869 uint32_t data_offset) {
8870 return index.IsConstant() ?
8871 Address(obj, (index.GetConstant()->AsIntConstant()->GetValue() << scale) + data_offset) :
8872 Address(obj, index.AsRegister<Register>(), scale, data_offset);
8873}
8874
Mark Mendell805b3b52015-09-18 14:10:29 -04008875Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
8876 Register reg,
8877 Register value) {
8878 // Create a fixup to be used to create and address the jump table.
8879 JumpTableRIPFixup* table_fixup =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008880 new (GetGraph()->GetAllocator()) JumpTableRIPFixup(*this, switch_instr);
Mark Mendell805b3b52015-09-18 14:10:29 -04008881
8882 // We have to populate the jump tables.
8883 fixups_to_jump_tables_.push_back(table_fixup);
8884
8885 // We want a scaled address, as we are extracting the correct offset from the table.
Vladimir Marko4ef451a2020-07-23 09:54:27 +00008886 return Address(reg, value, TIMES_4, kPlaceholder32BitOffset, table_fixup);
Mark Mendell805b3b52015-09-18 14:10:29 -04008887}
8888
Andreas Gampe85b62f22015-09-09 13:15:38 -07008889// TODO: target as memory.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008890void CodeGeneratorX86::MoveFromReturnRegister(Location target, DataType::Type type) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07008891 if (!target.IsValid()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008892 DCHECK_EQ(type, DataType::Type::kVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07008893 return;
8894 }
8895
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008896 DCHECK_NE(type, DataType::Type::kVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07008897
8898 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
8899 if (target.Equals(return_loc)) {
8900 return;
8901 }
8902
8903 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
8904 // with the else branch.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008905 if (type == DataType::Type::kInt64) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008906 HParallelMove parallel_move(GetGraph()->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008907 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), DataType::Type::kInt32, nullptr);
8908 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), DataType::Type::kInt32, nullptr);
Andreas Gampe85b62f22015-09-09 13:15:38 -07008909 GetMoveResolver()->EmitNativeCode(&parallel_move);
8910 } else {
8911 // Let the parallel move resolver take care of all of this.
Vladimir Markoca6fff82017-10-03 14:49:14 +01008912 HParallelMove parallel_move(GetGraph()->GetAllocator());
Andreas Gampe85b62f22015-09-09 13:15:38 -07008913 parallel_move.AddMove(return_loc, target, type, nullptr);
8914 GetMoveResolver()->EmitNativeCode(&parallel_move);
8915 }
8916}
8917
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008918void CodeGeneratorX86::PatchJitRootUse(uint8_t* code,
8919 const uint8_t* roots_data,
8920 const PatchInfo<Label>& info,
8921 uint64_t index_in_table) const {
8922 uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
8923 uintptr_t address =
8924 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
Andreas Gampec55bb392018-09-21 00:02:02 +00008925 using unaligned_uint32_t __attribute__((__aligned__(1))) = uint32_t;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008926 reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
8927 dchecked_integral_cast<uint32_t>(address);
8928}
8929
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008930void CodeGeneratorX86::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
8931 for (const PatchInfo<Label>& info : jit_string_patches_) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008932 StringReference string_reference(info.target_dex_file, dex::StringIndex(info.offset_or_index));
Vladimir Marko174b2e22017-10-12 13:34:49 +01008933 uint64_t index_in_table = GetJitStringRootIndex(string_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01008934 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008935 }
8936
8937 for (const PatchInfo<Label>& info : jit_class_patches_) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008938 TypeReference type_reference(info.target_dex_file, dex::TypeIndex(info.offset_or_index));
Vladimir Marko174b2e22017-10-12 13:34:49 +01008939 uint64_t index_in_table = GetJitClassRootIndex(type_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01008940 PatchJitRootUse(code, roots_data, info, index_in_table);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008941 }
8942}
8943
xueliang.zhonge0eb4832017-10-30 13:43:14 +00008944void LocationsBuilderX86::VisitIntermediateAddress(HIntermediateAddress* instruction
8945 ATTRIBUTE_UNUSED) {
8946 LOG(FATAL) << "Unreachable";
8947}
8948
8949void InstructionCodeGeneratorX86::VisitIntermediateAddress(HIntermediateAddress* instruction
8950 ATTRIBUTE_UNUSED) {
8951 LOG(FATAL) << "Unreachable";
8952}
8953
Shalini Salomi Bodapatib45a4352019-07-10 16:09:41 +05308954bool LocationsBuilderX86::CpuHasAvxFeatureFlag() {
8955 return codegen_->GetInstructionSetFeatures().HasAVX();
8956}
8957bool LocationsBuilderX86::CpuHasAvx2FeatureFlag() {
8958 return codegen_->GetInstructionSetFeatures().HasAVX2();
8959}
8960bool InstructionCodeGeneratorX86::CpuHasAvxFeatureFlag() {
8961 return codegen_->GetInstructionSetFeatures().HasAVX();
8962}
8963bool InstructionCodeGeneratorX86::CpuHasAvx2FeatureFlag() {
8964 return codegen_->GetInstructionSetFeatures().HasAVX2();
8965}
8966
Roland Levillain4d027112015-07-01 15:41:14 +01008967#undef __
8968
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00008969} // namespace x86
8970} // namespace art