blob: 0db5837b97eae291bd2b14a892642827c0693c92 [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
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method.h"
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010020#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000021#include "compiled_method.h"
Mark Mendell0616ae02015-04-17 12:49:27 -040022#include "constant_area_fixups_x86.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010023#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000024#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010025#include "gc/accounting/card_table.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040026#include "intrinsics.h"
27#include "intrinsics_x86.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070028#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070029#include "mirror/class-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010030#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010032#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010034#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010037
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000038namespace x86 {
39
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010041static constexpr Register kMethodRegisterArgument = EAX;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010042
Mark Mendell5f874182015-03-04 15:42:45 -050043static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010044
Mark Mendell24f2dfa2015-01-14 19:51:45 -050045static constexpr int kC2ConditionMask = 0x400;
46
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000047static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000048
Roland Levillain62a46b22015-06-01 18:24:13 +010049#define __ down_cast<X86Assembler*>(codegen->GetAssembler())->
Calin Juravle175dc732015-08-25 15:42:32 +010050#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86WordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010051
Andreas Gampe85b62f22015-09-09 13:15:38 -070052class NullCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010053 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010054 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010055
Alexandre Rames2ed20af2015-03-06 13:55:35 +000056 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010057 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010058 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000059 if (instruction_->CanThrowIntoCatchBlock()) {
60 // Live registers will be restored in the catch block if caught.
61 SaveLiveRegisters(codegen, instruction_->GetLocations());
62 }
Alexandre Rames8158f282015-08-07 10:26:17 +010063 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
64 instruction_,
65 instruction_->GetDexPc(),
66 this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067 }
68
Alexandre Rames8158f282015-08-07 10:26:17 +010069 bool IsFatal() const OVERRIDE { return true; }
70
Alexandre Rames9931f312015-06-19 14:47:01 +010071 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86"; }
72
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010074 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
76};
77
Andreas Gampe85b62f22015-09-09 13:15:38 -070078class DivZeroCheckSlowPathX86 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000079 public:
80 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
81
Alexandre Rames2ed20af2015-03-06 13:55:35 +000082 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames8158f282015-08-07 10:26:17 +010083 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Calin Juravled0d48522014-11-04 16:40:20 +000084 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000085 if (instruction_->CanThrowIntoCatchBlock()) {
86 // Live registers will be restored in the catch block if caught.
87 SaveLiveRegisters(codegen, instruction_->GetLocations());
88 }
Alexandre Rames8158f282015-08-07 10:26:17 +010089 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
90 instruction_,
91 instruction_->GetDexPc(),
92 this);
Calin Juravled0d48522014-11-04 16:40:20 +000093 }
94
Alexandre Rames8158f282015-08-07 10:26:17 +010095 bool IsFatal() const OVERRIDE { return true; }
96
Alexandre Rames9931f312015-06-19 14:47:01 +010097 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86"; }
98
Calin Juravled0d48522014-11-04 16:40:20 +000099 private:
100 HDivZeroCheck* const instruction_;
101 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
102};
103
Andreas Gampe85b62f22015-09-09 13:15:38 -0700104class DivRemMinusOneSlowPathX86 : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +0000105 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100106 DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000107
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000108 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000109 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +0000110 if (is_div_) {
111 __ negl(reg_);
112 } else {
113 __ movl(reg_, Immediate(0));
114 }
Calin Juravled0d48522014-11-04 16:40:20 +0000115 __ jmp(GetExitLabel());
116 }
117
Alexandre Rames9931f312015-06-19 14:47:01 +0100118 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86"; }
119
Calin Juravled0d48522014-11-04 16:40:20 +0000120 private:
121 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000122 bool is_div_;
123 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +0000124};
125
Andreas Gampe85b62f22015-09-09 13:15:38 -0700126class BoundsCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100128 explicit BoundsCheckSlowPathX86(HBoundsCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100129
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000130 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100131 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100132 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100133 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000134 // We're moving two locations to locations that could overlap, so we need a parallel
135 // move resolver.
David Brazdil77a48ae2015-09-15 12:34:04 +0000136 if (instruction_->CanThrowIntoCatchBlock()) {
137 // Live registers will be restored in the catch block if caught.
138 SaveLiveRegisters(codegen, instruction_->GetLocations());
139 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000141 x86_codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100142 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000143 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100144 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100145 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100146 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
147 Primitive::kPrimInt);
Alexandre Rames8158f282015-08-07 10:26:17 +0100148 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
149 instruction_,
150 instruction_->GetDexPc(),
151 this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 }
153
Alexandre Rames8158f282015-08-07 10:26:17 +0100154 bool IsFatal() const OVERRIDE { return true; }
155
Alexandre Rames9931f312015-06-19 14:47:01 +0100156 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86"; }
157
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100158 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100159 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160
161 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
162};
163
Andreas Gampe85b62f22015-09-09 13:15:38 -0700164class SuspendCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000165 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000166 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100167 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000168
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000169 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100170 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000171 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000172 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100173 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
174 instruction_,
175 instruction_->GetDexPc(),
176 this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000177 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100178 if (successor_ == nullptr) {
179 __ jmp(GetReturnLabel());
180 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100181 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100182 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000183 }
184
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100185 Label* GetReturnLabel() {
186 DCHECK(successor_ == nullptr);
187 return &return_label_;
188 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000189
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100190 HBasicBlock* GetSuccessor() const {
191 return successor_;
192 }
193
Alexandre Rames9931f312015-06-19 14:47:01 +0100194 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86"; }
195
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000196 private:
197 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100198 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000199 Label return_label_;
200
201 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
202};
203
Andreas Gampe85b62f22015-09-09 13:15:38 -0700204class LoadStringSlowPathX86 : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000205 public:
206 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
207
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000208 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000209 LocationSummary* locations = instruction_->GetLocations();
210 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
211
212 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
213 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000214 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000215
216 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800217 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100218 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
219 instruction_,
220 instruction_->GetDexPc(),
221 this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000222 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000223 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000224
225 __ jmp(GetExitLabel());
226 }
227
Alexandre Rames9931f312015-06-19 14:47:01 +0100228 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86"; }
229
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000230 private:
231 HLoadString* const instruction_;
232
233 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
234};
235
Andreas Gampe85b62f22015-09-09 13:15:38 -0700236class LoadClassSlowPathX86 : public SlowPathCode {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 public:
238 LoadClassSlowPathX86(HLoadClass* cls,
239 HInstruction* at,
240 uint32_t dex_pc,
241 bool do_clinit)
242 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
243 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
244 }
245
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000246 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000247 LocationSummary* locations = at_->GetLocations();
248 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
249 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000250 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000251
252 InvokeRuntimeCallingConvention calling_convention;
253 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
Alexandre Rames8158f282015-08-07 10:26:17 +0100254 x86_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
255 : QUICK_ENTRY_POINT(pInitializeType),
256 at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000257
258 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000259 Location out = locations->Out();
260 if (out.IsValid()) {
261 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
262 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000263 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000264
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000265 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000266 __ jmp(GetExitLabel());
267 }
268
Alexandre Rames9931f312015-06-19 14:47:01 +0100269 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86"; }
270
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000271 private:
272 // The class this slow path will load.
273 HLoadClass* const cls_;
274
275 // The instruction where this slow path is happening.
276 // (Might be the load class or an initialization check).
277 HInstruction* const at_;
278
279 // The dex PC of `at_`.
280 const uint32_t dex_pc_;
281
282 // Whether to initialize the class.
283 const bool do_clinit_;
284
285 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
286};
287
Andreas Gampe85b62f22015-09-09 13:15:38 -0700288class TypeCheckSlowPathX86 : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000289 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000290 TypeCheckSlowPathX86(HInstruction* instruction, bool is_fatal)
291 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000293 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100295 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
296 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000297 DCHECK(instruction_->IsCheckCast()
298 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299
300 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
301 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000302
303 if (instruction_->IsCheckCast()) {
304 // The codegen for the instruction overwrites `temp`, so put it back in place.
305 Register obj = locations->InAt(0).AsRegister<Register>();
306 Register temp = locations->GetTemp(0).AsRegister<Register>();
307 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
308 __ movl(temp, Address(obj, class_offset));
309 __ MaybeUnpoisonHeapReference(temp);
310 }
311
312 if (!is_fatal_) {
313 SaveLiveRegisters(codegen, locations);
314 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000315
316 // We're moving two locations to locations that could overlap, so we need a parallel
317 // move resolver.
318 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000319 x86_codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100320 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000321 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100322 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100323 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100324 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
325 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000326
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000327 if (instruction_->IsInstanceOf()) {
Alexandre Rames8158f282015-08-07 10:26:17 +0100328 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
329 instruction_,
330 instruction_->GetDexPc(),
331 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000332 } else {
333 DCHECK(instruction_->IsCheckCast());
Alexandre Rames8158f282015-08-07 10:26:17 +0100334 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
335 instruction_,
336 instruction_->GetDexPc(),
337 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000338 }
339
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000340 if (!is_fatal_) {
341 if (instruction_->IsInstanceOf()) {
342 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
343 }
344 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray75374372015-09-17 17:12:19 +0000345
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000346 __ jmp(GetExitLabel());
347 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000348 }
349
Alexandre Rames9931f312015-06-19 14:47:01 +0100350 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86"; }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000351 bool IsFatal() const OVERRIDE { return is_fatal_; }
Alexandre Rames9931f312015-06-19 14:47:01 +0100352
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000353 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000354 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000355 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000356
357 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
358};
359
Andreas Gampe85b62f22015-09-09 13:15:38 -0700360class DeoptimizationSlowPathX86 : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700361 public:
362 explicit DeoptimizationSlowPathX86(HInstruction* instruction)
363 : instruction_(instruction) {}
364
365 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames98596202015-08-19 11:33:36 +0100366 DCHECK(instruction_->IsDeoptimize());
Alexandre Rames8158f282015-08-07 10:26:17 +0100367 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700368 __ Bind(GetEntryLabel());
369 SaveLiveRegisters(codegen, instruction_->GetLocations());
Alexandre Rames8158f282015-08-07 10:26:17 +0100370 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
371 instruction_,
372 instruction_->GetDexPc(),
373 this);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700374 }
375
Alexandre Rames9931f312015-06-19 14:47:01 +0100376 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86"; }
377
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700378 private:
379 HInstruction* const instruction_;
380 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
381};
382
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100383class ArraySetSlowPathX86 : public SlowPathCode {
384 public:
385 explicit ArraySetSlowPathX86(HInstruction* instruction) : instruction_(instruction) {}
386
387 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
388 LocationSummary* locations = instruction_->GetLocations();
389 __ Bind(GetEntryLabel());
390 SaveLiveRegisters(codegen, locations);
391
392 InvokeRuntimeCallingConvention calling_convention;
393 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
394 parallel_move.AddMove(
395 locations->InAt(0),
396 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
397 Primitive::kPrimNot,
398 nullptr);
399 parallel_move.AddMove(
400 locations->InAt(1),
401 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
402 Primitive::kPrimInt,
403 nullptr);
404 parallel_move.AddMove(
405 locations->InAt(2),
406 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
407 Primitive::kPrimNot,
408 nullptr);
409 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
410
411 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
412 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
413 instruction_,
414 instruction_->GetDexPc(),
415 this);
416 RestoreLiveRegisters(codegen, locations);
417 __ jmp(GetExitLabel());
418 }
419
420 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86"; }
421
422 private:
423 HInstruction* const instruction_;
424
425 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86);
426};
427
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100428#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100429#define __ down_cast<X86Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100430
Aart Bike9f37602015-10-09 11:15:55 -0700431inline Condition X86Condition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700432 switch (cond) {
433 case kCondEQ: return kEqual;
434 case kCondNE: return kNotEqual;
435 case kCondLT: return kLess;
436 case kCondLE: return kLessEqual;
437 case kCondGT: return kGreater;
438 case kCondGE: return kGreaterEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700439 case kCondB: return kBelow;
440 case kCondBE: return kBelowEqual;
441 case kCondA: return kAbove;
442 case kCondAE: return kAboveEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700443 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100444 LOG(FATAL) << "Unreachable";
445 UNREACHABLE();
446}
447
Aart Bike9f37602015-10-09 11:15:55 -0700448// Maps signed condition to unsigned condition and FP condition to x86 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100449inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
450 switch (cond) {
451 case kCondEQ: return kEqual;
452 case kCondNE: return kNotEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700453 // Signed to unsigned, and FP to x86 name.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100454 case kCondLT: return kBelow;
455 case kCondLE: return kBelowEqual;
456 case kCondGT: return kAbove;
457 case kCondGE: return kAboveEqual;
Aart Bike9f37602015-10-09 11:15:55 -0700458 // Unsigned remain unchanged.
459 case kCondB: return kBelow;
460 case kCondBE: return kBelowEqual;
461 case kCondA: return kAbove;
462 case kCondAE: return kAboveEqual;
Roland Levillain4fa13f62015-07-06 18:11:54 +0100463 }
464 LOG(FATAL) << "Unreachable";
465 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700466}
467
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100468void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100469 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100470}
471
472void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100473 stream << XmmRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100474}
475
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100476size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
477 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
478 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100479}
480
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100481size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
482 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
483 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100484}
485
Mark Mendell7c8d0092015-01-26 11:21:33 -0500486size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
487 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
488 return GetFloatingPointSpillSlotSize();
489}
490
491size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
492 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
493 return GetFloatingPointSpillSlotSize();
494}
495
Calin Juravle175dc732015-08-25 15:42:32 +0100496void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint,
497 HInstruction* instruction,
498 uint32_t dex_pc,
499 SlowPathCode* slow_path) {
500 InvokeRuntime(GetThreadOffset<kX86WordSize>(entrypoint).Int32Value(),
501 instruction,
502 dex_pc,
503 slow_path);
504}
505
506void CodeGeneratorX86::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100507 HInstruction* instruction,
508 uint32_t dex_pc,
509 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100510 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100511 __ fs()->call(Address::Absolute(entry_point_offset));
Alexandre Rames8158f282015-08-07 10:26:17 +0100512 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100513}
514
Mark Mendellfb8d2792015-03-31 22:16:59 -0400515CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
516 const X86InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100517 const CompilerOptions& compiler_options,
518 OptimizingCompilerStats* stats)
Mark Mendell5f874182015-03-04 15:42:45 -0500519 : CodeGenerator(graph,
520 kNumberOfCpuRegisters,
521 kNumberOfXmmRegisters,
522 kNumberOfRegisterPairs,
523 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
524 arraysize(kCoreCalleeSaves))
525 | (1 << kFakeReturnRegister),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100526 0,
527 compiler_options,
528 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100529 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100530 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100531 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400532 move_resolver_(graph->GetArena(), this),
Vladimir Marko58155012015-08-19 12:49:41 +0000533 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100534 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Mark Mendell805b3b52015-09-18 14:10:29 -0400535 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
536 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000537 // Use a fake return address register to mimic Quick.
538 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100539}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100540
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100541Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100542 switch (type) {
543 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100544 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100545 X86ManagedRegister pair =
546 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100547 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
548 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100549 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
550 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100551 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100552 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100553 }
554
555 case Primitive::kPrimByte:
556 case Primitive::kPrimBoolean:
557 case Primitive::kPrimChar:
558 case Primitive::kPrimShort:
559 case Primitive::kPrimInt:
560 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100561 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100562 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100563 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100564 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
565 X86ManagedRegister current =
566 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
567 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100568 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100569 }
570 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100571 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100572 }
573
574 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100575 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100576 return Location::FpuRegisterLocation(
577 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100579
580 case Primitive::kPrimVoid:
581 LOG(FATAL) << "Unreachable type " << type;
582 }
583
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100584 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100585}
586
Mark Mendell5f874182015-03-04 15:42:45 -0500587void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100588 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100589 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100590
591 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100592 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100593
Mark Mendell5f874182015-03-04 15:42:45 -0500594 if (is_baseline) {
595 blocked_core_registers_[EBP] = true;
596 blocked_core_registers_[ESI] = true;
597 blocked_core_registers_[EDI] = true;
598 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100599
600 UpdateBlockedPairRegisters();
601}
602
603void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
604 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
605 X86ManagedRegister current =
606 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
607 if (blocked_core_registers_[current.AsRegisterPairLow()]
608 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
609 blocked_register_pairs_[i] = true;
610 }
611 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100612}
613
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100614InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
615 : HGraphVisitor(graph),
616 assembler_(codegen->GetAssembler()),
617 codegen_(codegen) {}
618
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100619static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100620 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100621}
622
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000623void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100624 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000625 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000626 bool skip_overflow_check =
627 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000628 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000629
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000630 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100631 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100632 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100633 }
634
Mark Mendell5f874182015-03-04 15:42:45 -0500635 if (HasEmptyFrame()) {
636 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000637 }
Mark Mendell5f874182015-03-04 15:42:45 -0500638
639 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
640 Register reg = kCoreCalleeSaves[i];
641 if (allocated_registers_.ContainsCoreRegister(reg)) {
642 __ pushl(reg);
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100643 __ cfi().AdjustCFAOffset(kX86WordSize);
644 __ cfi().RelOffset(DWARFReg(reg), 0);
Mark Mendell5f874182015-03-04 15:42:45 -0500645 }
646 }
647
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100648 int adjust = GetFrameSize() - FrameEntrySpillSize();
649 __ subl(ESP, Immediate(adjust));
650 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100651 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000652}
653
654void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100655 __ cfi().RememberState();
656 if (!HasEmptyFrame()) {
657 int adjust = GetFrameSize() - FrameEntrySpillSize();
658 __ addl(ESP, Immediate(adjust));
659 __ cfi().AdjustCFAOffset(-adjust);
Mark Mendell5f874182015-03-04 15:42:45 -0500660
David Srbeckyc34dc932015-04-12 09:27:43 +0100661 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
662 Register reg = kCoreCalleeSaves[i];
663 if (allocated_registers_.ContainsCoreRegister(reg)) {
664 __ popl(reg);
665 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
666 __ cfi().Restore(DWARFReg(reg));
667 }
Mark Mendell5f874182015-03-04 15:42:45 -0500668 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000669 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100670 __ ret();
671 __ cfi().RestoreState();
672 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000673}
674
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100675void CodeGeneratorX86::Bind(HBasicBlock* block) {
676 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000677}
678
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100679Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
680 switch (load->GetType()) {
681 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100682 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100683 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100684
685 case Primitive::kPrimInt:
686 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100688 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100689
690 case Primitive::kPrimBoolean:
691 case Primitive::kPrimByte:
692 case Primitive::kPrimChar:
693 case Primitive::kPrimShort:
694 case Primitive::kPrimVoid:
695 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700696 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100697 }
698
699 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700700 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100701}
702
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100703Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
704 switch (type) {
705 case Primitive::kPrimBoolean:
706 case Primitive::kPrimByte:
707 case Primitive::kPrimChar:
708 case Primitive::kPrimShort:
709 case Primitive::kPrimInt:
710 case Primitive::kPrimNot:
711 return Location::RegisterLocation(EAX);
712
713 case Primitive::kPrimLong:
714 return Location::RegisterPairLocation(EAX, EDX);
715
716 case Primitive::kPrimVoid:
717 return Location::NoLocation();
718
719 case Primitive::kPrimDouble:
720 case Primitive::kPrimFloat:
721 return Location::FpuRegisterLocation(XMM0);
722 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100723
724 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100725}
726
727Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
728 return Location::RegisterLocation(kMethodRegisterArgument);
729}
730
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100731Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100732 switch (type) {
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimChar:
736 case Primitive::kPrimShort:
737 case Primitive::kPrimInt:
738 case Primitive::kPrimNot: {
739 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000740 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100741 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100742 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100743 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000744 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100745 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100746 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100747
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000748 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100749 uint32_t index = gp_index_;
750 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000751 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100752 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100753 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
754 calling_convention.GetRegisterPairAt(index));
755 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100756 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000757 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
758 }
759 }
760
761 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100762 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000763 stack_index_++;
764 if (index < calling_convention.GetNumberOfFpuRegisters()) {
765 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
766 } else {
767 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
768 }
769 }
770
771 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100772 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000773 stack_index_ += 2;
774 if (index < calling_convention.GetNumberOfFpuRegisters()) {
775 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
776 } else {
777 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100778 }
779 }
780
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100781 case Primitive::kPrimVoid:
782 LOG(FATAL) << "Unexpected parameter type " << type;
783 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100784 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100785 return Location();
786}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100787
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100788void CodeGeneratorX86::Move32(Location destination, Location source) {
789 if (source.Equals(destination)) {
790 return;
791 }
792 if (destination.IsRegister()) {
793 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000794 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100795 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000796 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100797 } else {
798 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000799 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100800 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100801 } else if (destination.IsFpuRegister()) {
802 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000803 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100804 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000805 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100806 } else {
807 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000808 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100809 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100810 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000811 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100812 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000813 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100814 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000815 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500816 } else if (source.IsConstant()) {
817 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000818 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500819 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100820 } else {
821 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100822 __ pushl(Address(ESP, source.GetStackIndex()));
823 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100824 }
825 }
826}
827
828void CodeGeneratorX86::Move64(Location destination, Location source) {
829 if (source.Equals(destination)) {
830 return;
831 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100832 if (destination.IsRegisterPair()) {
833 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000834 EmitParallelMoves(
835 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
836 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100837 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000838 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100839 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
840 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100841 } else if (source.IsFpuRegister()) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100842 XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
843 __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
844 __ psrlq(src_reg, Immediate(32));
845 __ movd(destination.AsRegisterPairHigh<Register>(), src_reg);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100846 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000847 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100848 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100849 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
850 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100851 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
852 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100853 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500854 if (source.IsFpuRegister()) {
855 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
856 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000857 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Calin Juravlee460d1d2015-09-29 04:52:17 +0100858 } else if (source.IsRegisterPair()) {
859 size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt);
860 // Create stack space for 2 elements.
861 __ subl(ESP, Immediate(2 * elem_size));
862 __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>());
863 __ movl(Address(ESP, elem_size), source.AsRegisterPairHigh<Register>());
864 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
865 // And remove the temporary stack space we allocated.
866 __ addl(ESP, Immediate(2 * elem_size));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100867 } else {
868 LOG(FATAL) << "Unimplemented";
869 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100870 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000871 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100872 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000873 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100874 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100875 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100876 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100877 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000878 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000879 } else if (source.IsConstant()) {
880 HConstant* constant = source.GetConstant();
881 int64_t value;
882 if (constant->IsLongConstant()) {
883 value = constant->AsLongConstant()->GetValue();
884 } else {
885 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000886 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000887 }
888 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
889 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000891 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000892 EmitParallelMoves(
893 Location::StackSlot(source.GetStackIndex()),
894 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100895 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000896 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100897 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
898 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100899 }
900 }
901}
902
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100903void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000904 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100905 if (instruction->IsCurrentMethod()) {
906 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
907 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000908 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100909 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000910 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000911 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
912 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000913 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000914 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000915 } else if (location.IsStackSlot()) {
916 __ movl(Address(ESP, location.GetStackIndex()), imm);
917 } else {
918 DCHECK(location.IsConstant());
919 DCHECK_EQ(location.GetConstant(), const_to_move);
920 }
921 } else if (const_to_move->IsLongConstant()) {
922 int64_t value = const_to_move->AsLongConstant()->GetValue();
923 if (location.IsRegisterPair()) {
924 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
925 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
926 } else if (location.IsDoubleStackSlot()) {
927 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000928 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
929 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000930 } else {
931 DCHECK(location.IsConstant());
932 DCHECK_EQ(location.GetConstant(), instruction);
933 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100934 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000935 } else if (instruction->IsTemporary()) {
936 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000937 if (temp_location.IsStackSlot()) {
938 Move32(location, temp_location);
939 } else {
940 DCHECK(temp_location.IsDoubleStackSlot());
941 Move64(location, temp_location);
942 }
Roland Levillain476df552014-10-09 17:51:36 +0100943 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100944 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100945 switch (instruction->GetType()) {
946 case Primitive::kPrimBoolean:
947 case Primitive::kPrimByte:
948 case Primitive::kPrimChar:
949 case Primitive::kPrimShort:
950 case Primitive::kPrimInt:
951 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100952 case Primitive::kPrimFloat:
953 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100954 break;
955
956 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100957 case Primitive::kPrimDouble:
958 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100959 break;
960
961 default:
962 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
963 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000964 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100965 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100966 switch (instruction->GetType()) {
967 case Primitive::kPrimBoolean:
968 case Primitive::kPrimByte:
969 case Primitive::kPrimChar:
970 case Primitive::kPrimShort:
971 case Primitive::kPrimInt:
972 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100973 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000974 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100975 break;
976
977 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100978 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000979 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100980 break;
981
982 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100983 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100984 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000985 }
986}
987
Calin Juravle175dc732015-08-25 15:42:32 +0100988void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
989 DCHECK(location.IsRegister());
990 __ movl(location.AsRegister<Register>(), Immediate(value));
991}
992
Calin Juravlee460d1d2015-09-29 04:52:17 +0100993void CodeGeneratorX86::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
994 if (Primitive::Is64BitType(dst_type)) {
995 Move64(dst, src);
996 } else {
997 Move32(dst, src);
998 }
999}
1000
1001void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) {
1002 if (location.IsRegister()) {
1003 locations->AddTemp(location);
1004 } else if (location.IsRegisterPair()) {
1005 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1006 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1007 } else {
1008 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1009 }
1010}
1011
David Brazdilfc6a86a2015-06-26 10:33:45 +00001012void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001013 DCHECK(!successor->IsExitBlock());
1014
1015 HBasicBlock* block = got->GetBlock();
1016 HInstruction* previous = got->GetPrevious();
1017
1018 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001019 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001020 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1021 return;
1022 }
1023
1024 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1025 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1026 }
1027 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001028 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001029 }
1030}
1031
David Brazdilfc6a86a2015-06-26 10:33:45 +00001032void LocationsBuilderX86::VisitGoto(HGoto* got) {
1033 got->SetLocations(nullptr);
1034}
1035
1036void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
1037 HandleGoto(got, got->GetSuccessor());
1038}
1039
1040void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1041 try_boundary->SetLocations(nullptr);
1042}
1043
1044void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1045 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1046 if (!successor->IsExitBlock()) {
1047 HandleGoto(try_boundary, successor);
1048 }
1049}
1050
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001051void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001052 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001053}
1054
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001055void InstructionCodeGeneratorX86::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001056}
1057
Mark Mendellc4701932015-04-10 13:18:51 -04001058void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
1059 Label* true_label,
1060 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001061 if (cond->IsFPConditionTrueIfNaN()) {
1062 __ j(kUnordered, true_label);
1063 } else if (cond->IsFPConditionFalseIfNaN()) {
1064 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001065 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001066 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001067}
1068
1069void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
1070 Label* true_label,
1071 Label* false_label) {
1072 LocationSummary* locations = cond->GetLocations();
1073 Location left = locations->InAt(0);
1074 Location right = locations->InAt(1);
1075 IfCondition if_cond = cond->GetCondition();
1076
Mark Mendellc4701932015-04-10 13:18:51 -04001077 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001078 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001079 IfCondition true_high_cond = if_cond;
1080 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001081 Condition final_condition = X86UnsignedOrFPCondition(if_cond); // unsigned on lower part
Mark Mendellc4701932015-04-10 13:18:51 -04001082
1083 // Set the conditions for the test, remembering that == needs to be
1084 // decided using the low words.
1085 switch (if_cond) {
1086 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001087 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001088 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001089 break;
1090 case kCondLT:
1091 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001092 break;
1093 case kCondLE:
1094 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001095 break;
1096 case kCondGT:
1097 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001098 break;
1099 case kCondGE:
1100 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001101 break;
Aart Bike9f37602015-10-09 11:15:55 -07001102 case kCondB:
1103 false_high_cond = kCondA;
1104 break;
1105 case kCondBE:
1106 true_high_cond = kCondB;
1107 break;
1108 case kCondA:
1109 false_high_cond = kCondB;
1110 break;
1111 case kCondAE:
1112 true_high_cond = kCondA;
1113 break;
Mark Mendellc4701932015-04-10 13:18:51 -04001114 }
1115
1116 if (right.IsConstant()) {
1117 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001118 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001119 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001120
1121 if (val_high == 0) {
1122 __ testl(left_high, left_high);
1123 } else {
1124 __ cmpl(left_high, Immediate(val_high));
1125 }
1126 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001127 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001128 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001129 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001130 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001131 __ j(X86Condition(true_high_cond), true_label);
1132 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001133 }
1134 // Must be equal high, so compare the lows.
1135 if (val_low == 0) {
1136 __ testl(left_low, left_low);
1137 } else {
1138 __ cmpl(left_low, Immediate(val_low));
1139 }
1140 } else {
Mark Mendellc4701932015-04-10 13:18:51 -04001141 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001142 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001143
1144 __ cmpl(left_high, right_high);
1145 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001146 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001147 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001148 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001149 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001150 __ j(X86Condition(true_high_cond), true_label);
1151 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001152 }
1153 // Must be equal high, so compare the lows.
1154 __ cmpl(left_low, right_low);
1155 }
1156 // The last comparison might be unsigned.
1157 __ j(final_condition, true_label);
1158}
1159
1160void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
1161 HCondition* condition,
1162 Label* true_target,
1163 Label* false_target,
1164 Label* always_true_target) {
1165 LocationSummary* locations = condition->GetLocations();
1166 Location left = locations->InAt(0);
1167 Location right = locations->InAt(1);
1168
1169 // We don't want true_target as a nullptr.
1170 if (true_target == nullptr) {
1171 true_target = always_true_target;
1172 }
1173 bool falls_through = (false_target == nullptr);
1174
1175 // FP compares don't like null false_targets.
1176 if (false_target == nullptr) {
1177 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1178 }
1179
1180 Primitive::Type type = condition->InputAt(0)->GetType();
1181 switch (type) {
1182 case Primitive::kPrimLong:
1183 GenerateLongComparesAndJumps(condition, true_target, false_target);
1184 break;
1185 case Primitive::kPrimFloat:
Mark Mendellc4701932015-04-10 13:18:51 -04001186 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1187 GenerateFPJumps(condition, true_target, false_target);
1188 break;
1189 case Primitive::kPrimDouble:
Mark Mendellc4701932015-04-10 13:18:51 -04001190 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1191 GenerateFPJumps(condition, true_target, false_target);
1192 break;
1193 default:
1194 LOG(FATAL) << "Unexpected compare type " << type;
1195 }
1196
1197 if (!falls_through) {
1198 __ jmp(false_target);
1199 }
1200}
1201
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001202void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
1203 Label* true_target,
1204 Label* false_target,
1205 Label* always_true_target) {
1206 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001207 if (cond->IsIntConstant()) {
1208 // Constant condition, statically compared against 1.
1209 int32_t cond_value = cond->AsIntConstant()->GetValue();
1210 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001211 if (always_true_target != nullptr) {
1212 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001213 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001214 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001215 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001216 DCHECK_EQ(cond_value, 0);
1217 }
1218 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001219 HCondition* condition = cond->AsCondition();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001220 bool is_materialized =
Mark Mendellb8b97692015-05-22 16:58:19 -04001221 condition == nullptr || condition->NeedsMaterialization();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001222 // Moves do not affect the eflags register, so if the condition is
1223 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001224 // again. We can't use the eflags on long/FP conditions if they are
1225 // materialized due to the complex branching.
Mark Mendellb8b97692015-05-22 16:58:19 -04001226 Primitive::Type type = (condition != nullptr)
1227 ? cond->InputAt(0)->GetType()
1228 : Primitive::kPrimInt;
1229 bool eflags_set = condition != nullptr
1230 && condition->IsBeforeWhenDisregardMoves(instruction)
Roland Levillain4fa13f62015-07-06 18:11:54 +01001231 && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
Mark Mendellb8b97692015-05-22 16:58:19 -04001232 // Can we optimize the jump if we know that the next block is the true case?
1233 bool can_jump_to_false = CanReverseCondition(always_true_target, false_target, condition);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001234 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001235 if (!eflags_set) {
1236 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001237 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001238 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001239 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001240 } else {
1241 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
1242 }
Mark Mendellb8b97692015-05-22 16:58:19 -04001243 if (can_jump_to_false) {
1244 __ j(kEqual, false_target);
1245 return;
1246 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001247 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001248 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001249 if (can_jump_to_false) {
1250 __ j(X86Condition(condition->GetOppositeCondition()), false_target);
1251 return;
1252 }
1253 __ j(X86Condition(condition->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001254 }
1255 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001256 // Condition has not been materialized, use its inputs as the
1257 // comparison and its condition as the branch condition.
1258
Mark Mendellc4701932015-04-10 13:18:51 -04001259 // Is this a long or FP comparison that has been folded into the HCondition?
1260 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1261 // Generate the comparison directly.
1262 GenerateCompareTestAndBranch(instruction->AsIf(),
Mark Mendellb8b97692015-05-22 16:58:19 -04001263 condition,
Mark Mendellc4701932015-04-10 13:18:51 -04001264 true_target,
1265 false_target,
1266 always_true_target);
1267 return;
1268 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001269
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001270 Location lhs = cond->GetLocations()->InAt(0);
1271 Location rhs = cond->GetLocations()->InAt(1);
1272 // LHS is guaranteed to be in a register (see
1273 // LocationsBuilderX86::VisitCondition).
1274 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001275 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001276 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +01001277 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001278 if (constant == 0) {
1279 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1280 } else {
1281 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1282 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001283 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001284 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001285 }
Mark Mendellb8b97692015-05-22 16:58:19 -04001286
1287 if (can_jump_to_false) {
1288 __ j(X86Condition(condition->GetOppositeCondition()), false_target);
1289 return;
1290 }
1291
1292 __ j(X86Condition(condition->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001293 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001294 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001295 if (false_target != nullptr) {
1296 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001297 }
1298}
1299
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001300void LocationsBuilderX86::VisitIf(HIf* if_instr) {
1301 LocationSummary* locations =
1302 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1303 HInstruction* cond = if_instr->InputAt(0);
1304 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1305 locations->SetInAt(0, Location::Any());
1306 }
1307}
1308
1309void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
1310 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1311 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1312 Label* always_true_target = true_target;
1313 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1314 if_instr->IfTrueSuccessor())) {
1315 always_true_target = nullptr;
1316 }
1317 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1318 if_instr->IfFalseSuccessor())) {
1319 false_target = nullptr;
1320 }
1321 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1322}
1323
1324void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
1325 LocationSummary* locations = new (GetGraph()->GetArena())
1326 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1327 HInstruction* cond = deoptimize->InputAt(0);
Aart Bikbb245d12015-10-19 11:05:03 -07001328 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001329 locations->SetInAt(0, Location::Any());
1330 }
1331}
1332
1333void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001334 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001335 DeoptimizationSlowPathX86(deoptimize);
1336 codegen_->AddSlowPath(slow_path);
1337 Label* slow_path_entry = slow_path->GetEntryLabel();
1338 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1339}
1340
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001341void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001342 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001343}
1344
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001345void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
1346 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001347}
1348
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001349void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001350 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001351}
1352
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001353void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001354 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001355}
1356
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001357void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001358 LocationSummary* locations =
1359 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001360 switch (store->InputAt(1)->GetType()) {
1361 case Primitive::kPrimBoolean:
1362 case Primitive::kPrimByte:
1363 case Primitive::kPrimChar:
1364 case Primitive::kPrimShort:
1365 case Primitive::kPrimInt:
1366 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001367 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001368 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1369 break;
1370
1371 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001372 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001373 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1374 break;
1375
1376 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001377 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001378 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001379}
1380
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001381void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001382}
1383
Roland Levillain0d37cd02015-05-27 16:39:19 +01001384void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001385 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001386 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001387 // Handle the long/FP comparisons made in instruction simplification.
1388 switch (cond->InputAt(0)->GetType()) {
1389 case Primitive::kPrimLong: {
1390 locations->SetInAt(0, Location::RequiresRegister());
1391 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1392 if (cond->NeedsMaterialization()) {
1393 locations->SetOut(Location::RequiresRegister());
1394 }
1395 break;
1396 }
1397 case Primitive::kPrimFloat:
1398 case Primitive::kPrimDouble: {
1399 locations->SetInAt(0, Location::RequiresFpuRegister());
1400 locations->SetInAt(1, Location::RequiresFpuRegister());
1401 if (cond->NeedsMaterialization()) {
1402 locations->SetOut(Location::RequiresRegister());
1403 }
1404 break;
1405 }
1406 default:
1407 locations->SetInAt(0, Location::RequiresRegister());
1408 locations->SetInAt(1, Location::Any());
1409 if (cond->NeedsMaterialization()) {
1410 // We need a byte register.
1411 locations->SetOut(Location::RegisterLocation(ECX));
1412 }
1413 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001414 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001415}
1416
Roland Levillain0d37cd02015-05-27 16:39:19 +01001417void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001418 if (!cond->NeedsMaterialization()) {
1419 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001420 }
Mark Mendellc4701932015-04-10 13:18:51 -04001421
1422 LocationSummary* locations = cond->GetLocations();
1423 Location lhs = locations->InAt(0);
1424 Location rhs = locations->InAt(1);
1425 Register reg = locations->Out().AsRegister<Register>();
1426 Label true_label, false_label;
1427
1428 switch (cond->InputAt(0)->GetType()) {
1429 default: {
1430 // Integer case.
1431
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01001432 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04001433 __ xorl(reg, reg);
1434
1435 if (rhs.IsRegister()) {
1436 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1437 } else if (rhs.IsConstant()) {
1438 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1439 if (constant == 0) {
1440 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1441 } else {
1442 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1443 }
1444 } else {
1445 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1446 }
Aart Bike9f37602015-10-09 11:15:55 -07001447 __ setb(X86Condition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001448 return;
1449 }
1450 case Primitive::kPrimLong:
1451 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1452 break;
1453 case Primitive::kPrimFloat:
1454 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1455 GenerateFPJumps(cond, &true_label, &false_label);
1456 break;
1457 case Primitive::kPrimDouble:
1458 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1459 GenerateFPJumps(cond, &true_label, &false_label);
1460 break;
1461 }
1462
1463 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001464 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001465
Roland Levillain4fa13f62015-07-06 18:11:54 +01001466 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001467 __ Bind(&false_label);
1468 __ xorl(reg, reg);
1469 __ jmp(&done_label);
1470
Roland Levillain4fa13f62015-07-06 18:11:54 +01001471 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001472 __ Bind(&true_label);
1473 __ movl(reg, Immediate(1));
1474 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001475}
1476
1477void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1478 VisitCondition(comp);
1479}
1480
1481void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1482 VisitCondition(comp);
1483}
1484
1485void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1486 VisitCondition(comp);
1487}
1488
1489void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1490 VisitCondition(comp);
1491}
1492
1493void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1494 VisitCondition(comp);
1495}
1496
1497void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1498 VisitCondition(comp);
1499}
1500
1501void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1502 VisitCondition(comp);
1503}
1504
1505void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1506 VisitCondition(comp);
1507}
1508
1509void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1510 VisitCondition(comp);
1511}
1512
1513void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1514 VisitCondition(comp);
1515}
1516
1517void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1518 VisitCondition(comp);
1519}
1520
1521void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1522 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001523}
1524
Aart Bike9f37602015-10-09 11:15:55 -07001525void LocationsBuilderX86::VisitBelow(HBelow* comp) {
1526 VisitCondition(comp);
1527}
1528
1529void InstructionCodeGeneratorX86::VisitBelow(HBelow* comp) {
1530 VisitCondition(comp);
1531}
1532
1533void LocationsBuilderX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
1534 VisitCondition(comp);
1535}
1536
1537void InstructionCodeGeneratorX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
1538 VisitCondition(comp);
1539}
1540
1541void LocationsBuilderX86::VisitAbove(HAbove* comp) {
1542 VisitCondition(comp);
1543}
1544
1545void InstructionCodeGeneratorX86::VisitAbove(HAbove* comp) {
1546 VisitCondition(comp);
1547}
1548
1549void LocationsBuilderX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
1550 VisitCondition(comp);
1551}
1552
1553void InstructionCodeGeneratorX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
1554 VisitCondition(comp);
1555}
1556
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001557void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001558 LocationSummary* locations =
1559 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001560 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001561}
1562
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001563void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001564 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001565}
1566
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001567void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1568 LocationSummary* locations =
1569 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1570 locations->SetOut(Location::ConstantLocation(constant));
1571}
1572
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001573void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001574 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001575}
1576
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001577void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001578 LocationSummary* locations =
1579 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001580 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001581}
1582
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001583void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001584 // Will be generated at use site.
1585}
1586
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001587void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1588 LocationSummary* locations =
1589 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1590 locations->SetOut(Location::ConstantLocation(constant));
1591}
1592
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001593void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001594 // Will be generated at use site.
1595}
1596
1597void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1598 LocationSummary* locations =
1599 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1600 locations->SetOut(Location::ConstantLocation(constant));
1601}
1602
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001603void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001604 // Will be generated at use site.
1605}
1606
Calin Juravle27df7582015-04-17 19:12:31 +01001607void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1608 memory_barrier->SetLocations(nullptr);
1609}
1610
1611void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1612 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1613}
1614
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001615void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001616 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001617}
1618
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001619void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001620 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001621}
1622
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001623void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001624 LocationSummary* locations =
1625 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001626 switch (ret->InputAt(0)->GetType()) {
1627 case Primitive::kPrimBoolean:
1628 case Primitive::kPrimByte:
1629 case Primitive::kPrimChar:
1630 case Primitive::kPrimShort:
1631 case Primitive::kPrimInt:
1632 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001633 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001634 break;
1635
1636 case Primitive::kPrimLong:
1637 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001638 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001639 break;
1640
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001641 case Primitive::kPrimFloat:
1642 case Primitive::kPrimDouble:
1643 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001644 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001645 break;
1646
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001647 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001648 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001649 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001650}
1651
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001652void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001653 if (kIsDebugBuild) {
1654 switch (ret->InputAt(0)->GetType()) {
1655 case Primitive::kPrimBoolean:
1656 case Primitive::kPrimByte:
1657 case Primitive::kPrimChar:
1658 case Primitive::kPrimShort:
1659 case Primitive::kPrimInt:
1660 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001661 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001662 break;
1663
1664 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001665 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1666 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001667 break;
1668
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001669 case Primitive::kPrimFloat:
1670 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001671 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001672 break;
1673
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001674 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001675 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001676 }
1677 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001678 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001679}
1680
Calin Juravle175dc732015-08-25 15:42:32 +01001681void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1682 // The trampoline uses the same calling convention as dex calling conventions,
1683 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1684 // the method_idx.
1685 HandleInvoke(invoke);
1686}
1687
1688void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1689 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1690}
1691
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001692void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001693 // When we do not run baseline, explicit clinit checks triggered by static
1694 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1695 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001696
Mark Mendellfb8d2792015-03-31 22:16:59 -04001697 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001698 if (intrinsic.TryDispatch(invoke)) {
1699 return;
1700 }
1701
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001702 HandleInvoke(invoke);
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001703
1704 if (codegen_->IsBaseline()) {
1705 // Baseline does not have enough registers if the current method also
1706 // needs a register. We therefore do not require a register for it, and let
1707 // the code generation of the invoke handle it.
1708 LocationSummary* locations = invoke->GetLocations();
1709 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
1710 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
1711 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
1712 }
1713 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001714}
1715
Mark Mendell09ed1a32015-03-25 08:30:06 -04001716static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1717 if (invoke->GetLocations()->Intrinsified()) {
1718 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1719 intrinsic.Dispatch(invoke);
1720 return true;
1721 }
1722 return false;
1723}
1724
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001725void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001726 // When we do not run baseline, explicit clinit checks triggered by static
1727 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1728 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001729
Mark Mendell09ed1a32015-03-25 08:30:06 -04001730 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1731 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001732 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001733
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001734 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001735 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001736 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001737 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001738}
1739
1740void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1741 HandleInvoke(invoke);
1742}
1743
1744void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001745 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001746 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001747}
1748
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001749void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001750 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1751 return;
1752 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001753
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001754 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001755 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001756 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001757}
1758
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001759void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1760 HandleInvoke(invoke);
1761 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001762 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001763}
1764
1765void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1766 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001767 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001768 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1769 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001770 LocationSummary* locations = invoke->GetLocations();
1771 Location receiver = locations->InAt(0);
1772 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1773
1774 // Set the hidden argument.
1775 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001776 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001777
1778 // temp = object->GetClass();
1779 if (receiver.IsStackSlot()) {
1780 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1781 __ movl(temp, Address(temp, class_offset));
1782 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001783 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001784 }
Roland Levillain4d027112015-07-01 15:41:14 +01001785 codegen_->MaybeRecordImplicitNullCheck(invoke);
1786 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001787 // temp = temp->GetImtEntryAt(method_offset);
1788 __ movl(temp, Address(temp, method_offset));
1789 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001790 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001791 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001792
1793 DCHECK(!codegen_->IsLeafMethod());
1794 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1795}
1796
Roland Levillain88cb1752014-10-20 16:36:47 +01001797void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1798 LocationSummary* locations =
1799 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1800 switch (neg->GetResultType()) {
1801 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001802 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001803 locations->SetInAt(0, Location::RequiresRegister());
1804 locations->SetOut(Location::SameAsFirstInput());
1805 break;
1806
Roland Levillain88cb1752014-10-20 16:36:47 +01001807 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001808 locations->SetInAt(0, Location::RequiresFpuRegister());
1809 locations->SetOut(Location::SameAsFirstInput());
1810 locations->AddTemp(Location::RequiresRegister());
1811 locations->AddTemp(Location::RequiresFpuRegister());
1812 break;
1813
Roland Levillain88cb1752014-10-20 16:36:47 +01001814 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001815 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001816 locations->SetOut(Location::SameAsFirstInput());
1817 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001818 break;
1819
1820 default:
1821 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1822 }
1823}
1824
1825void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1826 LocationSummary* locations = neg->GetLocations();
1827 Location out = locations->Out();
1828 Location in = locations->InAt(0);
1829 switch (neg->GetResultType()) {
1830 case Primitive::kPrimInt:
1831 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001832 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001833 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001834 break;
1835
1836 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001837 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001838 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001839 __ negl(out.AsRegisterPairLow<Register>());
1840 // Negation is similar to subtraction from zero. The least
1841 // significant byte triggers a borrow when it is different from
1842 // zero; to take it into account, add 1 to the most significant
1843 // byte if the carry flag (CF) is set to 1 after the first NEGL
1844 // operation.
1845 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1846 __ negl(out.AsRegisterPairHigh<Register>());
1847 break;
1848
Roland Levillain5368c212014-11-27 15:03:41 +00001849 case Primitive::kPrimFloat: {
1850 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001851 Register constant = locations->GetTemp(0).AsRegister<Register>();
1852 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001853 // Implement float negation with an exclusive or with value
1854 // 0x80000000 (mask for bit 31, representing the sign of a
1855 // single-precision floating-point number).
1856 __ movl(constant, Immediate(INT32_C(0x80000000)));
1857 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001858 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001859 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001860 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001861
Roland Levillain5368c212014-11-27 15:03:41 +00001862 case Primitive::kPrimDouble: {
1863 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001864 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001865 // Implement double negation with an exclusive or with value
1866 // 0x8000000000000000 (mask for bit 63, representing the sign of
1867 // a double-precision floating-point number).
1868 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001869 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001870 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001871 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001872
1873 default:
1874 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1875 }
1876}
1877
Roland Levillaindff1f282014-11-05 14:15:05 +00001878void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001879 Primitive::Type result_type = conversion->GetResultType();
1880 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001881 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001882
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001883 // The float-to-long and double-to-long type conversions rely on a
1884 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001885 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001886 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1887 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001888 ? LocationSummary::kCall
1889 : LocationSummary::kNoCall;
1890 LocationSummary* locations =
1891 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1892
David Brazdilb2bd1c52015-03-25 11:17:37 +00001893 // The Java language does not allow treating boolean as an integral type but
1894 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001895
Roland Levillaindff1f282014-11-05 14:15:05 +00001896 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001897 case Primitive::kPrimByte:
1898 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001899 case Primitive::kPrimBoolean:
1900 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001901 case Primitive::kPrimShort:
1902 case Primitive::kPrimInt:
1903 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001904 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001905 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1906 // Make the output overlap to please the register allocator. This greatly simplifies
1907 // the validation of the linear scan implementation
1908 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001909 break;
1910
1911 default:
1912 LOG(FATAL) << "Unexpected type conversion from " << input_type
1913 << " to " << result_type;
1914 }
1915 break;
1916
Roland Levillain01a8d712014-11-14 16:27:39 +00001917 case Primitive::kPrimShort:
1918 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001919 case Primitive::kPrimBoolean:
1920 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001921 case Primitive::kPrimByte:
1922 case Primitive::kPrimInt:
1923 case Primitive::kPrimChar:
1924 // Processing a Dex `int-to-short' instruction.
1925 locations->SetInAt(0, Location::Any());
1926 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1927 break;
1928
1929 default:
1930 LOG(FATAL) << "Unexpected type conversion from " << input_type
1931 << " to " << result_type;
1932 }
1933 break;
1934
Roland Levillain946e1432014-11-11 17:35:19 +00001935 case Primitive::kPrimInt:
1936 switch (input_type) {
1937 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001938 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001939 locations->SetInAt(0, Location::Any());
1940 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1941 break;
1942
1943 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001944 // Processing a Dex `float-to-int' instruction.
1945 locations->SetInAt(0, Location::RequiresFpuRegister());
1946 locations->SetOut(Location::RequiresRegister());
1947 locations->AddTemp(Location::RequiresFpuRegister());
1948 break;
1949
Roland Levillain946e1432014-11-11 17:35:19 +00001950 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001951 // Processing a Dex `double-to-int' instruction.
1952 locations->SetInAt(0, Location::RequiresFpuRegister());
1953 locations->SetOut(Location::RequiresRegister());
1954 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001955 break;
1956
1957 default:
1958 LOG(FATAL) << "Unexpected type conversion from " << input_type
1959 << " to " << result_type;
1960 }
1961 break;
1962
Roland Levillaindff1f282014-11-05 14:15:05 +00001963 case Primitive::kPrimLong:
1964 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001965 case Primitive::kPrimBoolean:
1966 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001967 case Primitive::kPrimByte:
1968 case Primitive::kPrimShort:
1969 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001970 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001971 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001972 locations->SetInAt(0, Location::RegisterLocation(EAX));
1973 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1974 break;
1975
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001976 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001977 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001978 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001979 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001980 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1981 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1982
Vladimir Marko949c91f2015-01-27 10:48:44 +00001983 // The runtime helper puts the result in EAX, EDX.
1984 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001985 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001986 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001987
1988 default:
1989 LOG(FATAL) << "Unexpected type conversion from " << input_type
1990 << " to " << result_type;
1991 }
1992 break;
1993
Roland Levillain981e4542014-11-14 11:47:14 +00001994 case Primitive::kPrimChar:
1995 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001996 case Primitive::kPrimBoolean:
1997 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001998 case Primitive::kPrimByte:
1999 case Primitive::kPrimShort:
2000 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002001 // Processing a Dex `int-to-char' instruction.
2002 locations->SetInAt(0, Location::Any());
2003 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2004 break;
2005
2006 default:
2007 LOG(FATAL) << "Unexpected type conversion from " << input_type
2008 << " to " << result_type;
2009 }
2010 break;
2011
Roland Levillaindff1f282014-11-05 14:15:05 +00002012 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002013 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002014 case Primitive::kPrimBoolean:
2015 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002016 case Primitive::kPrimByte:
2017 case Primitive::kPrimShort:
2018 case Primitive::kPrimInt:
2019 case Primitive::kPrimChar:
2020 // Processing a Dex `int-to-float' instruction.
2021 locations->SetInAt(0, Location::RequiresRegister());
2022 locations->SetOut(Location::RequiresFpuRegister());
2023 break;
2024
2025 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002026 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002027 locations->SetInAt(0, Location::Any());
2028 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002029 break;
2030
Roland Levillaincff13742014-11-17 14:32:17 +00002031 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002032 // Processing a Dex `double-to-float' instruction.
2033 locations->SetInAt(0, Location::RequiresFpuRegister());
2034 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002035 break;
2036
2037 default:
2038 LOG(FATAL) << "Unexpected type conversion from " << input_type
2039 << " to " << result_type;
2040 };
2041 break;
2042
Roland Levillaindff1f282014-11-05 14:15:05 +00002043 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002044 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002045 case Primitive::kPrimBoolean:
2046 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002047 case Primitive::kPrimByte:
2048 case Primitive::kPrimShort:
2049 case Primitive::kPrimInt:
2050 case Primitive::kPrimChar:
2051 // Processing a Dex `int-to-double' instruction.
2052 locations->SetInAt(0, Location::RequiresRegister());
2053 locations->SetOut(Location::RequiresFpuRegister());
2054 break;
2055
2056 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002057 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002058 locations->SetInAt(0, Location::Any());
2059 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002060 break;
2061
Roland Levillaincff13742014-11-17 14:32:17 +00002062 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002063 // Processing a Dex `float-to-double' instruction.
2064 locations->SetInAt(0, Location::RequiresFpuRegister());
2065 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002066 break;
2067
2068 default:
2069 LOG(FATAL) << "Unexpected type conversion from " << input_type
2070 << " to " << result_type;
2071 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002072 break;
2073
2074 default:
2075 LOG(FATAL) << "Unexpected type conversion from " << input_type
2076 << " to " << result_type;
2077 }
2078}
2079
2080void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
2081 LocationSummary* locations = conversion->GetLocations();
2082 Location out = locations->Out();
2083 Location in = locations->InAt(0);
2084 Primitive::Type result_type = conversion->GetResultType();
2085 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002086 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002087 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002088 case Primitive::kPrimByte:
2089 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002090 case Primitive::kPrimBoolean:
2091 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002092 case Primitive::kPrimShort:
2093 case Primitive::kPrimInt:
2094 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002095 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002096 if (in.IsRegister()) {
2097 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002098 } else {
2099 DCHECK(in.GetConstant()->IsIntConstant());
2100 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
2101 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
2102 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00002103 break;
2104
2105 default:
2106 LOG(FATAL) << "Unexpected type conversion from " << input_type
2107 << " to " << result_type;
2108 }
2109 break;
2110
Roland Levillain01a8d712014-11-14 16:27:39 +00002111 case Primitive::kPrimShort:
2112 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002113 case Primitive::kPrimBoolean:
2114 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002115 case Primitive::kPrimByte:
2116 case Primitive::kPrimInt:
2117 case Primitive::kPrimChar:
2118 // Processing a Dex `int-to-short' instruction.
2119 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002120 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002121 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002122 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00002123 } else {
2124 DCHECK(in.GetConstant()->IsIntConstant());
2125 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002126 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00002127 }
2128 break;
2129
2130 default:
2131 LOG(FATAL) << "Unexpected type conversion from " << input_type
2132 << " to " << result_type;
2133 }
2134 break;
2135
Roland Levillain946e1432014-11-11 17:35:19 +00002136 case Primitive::kPrimInt:
2137 switch (input_type) {
2138 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002139 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002140 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002141 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002142 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002143 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00002144 } else {
2145 DCHECK(in.IsConstant());
2146 DCHECK(in.GetConstant()->IsLongConstant());
2147 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002148 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002149 }
2150 break;
2151
Roland Levillain3f8f9362014-12-02 17:45:01 +00002152 case Primitive::kPrimFloat: {
2153 // Processing a Dex `float-to-int' instruction.
2154 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2155 Register output = out.AsRegister<Register>();
2156 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002157 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002158
2159 __ movl(output, Immediate(kPrimIntMax));
2160 // temp = int-to-float(output)
2161 __ cvtsi2ss(temp, output);
2162 // if input >= temp goto done
2163 __ comiss(input, temp);
2164 __ j(kAboveEqual, &done);
2165 // if input == NaN goto nan
2166 __ j(kUnordered, &nan);
2167 // output = float-to-int-truncate(input)
2168 __ cvttss2si(output, input);
2169 __ jmp(&done);
2170 __ Bind(&nan);
2171 // output = 0
2172 __ xorl(output, output);
2173 __ Bind(&done);
2174 break;
2175 }
2176
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002177 case Primitive::kPrimDouble: {
2178 // Processing a Dex `double-to-int' instruction.
2179 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2180 Register output = out.AsRegister<Register>();
2181 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002182 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002183
2184 __ movl(output, Immediate(kPrimIntMax));
2185 // temp = int-to-double(output)
2186 __ cvtsi2sd(temp, output);
2187 // if input >= temp goto done
2188 __ comisd(input, temp);
2189 __ j(kAboveEqual, &done);
2190 // if input == NaN goto nan
2191 __ j(kUnordered, &nan);
2192 // output = double-to-int-truncate(input)
2193 __ cvttsd2si(output, input);
2194 __ jmp(&done);
2195 __ Bind(&nan);
2196 // output = 0
2197 __ xorl(output, output);
2198 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002199 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002200 }
Roland Levillain946e1432014-11-11 17:35:19 +00002201
2202 default:
2203 LOG(FATAL) << "Unexpected type conversion from " << input_type
2204 << " to " << result_type;
2205 }
2206 break;
2207
Roland Levillaindff1f282014-11-05 14:15:05 +00002208 case Primitive::kPrimLong:
2209 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002210 case Primitive::kPrimBoolean:
2211 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002212 case Primitive::kPrimByte:
2213 case Primitive::kPrimShort:
2214 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002215 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002216 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002217 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
2218 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002219 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00002220 __ cdq();
2221 break;
2222
2223 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002224 // Processing a Dex `float-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002225 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2226 conversion,
2227 conversion->GetDexPc(),
2228 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002229 break;
2230
Roland Levillaindff1f282014-11-05 14:15:05 +00002231 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002232 // Processing a Dex `double-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002233 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2234 conversion,
2235 conversion->GetDexPc(),
2236 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002237 break;
2238
2239 default:
2240 LOG(FATAL) << "Unexpected type conversion from " << input_type
2241 << " to " << result_type;
2242 }
2243 break;
2244
Roland Levillain981e4542014-11-14 11:47:14 +00002245 case Primitive::kPrimChar:
2246 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002247 case Primitive::kPrimBoolean:
2248 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002249 case Primitive::kPrimByte:
2250 case Primitive::kPrimShort:
2251 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002252 // Processing a Dex `Process a Dex `int-to-char'' instruction.
2253 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002254 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00002255 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002256 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00002257 } else {
2258 DCHECK(in.GetConstant()->IsIntConstant());
2259 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002260 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00002261 }
2262 break;
2263
2264 default:
2265 LOG(FATAL) << "Unexpected type conversion from " << input_type
2266 << " to " << result_type;
2267 }
2268 break;
2269
Roland Levillaindff1f282014-11-05 14:15:05 +00002270 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002271 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002272 case Primitive::kPrimBoolean:
2273 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002274 case Primitive::kPrimByte:
2275 case Primitive::kPrimShort:
2276 case Primitive::kPrimInt:
2277 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002278 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002279 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002280 break;
2281
Roland Levillain6d0e4832014-11-27 18:31:21 +00002282 case Primitive::kPrimLong: {
2283 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002284 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002285
Roland Levillain232ade02015-04-20 15:14:36 +01002286 // Create stack space for the call to
2287 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
2288 // TODO: enhance register allocator to ask for stack temporaries.
2289 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
2290 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2291 __ subl(ESP, Immediate(adjustment));
2292 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002293
Roland Levillain232ade02015-04-20 15:14:36 +01002294 // Load the value to the FP stack, using temporaries if needed.
2295 PushOntoFPStack(in, 0, adjustment, false, true);
2296
2297 if (out.IsStackSlot()) {
2298 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
2299 } else {
2300 __ fstps(Address(ESP, 0));
2301 Location stack_temp = Location::StackSlot(0);
2302 codegen_->Move32(out, stack_temp);
2303 }
2304
2305 // Remove the temporary stack space we allocated.
2306 if (adjustment != 0) {
2307 __ addl(ESP, Immediate(adjustment));
2308 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002309 break;
2310 }
2311
Roland Levillaincff13742014-11-17 14:32:17 +00002312 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002313 // Processing a Dex `double-to-float' instruction.
2314 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002315 break;
2316
2317 default:
2318 LOG(FATAL) << "Unexpected type conversion from " << input_type
2319 << " to " << result_type;
2320 };
2321 break;
2322
Roland Levillaindff1f282014-11-05 14:15:05 +00002323 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002324 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002325 case Primitive::kPrimBoolean:
2326 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002327 case Primitive::kPrimByte:
2328 case Primitive::kPrimShort:
2329 case Primitive::kPrimInt:
2330 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002331 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002332 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002333 break;
2334
Roland Levillain647b9ed2014-11-27 12:06:00 +00002335 case Primitive::kPrimLong: {
2336 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002337 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00002338
Roland Levillain232ade02015-04-20 15:14:36 +01002339 // Create stack space for the call to
2340 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
2341 // TODO: enhance register allocator to ask for stack temporaries.
2342 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
2343 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2344 __ subl(ESP, Immediate(adjustment));
2345 }
2346
2347 // Load the value to the FP stack, using temporaries if needed.
2348 PushOntoFPStack(in, 0, adjustment, false, true);
2349
2350 if (out.IsDoubleStackSlot()) {
2351 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
2352 } else {
2353 __ fstpl(Address(ESP, 0));
2354 Location stack_temp = Location::DoubleStackSlot(0);
2355 codegen_->Move64(out, stack_temp);
2356 }
2357
2358 // Remove the temporary stack space we allocated.
2359 if (adjustment != 0) {
2360 __ addl(ESP, Immediate(adjustment));
2361 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002362 break;
2363 }
2364
Roland Levillaincff13742014-11-17 14:32:17 +00002365 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002366 // Processing a Dex `float-to-double' instruction.
2367 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002368 break;
2369
2370 default:
2371 LOG(FATAL) << "Unexpected type conversion from " << input_type
2372 << " to " << result_type;
2373 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002374 break;
2375
2376 default:
2377 LOG(FATAL) << "Unexpected type conversion from " << input_type
2378 << " to " << result_type;
2379 }
2380}
2381
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002382void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002383 LocationSummary* locations =
2384 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002385 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002386 case Primitive::kPrimInt: {
2387 locations->SetInAt(0, Location::RequiresRegister());
2388 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2389 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2390 break;
2391 }
2392
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002393 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002394 locations->SetInAt(0, Location::RequiresRegister());
2395 locations->SetInAt(1, Location::Any());
2396 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002397 break;
2398 }
2399
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002400 case Primitive::kPrimFloat:
2401 case Primitive::kPrimDouble: {
2402 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002403 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002404 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002405 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002406 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002407
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002408 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002409 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2410 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002411 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002412}
2413
2414void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
2415 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002416 Location first = locations->InAt(0);
2417 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05002418 Location out = locations->Out();
2419
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002420 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002421 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002422 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002423 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2424 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002425 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2426 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05002427 } else {
2428 __ leal(out.AsRegister<Register>(), Address(
2429 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
2430 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002431 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002432 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
2433 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2434 __ addl(out.AsRegister<Register>(), Immediate(value));
2435 } else {
2436 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
2437 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002438 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05002439 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002440 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002441 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002442 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002443 }
2444
2445 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002446 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002447 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2448 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002449 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002450 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2451 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002452 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002453 } else {
2454 DCHECK(second.IsConstant()) << second;
2455 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2456 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2457 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002458 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002459 break;
2460 }
2461
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002462 case Primitive::kPrimFloat: {
2463 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002464 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002465 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2466 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2467 DCHECK(!const_area->NeedsMaterialization());
2468 __ addss(first.AsFpuRegister<XmmRegister>(),
2469 codegen_->LiteralFloatAddress(
2470 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2471 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2472 } else {
2473 DCHECK(second.IsStackSlot());
2474 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002475 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002476 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002477 }
2478
2479 case Primitive::kPrimDouble: {
2480 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002481 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002482 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2483 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2484 DCHECK(!const_area->NeedsMaterialization());
2485 __ addsd(first.AsFpuRegister<XmmRegister>(),
2486 codegen_->LiteralDoubleAddress(
2487 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2488 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2489 } else {
2490 DCHECK(second.IsDoubleStackSlot());
2491 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002492 }
2493 break;
2494 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002495
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002496 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002497 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002498 }
2499}
2500
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002501void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002502 LocationSummary* locations =
2503 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002504 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002505 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002506 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002507 locations->SetInAt(0, Location::RequiresRegister());
2508 locations->SetInAt(1, Location::Any());
2509 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002510 break;
2511 }
Calin Juravle11351682014-10-23 15:38:15 +01002512 case Primitive::kPrimFloat:
2513 case Primitive::kPrimDouble: {
2514 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002515 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002516 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002517 break;
Calin Juravle11351682014-10-23 15:38:15 +01002518 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002519
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002520 default:
Calin Juravle11351682014-10-23 15:38:15 +01002521 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002522 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002523}
2524
2525void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2526 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002527 Location first = locations->InAt(0);
2528 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002529 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002530 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002531 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002532 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002533 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002534 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002535 __ subl(first.AsRegister<Register>(),
2536 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002537 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002538 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002539 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002540 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002541 }
2542
2543 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002544 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002545 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2546 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002547 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002548 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002549 __ sbbl(first.AsRegisterPairHigh<Register>(),
2550 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002551 } else {
2552 DCHECK(second.IsConstant()) << second;
2553 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2554 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2555 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002556 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002557 break;
2558 }
2559
Calin Juravle11351682014-10-23 15:38:15 +01002560 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002561 if (second.IsFpuRegister()) {
2562 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2563 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2564 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2565 DCHECK(!const_area->NeedsMaterialization());
2566 __ subss(first.AsFpuRegister<XmmRegister>(),
2567 codegen_->LiteralFloatAddress(
2568 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2569 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2570 } else {
2571 DCHECK(second.IsStackSlot());
2572 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2573 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002574 break;
Calin Juravle11351682014-10-23 15:38:15 +01002575 }
2576
2577 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002578 if (second.IsFpuRegister()) {
2579 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2580 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2581 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2582 DCHECK(!const_area->NeedsMaterialization());
2583 __ subsd(first.AsFpuRegister<XmmRegister>(),
2584 codegen_->LiteralDoubleAddress(
2585 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2586 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2587 } else {
2588 DCHECK(second.IsDoubleStackSlot());
2589 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2590 }
Calin Juravle11351682014-10-23 15:38:15 +01002591 break;
2592 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002593
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002594 default:
Calin Juravle11351682014-10-23 15:38:15 +01002595 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002596 }
2597}
2598
Calin Juravle34bacdf2014-10-07 20:23:36 +01002599void LocationsBuilderX86::VisitMul(HMul* mul) {
2600 LocationSummary* locations =
2601 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2602 switch (mul->GetResultType()) {
2603 case Primitive::kPrimInt:
2604 locations->SetInAt(0, Location::RequiresRegister());
2605 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002606 if (mul->InputAt(1)->IsIntConstant()) {
2607 // Can use 3 operand multiply.
2608 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2609 } else {
2610 locations->SetOut(Location::SameAsFirstInput());
2611 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002612 break;
2613 case Primitive::kPrimLong: {
2614 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002615 locations->SetInAt(1, Location::Any());
2616 locations->SetOut(Location::SameAsFirstInput());
2617 // Needed for imul on 32bits with 64bits output.
2618 locations->AddTemp(Location::RegisterLocation(EAX));
2619 locations->AddTemp(Location::RegisterLocation(EDX));
2620 break;
2621 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002622 case Primitive::kPrimFloat:
2623 case Primitive::kPrimDouble: {
2624 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002625 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002626 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002627 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002628 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002629
2630 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002631 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002632 }
2633}
2634
2635void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2636 LocationSummary* locations = mul->GetLocations();
2637 Location first = locations->InAt(0);
2638 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002639 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002640
2641 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002642 case Primitive::kPrimInt:
2643 // The constant may have ended up in a register, so test explicitly to avoid
2644 // problems where the output may not be the same as the first operand.
2645 if (mul->InputAt(1)->IsIntConstant()) {
2646 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2647 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
2648 } else if (second.IsRegister()) {
2649 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002650 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002651 } else {
2652 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002653 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002654 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002655 }
2656 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002657
2658 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002659 Register in1_hi = first.AsRegisterPairHigh<Register>();
2660 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002661 Register eax = locations->GetTemp(0).AsRegister<Register>();
2662 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002663
2664 DCHECK_EQ(EAX, eax);
2665 DCHECK_EQ(EDX, edx);
2666
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002667 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002668 // output: in1
2669 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2670 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2671 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002672 if (second.IsConstant()) {
2673 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002674
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002675 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2676 int32_t low_value = Low32Bits(value);
2677 int32_t high_value = High32Bits(value);
2678 Immediate low(low_value);
2679 Immediate high(high_value);
2680
2681 __ movl(eax, high);
2682 // eax <- in1.lo * in2.hi
2683 __ imull(eax, in1_lo);
2684 // in1.hi <- in1.hi * in2.lo
2685 __ imull(in1_hi, low);
2686 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2687 __ addl(in1_hi, eax);
2688 // move in2_lo to eax to prepare for double precision
2689 __ movl(eax, low);
2690 // edx:eax <- in1.lo * in2.lo
2691 __ mull(in1_lo);
2692 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2693 __ addl(in1_hi, edx);
2694 // in1.lo <- (in1.lo * in2.lo)[31:0];
2695 __ movl(in1_lo, eax);
2696 } else if (second.IsRegisterPair()) {
2697 Register in2_hi = second.AsRegisterPairHigh<Register>();
2698 Register in2_lo = second.AsRegisterPairLow<Register>();
2699
2700 __ movl(eax, in2_hi);
2701 // eax <- in1.lo * in2.hi
2702 __ imull(eax, in1_lo);
2703 // in1.hi <- in1.hi * in2.lo
2704 __ imull(in1_hi, in2_lo);
2705 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2706 __ addl(in1_hi, eax);
2707 // move in1_lo to eax to prepare for double precision
2708 __ movl(eax, in1_lo);
2709 // edx:eax <- in1.lo * in2.lo
2710 __ mull(in2_lo);
2711 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2712 __ addl(in1_hi, edx);
2713 // in1.lo <- (in1.lo * in2.lo)[31:0];
2714 __ movl(in1_lo, eax);
2715 } else {
2716 DCHECK(second.IsDoubleStackSlot()) << second;
2717 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2718 Address in2_lo(ESP, second.GetStackIndex());
2719
2720 __ movl(eax, in2_hi);
2721 // eax <- in1.lo * in2.hi
2722 __ imull(eax, in1_lo);
2723 // in1.hi <- in1.hi * in2.lo
2724 __ imull(in1_hi, in2_lo);
2725 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2726 __ addl(in1_hi, eax);
2727 // move in1_lo to eax to prepare for double precision
2728 __ movl(eax, in1_lo);
2729 // edx:eax <- in1.lo * in2.lo
2730 __ mull(in2_lo);
2731 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2732 __ addl(in1_hi, edx);
2733 // in1.lo <- (in1.lo * in2.lo)[31:0];
2734 __ movl(in1_lo, eax);
2735 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002736
2737 break;
2738 }
2739
Calin Juravleb5bfa962014-10-21 18:02:24 +01002740 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002741 DCHECK(first.Equals(locations->Out()));
2742 if (second.IsFpuRegister()) {
2743 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2744 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2745 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2746 DCHECK(!const_area->NeedsMaterialization());
2747 __ mulss(first.AsFpuRegister<XmmRegister>(),
2748 codegen_->LiteralFloatAddress(
2749 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2750 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2751 } else {
2752 DCHECK(second.IsStackSlot());
2753 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2754 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002755 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002756 }
2757
2758 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002759 DCHECK(first.Equals(locations->Out()));
2760 if (second.IsFpuRegister()) {
2761 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2762 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2763 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2764 DCHECK(!const_area->NeedsMaterialization());
2765 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2766 codegen_->LiteralDoubleAddress(
2767 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2768 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2769 } else {
2770 DCHECK(second.IsDoubleStackSlot());
2771 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2772 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002773 break;
2774 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002775
2776 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002777 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002778 }
2779}
2780
Roland Levillain232ade02015-04-20 15:14:36 +01002781void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2782 uint32_t temp_offset,
2783 uint32_t stack_adjustment,
2784 bool is_fp,
2785 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002786 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002787 DCHECK(!is_wide);
2788 if (is_fp) {
2789 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2790 } else {
2791 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2792 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002793 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002794 DCHECK(is_wide);
2795 if (is_fp) {
2796 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2797 } else {
2798 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2799 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002800 } else {
2801 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002802 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002803 Location stack_temp = Location::StackSlot(temp_offset);
2804 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002805 if (is_fp) {
2806 __ flds(Address(ESP, temp_offset));
2807 } else {
2808 __ filds(Address(ESP, temp_offset));
2809 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002810 } else {
2811 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2812 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002813 if (is_fp) {
2814 __ fldl(Address(ESP, temp_offset));
2815 } else {
2816 __ fildl(Address(ESP, temp_offset));
2817 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002818 }
2819 }
2820}
2821
2822void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2823 Primitive::Type type = rem->GetResultType();
2824 bool is_float = type == Primitive::kPrimFloat;
2825 size_t elem_size = Primitive::ComponentSize(type);
2826 LocationSummary* locations = rem->GetLocations();
2827 Location first = locations->InAt(0);
2828 Location second = locations->InAt(1);
2829 Location out = locations->Out();
2830
2831 // Create stack space for 2 elements.
2832 // TODO: enhance register allocator to ask for stack temporaries.
2833 __ subl(ESP, Immediate(2 * elem_size));
2834
2835 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002836 const bool is_wide = !is_float;
2837 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2838 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002839
2840 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002841 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002842 __ Bind(&retry);
2843 __ fprem();
2844
2845 // Move FP status to AX.
2846 __ fstsw();
2847
2848 // And see if the argument reduction is complete. This is signaled by the
2849 // C2 FPU flag bit set to 0.
2850 __ andl(EAX, Immediate(kC2ConditionMask));
2851 __ j(kNotEqual, &retry);
2852
2853 // We have settled on the final value. Retrieve it into an XMM register.
2854 // Store FP top of stack to real stack.
2855 if (is_float) {
2856 __ fsts(Address(ESP, 0));
2857 } else {
2858 __ fstl(Address(ESP, 0));
2859 }
2860
2861 // Pop the 2 items from the FP stack.
2862 __ fucompp();
2863
2864 // Load the value from the stack into an XMM register.
2865 DCHECK(out.IsFpuRegister()) << out;
2866 if (is_float) {
2867 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2868 } else {
2869 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2870 }
2871
2872 // And remove the temporary stack space we allocated.
2873 __ addl(ESP, Immediate(2 * elem_size));
2874}
2875
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002876
2877void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2878 DCHECK(instruction->IsDiv() || instruction->IsRem());
2879
2880 LocationSummary* locations = instruction->GetLocations();
2881 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002882 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002883
2884 Register out_register = locations->Out().AsRegister<Register>();
2885 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002886 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002887
2888 DCHECK(imm == 1 || imm == -1);
2889
2890 if (instruction->IsRem()) {
2891 __ xorl(out_register, out_register);
2892 } else {
2893 __ movl(out_register, input_register);
2894 if (imm == -1) {
2895 __ negl(out_register);
2896 }
2897 }
2898}
2899
2900
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002901void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002902 LocationSummary* locations = instruction->GetLocations();
2903
2904 Register out_register = locations->Out().AsRegister<Register>();
2905 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002906 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002907
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002908 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002909 Register num = locations->GetTemp(0).AsRegister<Register>();
2910
2911 __ leal(num, Address(input_register, std::abs(imm) - 1));
2912 __ testl(input_register, input_register);
2913 __ cmovl(kGreaterEqual, num, input_register);
2914 int shift = CTZ(imm);
2915 __ sarl(num, Immediate(shift));
2916
2917 if (imm < 0) {
2918 __ negl(num);
2919 }
2920
2921 __ movl(out_register, num);
2922}
2923
2924void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2925 DCHECK(instruction->IsDiv() || instruction->IsRem());
2926
2927 LocationSummary* locations = instruction->GetLocations();
2928 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2929
2930 Register eax = locations->InAt(0).AsRegister<Register>();
2931 Register out = locations->Out().AsRegister<Register>();
2932 Register num;
2933 Register edx;
2934
2935 if (instruction->IsDiv()) {
2936 edx = locations->GetTemp(0).AsRegister<Register>();
2937 num = locations->GetTemp(1).AsRegister<Register>();
2938 } else {
2939 edx = locations->Out().AsRegister<Register>();
2940 num = locations->GetTemp(0).AsRegister<Register>();
2941 }
2942
2943 DCHECK_EQ(EAX, eax);
2944 DCHECK_EQ(EDX, edx);
2945 if (instruction->IsDiv()) {
2946 DCHECK_EQ(EAX, out);
2947 } else {
2948 DCHECK_EQ(EDX, out);
2949 }
2950
2951 int64_t magic;
2952 int shift;
2953 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2954
Mark Mendell0c9497d2015-08-21 09:30:05 -04002955 NearLabel ndiv;
2956 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002957 // If numerator is 0, the result is 0, no computation needed.
2958 __ testl(eax, eax);
2959 __ j(kNotEqual, &ndiv);
2960
2961 __ xorl(out, out);
2962 __ jmp(&end);
2963
2964 __ Bind(&ndiv);
2965
2966 // Save the numerator.
2967 __ movl(num, eax);
2968
2969 // EAX = magic
2970 __ movl(eax, Immediate(magic));
2971
2972 // EDX:EAX = magic * numerator
2973 __ imull(num);
2974
2975 if (imm > 0 && magic < 0) {
2976 // EDX += num
2977 __ addl(edx, num);
2978 } else if (imm < 0 && magic > 0) {
2979 __ subl(edx, num);
2980 }
2981
2982 // Shift if needed.
2983 if (shift != 0) {
2984 __ sarl(edx, Immediate(shift));
2985 }
2986
2987 // EDX += 1 if EDX < 0
2988 __ movl(eax, edx);
2989 __ shrl(edx, Immediate(31));
2990 __ addl(edx, eax);
2991
2992 if (instruction->IsRem()) {
2993 __ movl(eax, num);
2994 __ imull(edx, Immediate(imm));
2995 __ subl(eax, edx);
2996 __ movl(edx, eax);
2997 } else {
2998 __ movl(eax, edx);
2999 }
3000 __ Bind(&end);
3001}
3002
Calin Juravlebacfec32014-11-14 15:54:36 +00003003void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3004 DCHECK(instruction->IsDiv() || instruction->IsRem());
3005
3006 LocationSummary* locations = instruction->GetLocations();
3007 Location out = locations->Out();
3008 Location first = locations->InAt(0);
3009 Location second = locations->InAt(1);
3010 bool is_div = instruction->IsDiv();
3011
3012 switch (instruction->GetResultType()) {
3013 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003014 DCHECK_EQ(EAX, first.AsRegister<Register>());
3015 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00003016
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003017 if (instruction->InputAt(1)->IsIntConstant()) {
3018 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003019
3020 if (imm == 0) {
3021 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
3022 } else if (imm == 1 || imm == -1) {
3023 DivRemOneOrMinusOne(instruction);
3024 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003025 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003026 } else {
3027 DCHECK(imm <= -2 || imm >= 2);
3028 GenerateDivRemWithAnyConstant(instruction);
3029 }
3030 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003031 SlowPathCode* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00003032 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003033 is_div);
3034 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003035
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003036 Register second_reg = second.AsRegister<Register>();
3037 // 0x80000000/-1 triggers an arithmetic exception!
3038 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
3039 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00003040
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003041 __ cmpl(second_reg, Immediate(-1));
3042 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00003043
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003044 // edx:eax <- sign-extended of eax
3045 __ cdq();
3046 // eax = quotient, edx = remainder
3047 __ idivl(second_reg);
3048 __ Bind(slow_path->GetExitLabel());
3049 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003050 break;
3051 }
3052
3053 case Primitive::kPrimLong: {
3054 InvokeRuntimeCallingConvention calling_convention;
3055 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3056 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3057 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3058 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3059 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
3060 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
3061
3062 if (is_div) {
Alexandre Rames8158f282015-08-07 10:26:17 +01003063 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
3064 instruction,
3065 instruction->GetDexPc(),
3066 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003067 } else {
Alexandre Rames8158f282015-08-07 10:26:17 +01003068 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
3069 instruction,
3070 instruction->GetDexPc(),
3071 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003072 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003073 break;
3074 }
3075
3076 default:
3077 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
3078 }
3079}
3080
Calin Juravle7c4954d2014-10-28 16:57:40 +00003081void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003082 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003083 ? LocationSummary::kCall
3084 : LocationSummary::kNoCall;
3085 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3086
Calin Juravle7c4954d2014-10-28 16:57:40 +00003087 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003088 case Primitive::kPrimInt: {
3089 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003090 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003091 locations->SetOut(Location::SameAsFirstInput());
3092 // Intel uses edx:eax as the dividend.
3093 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003094 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3095 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
3096 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003097 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003098 locations->AddTemp(Location::RequiresRegister());
3099 }
Calin Juravled0d48522014-11-04 16:40:20 +00003100 break;
3101 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003102 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003103 InvokeRuntimeCallingConvention calling_convention;
3104 locations->SetInAt(0, Location::RegisterPairLocation(
3105 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3106 locations->SetInAt(1, Location::RegisterPairLocation(
3107 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3108 // Runtime helper puts the result in EAX, EDX.
3109 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00003110 break;
3111 }
3112 case Primitive::kPrimFloat:
3113 case Primitive::kPrimDouble: {
3114 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04003115 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003116 locations->SetOut(Location::SameAsFirstInput());
3117 break;
3118 }
3119
3120 default:
3121 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3122 }
3123}
3124
3125void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
3126 LocationSummary* locations = div->GetLocations();
3127 Location first = locations->InAt(0);
3128 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003129
3130 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003131 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00003132 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003133 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003134 break;
3135 }
3136
3137 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003138 if (second.IsFpuRegister()) {
3139 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3140 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3141 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3142 DCHECK(!const_area->NeedsMaterialization());
3143 __ divss(first.AsFpuRegister<XmmRegister>(),
3144 codegen_->LiteralFloatAddress(
3145 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3146 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3147 } else {
3148 DCHECK(second.IsStackSlot());
3149 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3150 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003151 break;
3152 }
3153
3154 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003155 if (second.IsFpuRegister()) {
3156 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3157 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3158 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3159 DCHECK(!const_area->NeedsMaterialization());
3160 __ divsd(first.AsFpuRegister<XmmRegister>(),
3161 codegen_->LiteralDoubleAddress(
3162 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3163 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3164 } else {
3165 DCHECK(second.IsDoubleStackSlot());
3166 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3167 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003168 break;
3169 }
3170
3171 default:
3172 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3173 }
3174}
3175
Calin Juravlebacfec32014-11-14 15:54:36 +00003176void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003177 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003178
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003179 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
3180 ? LocationSummary::kCall
3181 : LocationSummary::kNoCall;
3182 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00003183
Calin Juravled2ec87d2014-12-08 14:24:46 +00003184 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003185 case Primitive::kPrimInt: {
3186 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003187 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003188 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003189 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3190 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
3191 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003192 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003193 locations->AddTemp(Location::RequiresRegister());
3194 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003195 break;
3196 }
3197 case Primitive::kPrimLong: {
3198 InvokeRuntimeCallingConvention calling_convention;
3199 locations->SetInAt(0, Location::RegisterPairLocation(
3200 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3201 locations->SetInAt(1, Location::RegisterPairLocation(
3202 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3203 // Runtime helper puts the result in EAX, EDX.
3204 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3205 break;
3206 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003207 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003208 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003209 locations->SetInAt(0, Location::Any());
3210 locations->SetInAt(1, Location::Any());
3211 locations->SetOut(Location::RequiresFpuRegister());
3212 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003213 break;
3214 }
3215
3216 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003217 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003218 }
3219}
3220
3221void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
3222 Primitive::Type type = rem->GetResultType();
3223 switch (type) {
3224 case Primitive::kPrimInt:
3225 case Primitive::kPrimLong: {
3226 GenerateDivRemIntegral(rem);
3227 break;
3228 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003229 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00003230 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003231 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00003232 break;
3233 }
3234 default:
3235 LOG(FATAL) << "Unexpected rem type " << type;
3236 }
3237}
3238
Calin Juravled0d48522014-11-04 16:40:20 +00003239void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003240 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3241 ? LocationSummary::kCallOnSlowPath
3242 : LocationSummary::kNoCall;
3243 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003244 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003245 case Primitive::kPrimByte:
3246 case Primitive::kPrimChar:
3247 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003248 case Primitive::kPrimInt: {
3249 locations->SetInAt(0, Location::Any());
3250 break;
3251 }
3252 case Primitive::kPrimLong: {
3253 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3254 if (!instruction->IsConstant()) {
3255 locations->AddTemp(Location::RequiresRegister());
3256 }
3257 break;
3258 }
3259 default:
3260 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3261 }
Calin Juravled0d48522014-11-04 16:40:20 +00003262 if (instruction->HasUses()) {
3263 locations->SetOut(Location::SameAsFirstInput());
3264 }
3265}
3266
3267void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003268 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003269 codegen_->AddSlowPath(slow_path);
3270
3271 LocationSummary* locations = instruction->GetLocations();
3272 Location value = locations->InAt(0);
3273
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003274 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003275 case Primitive::kPrimByte:
3276 case Primitive::kPrimChar:
3277 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003278 case Primitive::kPrimInt: {
3279 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003280 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003281 __ j(kEqual, slow_path->GetEntryLabel());
3282 } else if (value.IsStackSlot()) {
3283 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
3284 __ j(kEqual, slow_path->GetEntryLabel());
3285 } else {
3286 DCHECK(value.IsConstant()) << value;
3287 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3288 __ jmp(slow_path->GetEntryLabel());
3289 }
3290 }
3291 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003292 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003293 case Primitive::kPrimLong: {
3294 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003295 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003296 __ movl(temp, value.AsRegisterPairLow<Register>());
3297 __ orl(temp, value.AsRegisterPairHigh<Register>());
3298 __ j(kEqual, slow_path->GetEntryLabel());
3299 } else {
3300 DCHECK(value.IsConstant()) << value;
3301 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3302 __ jmp(slow_path->GetEntryLabel());
3303 }
3304 }
3305 break;
3306 }
3307 default:
3308 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003309 }
Calin Juravled0d48522014-11-04 16:40:20 +00003310}
3311
Calin Juravle9aec02f2014-11-18 23:06:35 +00003312void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
3313 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3314
3315 LocationSummary* locations =
3316 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3317
3318 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00003319 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00003320 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003321 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00003322 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00003323 // The shift count needs to be in CL or a constant.
3324 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003325 locations->SetOut(Location::SameAsFirstInput());
3326 break;
3327 }
3328 default:
3329 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3330 }
3331}
3332
3333void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
3334 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3335
3336 LocationSummary* locations = op->GetLocations();
3337 Location first = locations->InAt(0);
3338 Location second = locations->InAt(1);
3339 DCHECK(first.Equals(locations->Out()));
3340
3341 switch (op->GetResultType()) {
3342 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00003343 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003344 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003345 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003346 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003347 DCHECK_EQ(ECX, second_reg);
3348 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003349 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003350 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003351 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003352 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003353 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003354 }
3355 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003356 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
3357 if (shift == 0) {
3358 return;
3359 }
3360 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003361 if (op->IsShl()) {
3362 __ shll(first_reg, imm);
3363 } else if (op->IsShr()) {
3364 __ sarl(first_reg, imm);
3365 } else {
3366 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003367 }
3368 }
3369 break;
3370 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003371 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003372 if (second.IsRegister()) {
3373 Register second_reg = second.AsRegister<Register>();
3374 DCHECK_EQ(ECX, second_reg);
3375 if (op->IsShl()) {
3376 GenerateShlLong(first, second_reg);
3377 } else if (op->IsShr()) {
3378 GenerateShrLong(first, second_reg);
3379 } else {
3380 GenerateUShrLong(first, second_reg);
3381 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003382 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003383 // Shift by a constant.
3384 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
3385 // Nothing to do if the shift is 0, as the input is already the output.
3386 if (shift != 0) {
3387 if (op->IsShl()) {
3388 GenerateShlLong(first, shift);
3389 } else if (op->IsShr()) {
3390 GenerateShrLong(first, shift);
3391 } else {
3392 GenerateUShrLong(first, shift);
3393 }
3394 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003395 }
3396 break;
3397 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003398 default:
3399 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3400 }
3401}
3402
Mark P Mendell73945692015-04-29 14:56:17 +00003403void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
3404 Register low = loc.AsRegisterPairLow<Register>();
3405 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04003406 if (shift == 1) {
3407 // This is just an addition.
3408 __ addl(low, low);
3409 __ adcl(high, high);
3410 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00003411 // Shift by 32 is easy. High gets low, and low gets 0.
3412 codegen_->EmitParallelMoves(
3413 loc.ToLow(),
3414 loc.ToHigh(),
3415 Primitive::kPrimInt,
3416 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3417 loc.ToLow(),
3418 Primitive::kPrimInt);
3419 } else if (shift > 32) {
3420 // Low part becomes 0. High part is low part << (shift-32).
3421 __ movl(high, low);
3422 __ shll(high, Immediate(shift - 32));
3423 __ xorl(low, low);
3424 } else {
3425 // Between 1 and 31.
3426 __ shld(high, low, Immediate(shift));
3427 __ shll(low, Immediate(shift));
3428 }
3429}
3430
Calin Juravle9aec02f2014-11-18 23:06:35 +00003431void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003432 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003433 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
3434 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
3435 __ testl(shifter, Immediate(32));
3436 __ j(kEqual, &done);
3437 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
3438 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
3439 __ Bind(&done);
3440}
3441
Mark P Mendell73945692015-04-29 14:56:17 +00003442void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
3443 Register low = loc.AsRegisterPairLow<Register>();
3444 Register high = loc.AsRegisterPairHigh<Register>();
3445 if (shift == 32) {
3446 // Need to copy the sign.
3447 DCHECK_NE(low, high);
3448 __ movl(low, high);
3449 __ sarl(high, Immediate(31));
3450 } else if (shift > 32) {
3451 DCHECK_NE(low, high);
3452 // High part becomes sign. Low part is shifted by shift - 32.
3453 __ movl(low, high);
3454 __ sarl(high, Immediate(31));
3455 __ sarl(low, Immediate(shift - 32));
3456 } else {
3457 // Between 1 and 31.
3458 __ shrd(low, high, Immediate(shift));
3459 __ sarl(high, Immediate(shift));
3460 }
3461}
3462
Calin Juravle9aec02f2014-11-18 23:06:35 +00003463void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003464 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003465 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3466 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
3467 __ testl(shifter, Immediate(32));
3468 __ j(kEqual, &done);
3469 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3470 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
3471 __ Bind(&done);
3472}
3473
Mark P Mendell73945692015-04-29 14:56:17 +00003474void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
3475 Register low = loc.AsRegisterPairLow<Register>();
3476 Register high = loc.AsRegisterPairHigh<Register>();
3477 if (shift == 32) {
3478 // Shift by 32 is easy. Low gets high, and high gets 0.
3479 codegen_->EmitParallelMoves(
3480 loc.ToHigh(),
3481 loc.ToLow(),
3482 Primitive::kPrimInt,
3483 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3484 loc.ToHigh(),
3485 Primitive::kPrimInt);
3486 } else if (shift > 32) {
3487 // Low part is high >> (shift - 32). High part becomes 0.
3488 __ movl(low, high);
3489 __ shrl(low, Immediate(shift - 32));
3490 __ xorl(high, high);
3491 } else {
3492 // Between 1 and 31.
3493 __ shrd(low, high, Immediate(shift));
3494 __ shrl(high, Immediate(shift));
3495 }
3496}
3497
Calin Juravle9aec02f2014-11-18 23:06:35 +00003498void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003499 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003500 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3501 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
3502 __ testl(shifter, Immediate(32));
3503 __ j(kEqual, &done);
3504 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3505 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
3506 __ Bind(&done);
3507}
3508
3509void LocationsBuilderX86::VisitShl(HShl* shl) {
3510 HandleShift(shl);
3511}
3512
3513void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
3514 HandleShift(shl);
3515}
3516
3517void LocationsBuilderX86::VisitShr(HShr* shr) {
3518 HandleShift(shr);
3519}
3520
3521void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
3522 HandleShift(shr);
3523}
3524
3525void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
3526 HandleShift(ushr);
3527}
3528
3529void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
3530 HandleShift(ushr);
3531}
3532
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003533void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003534 LocationSummary* locations =
3535 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003536 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003537 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003538 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003539 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003540}
3541
3542void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
3543 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003544 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01003545 // Note: if heap poisoning is enabled, the entry point takes cares
3546 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003547 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3548 instruction,
3549 instruction->GetDexPc(),
3550 nullptr);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003551 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003552}
3553
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003554void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
3555 LocationSummary* locations =
3556 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3557 locations->SetOut(Location::RegisterLocation(EAX));
3558 InvokeRuntimeCallingConvention calling_convention;
3559 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003560 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003561 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003562}
3563
3564void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
3565 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003566 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
3567
Roland Levillain4d027112015-07-01 15:41:14 +01003568 // Note: if heap poisoning is enabled, the entry point takes cares
3569 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003570 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3571 instruction,
3572 instruction->GetDexPc(),
3573 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003574 DCHECK(!codegen_->IsLeafMethod());
3575}
3576
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003577void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003578 LocationSummary* locations =
3579 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003580 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3581 if (location.IsStackSlot()) {
3582 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3583 } else if (location.IsDoubleStackSlot()) {
3584 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003585 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003586 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003587}
3588
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003589void InstructionCodeGeneratorX86::VisitParameterValue(
3590 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3591}
3592
3593void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3594 LocationSummary* locations =
3595 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3596 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3597}
3598
3599void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003600}
3601
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003602void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003603 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003604 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003605 locations->SetInAt(0, Location::RequiresRegister());
3606 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003607}
3608
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003609void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3610 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003611 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003612 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003613 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003614 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003615 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003616 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003617 break;
3618
3619 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003620 __ notl(out.AsRegisterPairLow<Register>());
3621 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003622 break;
3623
3624 default:
3625 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3626 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003627}
3628
David Brazdil66d126e2015-04-03 16:02:44 +01003629void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3630 LocationSummary* locations =
3631 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3632 locations->SetInAt(0, Location::RequiresRegister());
3633 locations->SetOut(Location::SameAsFirstInput());
3634}
3635
3636void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003637 LocationSummary* locations = bool_not->GetLocations();
3638 Location in = locations->InAt(0);
3639 Location out = locations->Out();
3640 DCHECK(in.Equals(out));
3641 __ xorl(out.AsRegister<Register>(), Immediate(1));
3642}
3643
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003644void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003645 LocationSummary* locations =
3646 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003647 switch (compare->InputAt(0)->GetType()) {
3648 case Primitive::kPrimLong: {
3649 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003650 locations->SetInAt(1, Location::Any());
3651 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3652 break;
3653 }
3654 case Primitive::kPrimFloat:
3655 case Primitive::kPrimDouble: {
3656 locations->SetInAt(0, Location::RequiresFpuRegister());
3657 locations->SetInAt(1, Location::RequiresFpuRegister());
3658 locations->SetOut(Location::RequiresRegister());
3659 break;
3660 }
3661 default:
3662 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3663 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003664}
3665
3666void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003667 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003668 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003669 Location left = locations->InAt(0);
3670 Location right = locations->InAt(1);
3671
Mark Mendell0c9497d2015-08-21 09:30:05 -04003672 NearLabel less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003673 switch (compare->InputAt(0)->GetType()) {
3674 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003675 Register left_low = left.AsRegisterPairLow<Register>();
3676 Register left_high = left.AsRegisterPairHigh<Register>();
3677 int32_t val_low = 0;
3678 int32_t val_high = 0;
3679 bool right_is_const = false;
3680
3681 if (right.IsConstant()) {
3682 DCHECK(right.GetConstant()->IsLongConstant());
3683 right_is_const = true;
3684 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3685 val_low = Low32Bits(val);
3686 val_high = High32Bits(val);
3687 }
3688
Calin Juravleddb7df22014-11-25 20:56:51 +00003689 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003690 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003691 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003692 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003693 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003694 DCHECK(right_is_const) << right;
3695 if (val_high == 0) {
3696 __ testl(left_high, left_high);
3697 } else {
3698 __ cmpl(left_high, Immediate(val_high));
3699 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003700 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003701 __ j(kLess, &less); // Signed compare.
3702 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003703 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003704 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003705 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003706 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003707 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003708 DCHECK(right_is_const) << right;
3709 if (val_low == 0) {
3710 __ testl(left_low, left_low);
3711 } else {
3712 __ cmpl(left_low, Immediate(val_low));
3713 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003714 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003715 break;
3716 }
3717 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003718 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003719 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3720 break;
3721 }
3722 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003723 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003724 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003725 break;
3726 }
3727 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003728 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003729 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003730 __ movl(out, Immediate(0));
3731 __ j(kEqual, &done);
3732 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3733
3734 __ Bind(&greater);
3735 __ movl(out, Immediate(1));
3736 __ jmp(&done);
3737
3738 __ Bind(&less);
3739 __ movl(out, Immediate(-1));
3740
3741 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003742}
3743
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003744void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003745 LocationSummary* locations =
3746 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003747 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3748 locations->SetInAt(i, Location::Any());
3749 }
3750 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003751}
3752
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003753void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003754 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003755}
3756
Calin Juravle52c48962014-12-16 17:02:57 +00003757void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3758 /*
3759 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3760 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3761 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3762 */
3763 switch (kind) {
3764 case MemBarrierKind::kAnyAny: {
3765 __ mfence();
3766 break;
3767 }
3768 case MemBarrierKind::kAnyStore:
3769 case MemBarrierKind::kLoadAny:
3770 case MemBarrierKind::kStoreStore: {
3771 // nop
3772 break;
3773 }
3774 default:
3775 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003776 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003777}
3778
Vladimir Markodc151b22015-10-15 18:02:30 +01003779HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
3780 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
3781 MethodReference target_method ATTRIBUTE_UNUSED) {
3782 if (desired_dispatch_info.method_load_kind ==
3783 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative) {
3784 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
3785 return HInvokeStaticOrDirect::DispatchInfo {
3786 HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
3787 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
3788 0u,
3789 0u
3790 };
3791 }
3792 switch (desired_dispatch_info.code_ptr_location) {
3793 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3794 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3795 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
3796 // (Though the direct CALL ptr16:32 is available for consideration).
3797 return HInvokeStaticOrDirect::DispatchInfo {
3798 desired_dispatch_info.method_load_kind,
3799 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
3800 desired_dispatch_info.method_load_data,
3801 0u
3802 };
3803 default:
3804 return desired_dispatch_info;
3805 }
3806}
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003807
Vladimir Marko58155012015-08-19 12:49:41 +00003808void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3809 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3810 switch (invoke->GetMethodLoadKind()) {
3811 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3812 // temp = thread->string_init_entrypoint
3813 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
3814 break;
3815 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
3816 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3817 break;
3818 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3819 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
3820 break;
3821 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3822 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder.
3823 method_patches_.emplace_back(invoke->GetTargetMethod());
3824 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
3825 break;
3826 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01003827 // TODO: Implement this type.
3828 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
3829 LOG(FATAL) << "Unsupported";
3830 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +00003831 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
3832 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3833 Register method_reg;
3834 Register reg = temp.AsRegister<Register>();
3835 if (current_method.IsRegister()) {
3836 method_reg = current_method.AsRegister<Register>();
3837 } else {
3838 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
3839 DCHECK(!current_method.IsValid());
3840 method_reg = reg;
3841 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
3842 }
3843 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01003844 __ movl(reg, Address(method_reg,
3845 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
Vladimir Marko58155012015-08-19 12:49:41 +00003846 // temp = temp[index_in_cache]
3847 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3848 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
3849 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01003850 }
Vladimir Marko58155012015-08-19 12:49:41 +00003851 }
3852
3853 switch (invoke->GetCodePtrLocation()) {
3854 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3855 __ call(GetFrameEntryLabel());
3856 break;
3857 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
3858 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
3859 Label* label = &relative_call_patches_.back().label;
3860 __ call(label); // Bind to the patch label, override at link time.
3861 __ Bind(label); // Bind the label at the end of the "call" insn.
3862 break;
3863 }
3864 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3865 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
Vladimir Markodc151b22015-10-15 18:02:30 +01003866 // Filtered out by GetSupportedInvokeStaticOrDirectDispatch().
3867 LOG(FATAL) << "Unsupported";
3868 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +00003869 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3870 // (callee_method + offset_of_quick_compiled_code)()
3871 __ call(Address(callee_method.AsRegister<Register>(),
3872 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3873 kX86WordSize).Int32Value()));
3874 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04003875 }
3876
3877 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003878}
3879
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003880void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
3881 Register temp = temp_in.AsRegister<Register>();
3882 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3883 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
3884 LocationSummary* locations = invoke->GetLocations();
3885 Location receiver = locations->InAt(0);
3886 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3887 // temp = object->GetClass();
3888 DCHECK(receiver.IsRegister());
3889 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
3890 MaybeRecordImplicitNullCheck(invoke);
3891 __ MaybeUnpoisonHeapReference(temp);
3892 // temp = temp->GetMethodAt(method_offset);
3893 __ movl(temp, Address(temp, method_offset));
3894 // call temp->GetEntryPoint();
3895 __ call(Address(
3896 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3897}
3898
Vladimir Marko58155012015-08-19 12:49:41 +00003899void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
3900 DCHECK(linker_patches->empty());
3901 linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
3902 for (const MethodPatchInfo<Label>& info : method_patches_) {
3903 // The label points to the end of the "movl" insn but the literal offset for method
3904 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3905 uint32_t literal_offset = info.label.Position() - 4;
3906 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
3907 info.target_method.dex_file,
3908 info.target_method.dex_method_index));
3909 }
3910 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
3911 // The label points to the end of the "call" insn but the literal offset for method
3912 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3913 uint32_t literal_offset = info.label.Position() - 4;
3914 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
3915 info.target_method.dex_file,
3916 info.target_method.dex_method_index));
3917 }
3918}
3919
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003920void CodeGeneratorX86::MarkGCCard(Register temp,
3921 Register card,
3922 Register object,
3923 Register value,
3924 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003925 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003926 if (value_can_be_null) {
3927 __ testl(value, value);
3928 __ j(kEqual, &is_null);
3929 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003930 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3931 __ movl(temp, object);
3932 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003933 __ movb(Address(temp, card, TIMES_1, 0),
3934 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003935 if (value_can_be_null) {
3936 __ Bind(&is_null);
3937 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003938}
3939
Calin Juravle52c48962014-12-16 17:02:57 +00003940void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3941 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003942 LocationSummary* locations =
3943 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003944 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003945
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003946 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3947 locations->SetOut(Location::RequiresFpuRegister());
3948 } else {
3949 // The output overlaps in case of long: we don't want the low move to overwrite
3950 // the object's location.
3951 locations->SetOut(Location::RequiresRegister(),
3952 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3953 : Location::kNoOutputOverlap);
3954 }
Calin Juravle52c48962014-12-16 17:02:57 +00003955
3956 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3957 // Long values can be loaded atomically into an XMM using movsd.
3958 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3959 // and then copy the XMM into the output 32bits at a time).
3960 locations->AddTemp(Location::RequiresFpuRegister());
3961 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003962}
3963
Calin Juravle52c48962014-12-16 17:02:57 +00003964void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3965 const FieldInfo& field_info) {
3966 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003967
Calin Juravle52c48962014-12-16 17:02:57 +00003968 LocationSummary* locations = instruction->GetLocations();
3969 Register base = locations->InAt(0).AsRegister<Register>();
3970 Location out = locations->Out();
3971 bool is_volatile = field_info.IsVolatile();
3972 Primitive::Type field_type = field_info.GetFieldType();
3973 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3974
3975 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003976 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003977 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003978 break;
3979 }
3980
3981 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003982 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003983 break;
3984 }
3985
3986 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003987 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003988 break;
3989 }
3990
3991 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003992 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003993 break;
3994 }
3995
3996 case Primitive::kPrimInt:
3997 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003998 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003999 break;
4000 }
4001
4002 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00004003 if (is_volatile) {
4004 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4005 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004006 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004007 __ movd(out.AsRegisterPairLow<Register>(), temp);
4008 __ psrlq(temp, Immediate(32));
4009 __ movd(out.AsRegisterPairHigh<Register>(), temp);
4010 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004011 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00004012 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004013 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004014 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
4015 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004016 break;
4017 }
4018
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004019 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00004020 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004021 break;
4022 }
4023
4024 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004025 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004026 break;
4027 }
4028
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004029 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004030 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004031 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004032 }
Calin Juravle52c48962014-12-16 17:02:57 +00004033
Calin Juravle77520bc2015-01-12 18:45:46 +00004034 // Longs are handled in the switch.
4035 if (field_type != Primitive::kPrimLong) {
4036 codegen_->MaybeRecordImplicitNullCheck(instruction);
4037 }
4038
Calin Juravle52c48962014-12-16 17:02:57 +00004039 if (is_volatile) {
4040 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4041 }
Roland Levillain4d027112015-07-01 15:41:14 +01004042
4043 if (field_type == Primitive::kPrimNot) {
4044 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
4045 }
Calin Juravle52c48962014-12-16 17:02:57 +00004046}
4047
4048void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
4049 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4050
4051 LocationSummary* locations =
4052 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4053 locations->SetInAt(0, Location::RequiresRegister());
4054 bool is_volatile = field_info.IsVolatile();
4055 Primitive::Type field_type = field_info.GetFieldType();
4056 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
4057 || (field_type == Primitive::kPrimByte);
4058
4059 // The register allocator does not support multiple
4060 // inputs that die at entry with one in a specific register.
4061 if (is_byte_type) {
4062 // Ensure the value is in a byte register.
4063 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004064 } else if (Primitive::IsFloatingPointType(field_type)) {
4065 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004066 } else {
4067 locations->SetInAt(1, Location::RequiresRegister());
4068 }
Calin Juravle52c48962014-12-16 17:02:57 +00004069 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Roland Levillain4d027112015-07-01 15:41:14 +01004070 // Temporary registers for the write barrier.
4071 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Calin Juravle52c48962014-12-16 17:02:57 +00004072 // Ensure the card is in a byte register.
4073 locations->AddTemp(Location::RegisterLocation(ECX));
4074 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
4075 // 64bits value can be atomically written to an address with movsd and an XMM register.
4076 // We need two XMM registers because there's no easier way to (bit) copy a register pair
4077 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
4078 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
4079 // isolated cases when we need this it isn't worth adding the extra complexity.
4080 locations->AddTemp(Location::RequiresFpuRegister());
4081 locations->AddTemp(Location::RequiresFpuRegister());
4082 }
4083}
4084
4085void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004086 const FieldInfo& field_info,
4087 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004088 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4089
4090 LocationSummary* locations = instruction->GetLocations();
4091 Register base = locations->InAt(0).AsRegister<Register>();
4092 Location value = locations->InAt(1);
4093 bool is_volatile = field_info.IsVolatile();
4094 Primitive::Type field_type = field_info.GetFieldType();
4095 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004096 bool needs_write_barrier =
4097 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004098
4099 if (is_volatile) {
4100 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4101 }
4102
4103 switch (field_type) {
4104 case Primitive::kPrimBoolean:
4105 case Primitive::kPrimByte: {
4106 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
4107 break;
4108 }
4109
4110 case Primitive::kPrimShort:
4111 case Primitive::kPrimChar: {
4112 __ movw(Address(base, offset), value.AsRegister<Register>());
4113 break;
4114 }
4115
4116 case Primitive::kPrimInt:
4117 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004118 if (kPoisonHeapReferences && needs_write_barrier) {
4119 // Note that in the case where `value` is a null reference,
4120 // we do not enter this block, as the reference does not
4121 // need poisoning.
4122 DCHECK_EQ(field_type, Primitive::kPrimNot);
4123 Register temp = locations->GetTemp(0).AsRegister<Register>();
4124 __ movl(temp, value.AsRegister<Register>());
4125 __ PoisonHeapReference(temp);
4126 __ movl(Address(base, offset), temp);
4127 } else {
4128 __ movl(Address(base, offset), value.AsRegister<Register>());
4129 }
Calin Juravle52c48962014-12-16 17:02:57 +00004130 break;
4131 }
4132
4133 case Primitive::kPrimLong: {
4134 if (is_volatile) {
4135 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4136 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
4137 __ movd(temp1, value.AsRegisterPairLow<Register>());
4138 __ movd(temp2, value.AsRegisterPairHigh<Register>());
4139 __ punpckldq(temp1, temp2);
4140 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00004141 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004142 } else {
4143 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004144 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004145 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
4146 }
4147 break;
4148 }
4149
4150 case Primitive::kPrimFloat: {
4151 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4152 break;
4153 }
4154
4155 case Primitive::kPrimDouble: {
4156 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4157 break;
4158 }
4159
4160 case Primitive::kPrimVoid:
4161 LOG(FATAL) << "Unreachable type " << field_type;
4162 UNREACHABLE();
4163 }
4164
Calin Juravle77520bc2015-01-12 18:45:46 +00004165 // Longs are handled in the switch.
4166 if (field_type != Primitive::kPrimLong) {
4167 codegen_->MaybeRecordImplicitNullCheck(instruction);
4168 }
4169
Roland Levillain4d027112015-07-01 15:41:14 +01004170 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004171 Register temp = locations->GetTemp(0).AsRegister<Register>();
4172 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004173 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004174 }
4175
Calin Juravle52c48962014-12-16 17:02:57 +00004176 if (is_volatile) {
4177 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4178 }
4179}
4180
4181void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4182 HandleFieldGet(instruction, instruction->GetFieldInfo());
4183}
4184
4185void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4186 HandleFieldGet(instruction, instruction->GetFieldInfo());
4187}
4188
4189void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4190 HandleFieldSet(instruction, instruction->GetFieldInfo());
4191}
4192
4193void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004194 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004195}
4196
4197void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4198 HandleFieldSet(instruction, instruction->GetFieldInfo());
4199}
4200
4201void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004202 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004203}
4204
4205void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4206 HandleFieldGet(instruction, instruction->GetFieldInfo());
4207}
4208
4209void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4210 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004211}
4212
Calin Juravlee460d1d2015-09-29 04:52:17 +01004213void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
4214 HUnresolvedInstanceFieldGet* instruction) {
4215 FieldAccessCallingConventionX86 calling_convention;
4216 codegen_->CreateUnresolvedFieldLocationSummary(
4217 instruction, instruction->GetFieldType(), calling_convention);
4218}
4219
4220void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
4221 HUnresolvedInstanceFieldGet* instruction) {
4222 FieldAccessCallingConventionX86 calling_convention;
4223 codegen_->GenerateUnresolvedFieldAccess(instruction,
4224 instruction->GetFieldType(),
4225 instruction->GetFieldIndex(),
4226 instruction->GetDexPc(),
4227 calling_convention);
4228}
4229
4230void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
4231 HUnresolvedInstanceFieldSet* instruction) {
4232 FieldAccessCallingConventionX86 calling_convention;
4233 codegen_->CreateUnresolvedFieldLocationSummary(
4234 instruction, instruction->GetFieldType(), calling_convention);
4235}
4236
4237void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
4238 HUnresolvedInstanceFieldSet* instruction) {
4239 FieldAccessCallingConventionX86 calling_convention;
4240 codegen_->GenerateUnresolvedFieldAccess(instruction,
4241 instruction->GetFieldType(),
4242 instruction->GetFieldIndex(),
4243 instruction->GetDexPc(),
4244 calling_convention);
4245}
4246
4247void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
4248 HUnresolvedStaticFieldGet* instruction) {
4249 FieldAccessCallingConventionX86 calling_convention;
4250 codegen_->CreateUnresolvedFieldLocationSummary(
4251 instruction, instruction->GetFieldType(), calling_convention);
4252}
4253
4254void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
4255 HUnresolvedStaticFieldGet* instruction) {
4256 FieldAccessCallingConventionX86 calling_convention;
4257 codegen_->GenerateUnresolvedFieldAccess(instruction,
4258 instruction->GetFieldType(),
4259 instruction->GetFieldIndex(),
4260 instruction->GetDexPc(),
4261 calling_convention);
4262}
4263
4264void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
4265 HUnresolvedStaticFieldSet* instruction) {
4266 FieldAccessCallingConventionX86 calling_convention;
4267 codegen_->CreateUnresolvedFieldLocationSummary(
4268 instruction, instruction->GetFieldType(), calling_convention);
4269}
4270
4271void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
4272 HUnresolvedStaticFieldSet* instruction) {
4273 FieldAccessCallingConventionX86 calling_convention;
4274 codegen_->GenerateUnresolvedFieldAccess(instruction,
4275 instruction->GetFieldType(),
4276 instruction->GetFieldIndex(),
4277 instruction->GetDexPc(),
4278 calling_convention);
4279}
4280
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004281void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004282 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4283 ? LocationSummary::kCallOnSlowPath
4284 : LocationSummary::kNoCall;
4285 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4286 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004287 ? Location::RequiresRegister()
4288 : Location::Any();
4289 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004290 if (instruction->HasUses()) {
4291 locations->SetOut(Location::SameAsFirstInput());
4292 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004293}
4294
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004295void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004296 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4297 return;
4298 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004299 LocationSummary* locations = instruction->GetLocations();
4300 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004301
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004302 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
4303 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4304}
4305
4306void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004307 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004308 codegen_->AddSlowPath(slow_path);
4309
4310 LocationSummary* locations = instruction->GetLocations();
4311 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004312
4313 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04004314 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004315 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004316 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004317 } else {
4318 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004319 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004320 __ jmp(slow_path->GetEntryLabel());
4321 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004322 }
4323 __ j(kEqual, slow_path->GetEntryLabel());
4324}
4325
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004326void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004327 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004328 GenerateImplicitNullCheck(instruction);
4329 } else {
4330 GenerateExplicitNullCheck(instruction);
4331 }
4332}
4333
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004334void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004335 LocationSummary* locations =
4336 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004337 locations->SetInAt(0, Location::RequiresRegister());
4338 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004339 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4340 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4341 } else {
4342 // The output overlaps in case of long: we don't want the low move to overwrite
4343 // the array's location.
4344 locations->SetOut(Location::RequiresRegister(),
4345 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
4346 : Location::kNoOutputOverlap);
4347 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004348}
4349
4350void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
4351 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004352 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004353 Location index = locations->InAt(1);
4354
Calin Juravle77520bc2015-01-12 18:45:46 +00004355 Primitive::Type type = instruction->GetType();
4356 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004357 case Primitive::kPrimBoolean: {
4358 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004359 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004360 if (index.IsConstant()) {
4361 __ movzxb(out, Address(obj,
4362 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4363 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004364 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004365 }
4366 break;
4367 }
4368
4369 case Primitive::kPrimByte: {
4370 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004371 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004372 if (index.IsConstant()) {
4373 __ movsxb(out, Address(obj,
4374 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4375 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004376 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004377 }
4378 break;
4379 }
4380
4381 case Primitive::kPrimShort: {
4382 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004383 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004384 if (index.IsConstant()) {
4385 __ movsxw(out, Address(obj,
4386 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4387 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004388 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004389 }
4390 break;
4391 }
4392
4393 case Primitive::kPrimChar: {
4394 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004395 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004396 if (index.IsConstant()) {
4397 __ movzxw(out, Address(obj,
4398 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4399 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004400 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004401 }
4402 break;
4403 }
4404
4405 case Primitive::kPrimInt:
4406 case Primitive::kPrimNot: {
4407 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004408 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004409 if (index.IsConstant()) {
4410 __ movl(out, Address(obj,
4411 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4412 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004413 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004414 }
4415 break;
4416 }
4417
4418 case Primitive::kPrimLong: {
4419 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004420 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004421 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004422 if (index.IsConstant()) {
4423 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004424 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004425 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004426 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004427 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004428 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004429 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004430 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004431 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004432 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004433 }
4434 break;
4435 }
4436
Mark Mendell7c8d0092015-01-26 11:21:33 -05004437 case Primitive::kPrimFloat: {
4438 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4439 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4440 if (index.IsConstant()) {
4441 __ movss(out, Address(obj,
4442 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4443 } else {
4444 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
4445 }
4446 break;
4447 }
4448
4449 case Primitive::kPrimDouble: {
4450 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4451 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4452 if (index.IsConstant()) {
4453 __ movsd(out, Address(obj,
4454 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4455 } else {
4456 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
4457 }
4458 break;
4459 }
4460
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004461 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00004462 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004463 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004464 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004465
4466 if (type != Primitive::kPrimLong) {
4467 codegen_->MaybeRecordImplicitNullCheck(instruction);
4468 }
Roland Levillain4d027112015-07-01 15:41:14 +01004469
4470 if (type == Primitive::kPrimNot) {
4471 Register out = locations->Out().AsRegister<Register>();
4472 __ MaybeUnpoisonHeapReference(out);
4473 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004474}
4475
4476void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05004477 // This location builder might end up asking to up to four registers, which is
4478 // not currently possible for baseline. The situation in which we need four
4479 // registers cannot be met by baseline though, because it has not run any
4480 // optimization.
4481
Nicolas Geoffray39468442014-09-02 15:17:15 +01004482 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004483 bool needs_write_barrier =
4484 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4485
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004486 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004487
Nicolas Geoffray39468442014-09-02 15:17:15 +01004488 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4489 instruction,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004490 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004491
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004492 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
4493 || (value_type == Primitive::kPrimByte);
4494 // We need the inputs to be different than the output in case of long operation.
4495 // In case of a byte operation, the register allocator does not support multiple
4496 // inputs that die at entry with one in a specific register.
4497 locations->SetInAt(0, Location::RequiresRegister());
4498 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4499 if (is_byte_type) {
4500 // Ensure the value is in a byte register.
4501 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
4502 } else if (Primitive::IsFloatingPointType(value_type)) {
4503 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004504 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004505 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4506 }
4507 if (needs_write_barrier) {
4508 // Temporary registers for the write barrier.
4509 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4510 // Ensure the card is in a byte register.
4511 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004512 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004513}
4514
4515void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
4516 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004517 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004518 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004519 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004520 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004521 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4522 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4523 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4524 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004525 bool needs_write_barrier =
4526 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004527
4528 switch (value_type) {
4529 case Primitive::kPrimBoolean:
4530 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004531 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4532 Address address = index.IsConstant()
4533 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4534 : Address(array, index.AsRegister<Register>(), TIMES_1, offset);
4535 if (value.IsRegister()) {
4536 __ movb(address, value.AsRegister<ByteRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004537 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004538 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004539 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004540 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004541 break;
4542 }
4543
4544 case Primitive::kPrimShort:
4545 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004546 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4547 Address address = index.IsConstant()
4548 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4549 : Address(array, index.AsRegister<Register>(), TIMES_2, offset);
4550 if (value.IsRegister()) {
4551 __ movw(address, value.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004552 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004553 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004554 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004555 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004556 break;
4557 }
4558
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004559 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004560 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4561 Address address = index.IsConstant()
4562 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4563 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4564 if (!value.IsRegister()) {
4565 // Just setting null.
4566 DCHECK(instruction->InputAt(2)->IsNullConstant());
4567 DCHECK(value.IsConstant()) << value;
4568 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004569 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004570 DCHECK(!needs_write_barrier);
4571 DCHECK(!may_need_runtime_call);
4572 break;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004573 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004574
4575 DCHECK(needs_write_barrier);
4576 Register register_value = value.AsRegister<Register>();
4577 NearLabel done, not_null, do_put;
4578 SlowPathCode* slow_path = nullptr;
4579 Register temp = locations->GetTemp(0).AsRegister<Register>();
4580 if (may_need_runtime_call) {
4581 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86(instruction);
4582 codegen_->AddSlowPath(slow_path);
4583 if (instruction->GetValueCanBeNull()) {
4584 __ testl(register_value, register_value);
4585 __ j(kNotEqual, &not_null);
4586 __ movl(address, Immediate(0));
4587 codegen_->MaybeRecordImplicitNullCheck(instruction);
4588 __ jmp(&done);
4589 __ Bind(&not_null);
4590 }
4591
4592 __ movl(temp, Address(array, class_offset));
4593 codegen_->MaybeRecordImplicitNullCheck(instruction);
4594 __ MaybeUnpoisonHeapReference(temp);
4595 __ movl(temp, Address(temp, component_offset));
4596 // No need to poison/unpoison, we're comparing two poisoned references.
4597 __ cmpl(temp, Address(register_value, class_offset));
4598 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4599 __ j(kEqual, &do_put);
4600 __ MaybeUnpoisonHeapReference(temp);
4601 __ movl(temp, Address(temp, super_offset));
4602 // No need to unpoison, we're comparing against null..
4603 __ testl(temp, temp);
4604 __ j(kNotEqual, slow_path->GetEntryLabel());
4605 __ Bind(&do_put);
4606 } else {
4607 __ j(kNotEqual, slow_path->GetEntryLabel());
4608 }
4609 }
4610
4611 if (kPoisonHeapReferences) {
4612 __ movl(temp, register_value);
4613 __ PoisonHeapReference(temp);
4614 __ movl(address, temp);
4615 } else {
4616 __ movl(address, register_value);
4617 }
4618 if (!may_need_runtime_call) {
4619 codegen_->MaybeRecordImplicitNullCheck(instruction);
4620 }
4621
4622 Register card = locations->GetTemp(1).AsRegister<Register>();
4623 codegen_->MarkGCCard(
4624 temp, card, array, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
4625 __ Bind(&done);
4626
4627 if (slow_path != nullptr) {
4628 __ Bind(slow_path->GetExitLabel());
4629 }
4630
4631 break;
4632 }
4633 case Primitive::kPrimInt: {
4634 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4635 Address address = index.IsConstant()
4636 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4637 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4638 if (value.IsRegister()) {
4639 __ movl(address, value.AsRegister<Register>());
4640 } else {
4641 DCHECK(value.IsConstant()) << value;
4642 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4643 __ movl(address, Immediate(v));
4644 }
4645 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004646 break;
4647 }
4648
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004649 case Primitive::kPrimLong: {
4650 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004651 if (index.IsConstant()) {
4652 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004653 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004654 __ movl(Address(array, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004655 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004656 __ movl(Address(array, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004657 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004658 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004659 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004660 __ movl(Address(array, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004661 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004662 __ movl(Address(array, offset + kX86WordSize), Immediate(High32Bits(val)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004663 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004664 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004665 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004666 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004667 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004668 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004669 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004670 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004671 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004672 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004673 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004674 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004675 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004676 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004677 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004678 Immediate(High32Bits(val)));
4679 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004680 }
4681 break;
4682 }
4683
Mark Mendell7c8d0092015-01-26 11:21:33 -05004684 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004685 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4686 Address address = index.IsConstant()
4687 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4688 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004689 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004690 __ movss(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004691 break;
4692 }
4693
4694 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004695 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4696 Address address = index.IsConstant()
4697 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4698 : Address(array, index.AsRegister<Register>(), TIMES_8, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004699 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004700 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004701 break;
4702 }
4703
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004704 case Primitive::kPrimVoid:
4705 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004706 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004707 }
4708}
4709
4710void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
4711 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004712 locations->SetInAt(0, Location::RequiresRegister());
4713 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004714}
4715
4716void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
4717 LocationSummary* locations = instruction->GetLocations();
4718 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004719 Register obj = locations->InAt(0).AsRegister<Register>();
4720 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004721 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004722 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004723}
4724
4725void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004726 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4727 ? LocationSummary::kCallOnSlowPath
4728 : LocationSummary::kNoCall;
4729 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004730 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004731 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004732 if (instruction->HasUses()) {
4733 locations->SetOut(Location::SameAsFirstInput());
4734 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004735}
4736
4737void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
4738 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004739 Location index_loc = locations->InAt(0);
4740 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004741 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004742 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004743
Mark Mendell99dbd682015-04-22 16:18:52 -04004744 if (length_loc.IsConstant()) {
4745 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4746 if (index_loc.IsConstant()) {
4747 // BCE will remove the bounds check if we are guarenteed to pass.
4748 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4749 if (index < 0 || index >= length) {
4750 codegen_->AddSlowPath(slow_path);
4751 __ jmp(slow_path->GetEntryLabel());
4752 } else {
4753 // Some optimization after BCE may have generated this, and we should not
4754 // generate a bounds check if it is a valid range.
4755 }
4756 return;
4757 }
4758
4759 // We have to reverse the jump condition because the length is the constant.
4760 Register index_reg = index_loc.AsRegister<Register>();
4761 __ cmpl(index_reg, Immediate(length));
4762 codegen_->AddSlowPath(slow_path);
4763 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004764 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004765 Register length = length_loc.AsRegister<Register>();
4766 if (index_loc.IsConstant()) {
4767 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4768 __ cmpl(length, Immediate(value));
4769 } else {
4770 __ cmpl(length, index_loc.AsRegister<Register>());
4771 }
4772 codegen_->AddSlowPath(slow_path);
4773 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004774 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004775}
4776
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004777void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
4778 temp->SetLocations(nullptr);
4779}
4780
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004781void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004782 // Nothing to do, this is driven by the code generator.
4783}
4784
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004785void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004786 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004787}
4788
4789void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004790 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4791}
4792
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004793void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
4794 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4795}
4796
4797void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004798 HBasicBlock* block = instruction->GetBlock();
4799 if (block->GetLoopInformation() != nullptr) {
4800 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4801 // The back edge will generate the suspend check.
4802 return;
4803 }
4804 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4805 // The goto will generate the suspend check.
4806 return;
4807 }
4808 GenerateSuspendCheck(instruction, nullptr);
4809}
4810
4811void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4812 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004813 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004814 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4815 if (slow_path == nullptr) {
4816 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4817 instruction->SetSlowPath(slow_path);
4818 codegen_->AddSlowPath(slow_path);
4819 if (successor != nullptr) {
4820 DCHECK(successor->IsLoopHeader());
4821 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4822 }
4823 } else {
4824 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4825 }
4826
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004827 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004828 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004829 if (successor == nullptr) {
4830 __ j(kNotEqual, slow_path->GetEntryLabel());
4831 __ Bind(slow_path->GetReturnLabel());
4832 } else {
4833 __ j(kEqual, codegen_->GetLabelOf(successor));
4834 __ jmp(slow_path->GetEntryLabel());
4835 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004836}
4837
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004838X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4839 return codegen_->GetAssembler();
4840}
4841
Mark Mendell7c8d0092015-01-26 11:21:33 -05004842void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004843 ScratchRegisterScope ensure_scratch(
4844 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4845 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4846 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4847 __ movl(temp_reg, Address(ESP, src + stack_offset));
4848 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004849}
4850
4851void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004852 ScratchRegisterScope ensure_scratch(
4853 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4854 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4855 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4856 __ movl(temp_reg, Address(ESP, src + stack_offset));
4857 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4858 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4859 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004860}
4861
4862void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004863 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004864 Location source = move->GetSource();
4865 Location destination = move->GetDestination();
4866
4867 if (source.IsRegister()) {
4868 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004869 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004870 } else {
4871 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004872 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004873 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004874 } else if (source.IsFpuRegister()) {
4875 if (destination.IsFpuRegister()) {
4876 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4877 } else if (destination.IsStackSlot()) {
4878 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4879 } else {
4880 DCHECK(destination.IsDoubleStackSlot());
4881 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4882 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004883 } else if (source.IsStackSlot()) {
4884 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004885 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004886 } else if (destination.IsFpuRegister()) {
4887 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004888 } else {
4889 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004890 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4891 }
4892 } else if (source.IsDoubleStackSlot()) {
4893 if (destination.IsFpuRegister()) {
4894 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4895 } else {
4896 DCHECK(destination.IsDoubleStackSlot()) << destination;
4897 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004898 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004899 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004900 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004901 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004902 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004903 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004904 if (value == 0) {
4905 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4906 } else {
4907 __ movl(destination.AsRegister<Register>(), Immediate(value));
4908 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004909 } else {
4910 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05004911 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004912 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004913 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004914 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004915 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004916 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004917 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004918 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4919 if (value == 0) {
4920 // Easy handling of 0.0.
4921 __ xorps(dest, dest);
4922 } else {
4923 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004924 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4925 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4926 __ movl(temp, Immediate(value));
4927 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004928 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004929 } else {
4930 DCHECK(destination.IsStackSlot()) << destination;
4931 __ movl(Address(ESP, destination.GetStackIndex()), imm);
4932 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004933 } else if (constant->IsLongConstant()) {
4934 int64_t value = constant->AsLongConstant()->GetValue();
4935 int32_t low_value = Low32Bits(value);
4936 int32_t high_value = High32Bits(value);
4937 Immediate low(low_value);
4938 Immediate high(high_value);
4939 if (destination.IsDoubleStackSlot()) {
4940 __ movl(Address(ESP, destination.GetStackIndex()), low);
4941 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4942 } else {
4943 __ movl(destination.AsRegisterPairLow<Register>(), low);
4944 __ movl(destination.AsRegisterPairHigh<Register>(), high);
4945 }
4946 } else {
4947 DCHECK(constant->IsDoubleConstant());
4948 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004949 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004950 int32_t low_value = Low32Bits(value);
4951 int32_t high_value = High32Bits(value);
4952 Immediate low(low_value);
4953 Immediate high(high_value);
4954 if (destination.IsFpuRegister()) {
4955 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4956 if (value == 0) {
4957 // Easy handling of 0.0.
4958 __ xorpd(dest, dest);
4959 } else {
4960 __ pushl(high);
4961 __ pushl(low);
4962 __ movsd(dest, Address(ESP, 0));
4963 __ addl(ESP, Immediate(8));
4964 }
4965 } else {
4966 DCHECK(destination.IsDoubleStackSlot()) << destination;
4967 __ movl(Address(ESP, destination.GetStackIndex()), low);
4968 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4969 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004970 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004971 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00004972 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004973 }
4974}
4975
Mark Mendella5c19ce2015-04-01 12:51:05 -04004976void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004977 Register suggested_scratch = reg == EAX ? EBX : EAX;
4978 ScratchRegisterScope ensure_scratch(
4979 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4980
4981 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4982 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4983 __ movl(Address(ESP, mem + stack_offset), reg);
4984 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004985}
4986
Mark Mendell7c8d0092015-01-26 11:21:33 -05004987void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004988 ScratchRegisterScope ensure_scratch(
4989 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4990
4991 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4992 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4993 __ movl(temp_reg, Address(ESP, mem + stack_offset));
4994 __ movss(Address(ESP, mem + stack_offset), reg);
4995 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004996}
4997
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004998void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004999 ScratchRegisterScope ensure_scratch1(
5000 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005001
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005002 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
5003 ScratchRegisterScope ensure_scratch2(
5004 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005005
Guillaume Sancheze14590b2015-04-15 18:57:27 +00005006 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
5007 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
5008 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
5009 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
5010 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
5011 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005012}
5013
5014void ParallelMoveResolverX86::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005015 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005016 Location source = move->GetSource();
5017 Location destination = move->GetDestination();
5018
5019 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04005020 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
5021 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
5022 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
5023 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
5024 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005025 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005026 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005027 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005028 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005029 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5030 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05005031 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5032 // Use XOR Swap algorithm to avoid a temporary.
5033 DCHECK_NE(source.reg(), destination.reg());
5034 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
5035 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5036 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
5037 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
5038 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
5039 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
5040 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005041 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
5042 // Take advantage of the 16 bytes in the XMM register.
5043 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
5044 Address stack(ESP, destination.GetStackIndex());
5045 // Load the double into the high doubleword.
5046 __ movhpd(reg, stack);
5047
5048 // Store the low double into the destination.
5049 __ movsd(stack, reg);
5050
5051 // Move the high double to the low double.
5052 __ psrldq(reg, Immediate(8));
5053 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
5054 // Take advantage of the 16 bytes in the XMM register.
5055 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
5056 Address stack(ESP, source.GetStackIndex());
5057 // Load the double into the high doubleword.
5058 __ movhpd(reg, stack);
5059
5060 // Store the low double into the destination.
5061 __ movsd(stack, reg);
5062
5063 // Move the high double to the low double.
5064 __ psrldq(reg, Immediate(8));
5065 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
5066 Exchange(destination.GetStackIndex(), source.GetStackIndex());
5067 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005068 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05005069 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005070 }
5071}
5072
5073void ParallelMoveResolverX86::SpillScratch(int reg) {
5074 __ pushl(static_cast<Register>(reg));
5075}
5076
5077void ParallelMoveResolverX86::RestoreScratch(int reg) {
5078 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005079}
5080
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005081void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005082 InvokeRuntimeCallingConvention calling_convention;
5083 CodeGenerator::CreateLoadClassLocationSummary(
5084 cls,
5085 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5086 Location::RegisterLocation(EAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005087}
5088
5089void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005090 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005091 if (cls->NeedsAccessCheck()) {
5092 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5093 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5094 cls,
5095 cls->GetDexPc(),
5096 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01005097 return;
5098 }
5099
5100 Register out = locations->Out().AsRegister<Register>();
5101 Register current_method = locations->InAt(0).AsRegister<Register>();
5102 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005103 DCHECK(!cls->CanCallRuntime());
5104 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07005105 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005106 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005107 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005108 __ movl(out, Address(
Vladimir Marko05792b92015-08-03 11:56:49 +01005109 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005110 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005111 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005112
Andreas Gampe85b62f22015-09-09 13:15:38 -07005113 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005114 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5115 codegen_->AddSlowPath(slow_path);
5116 __ testl(out, out);
5117 __ j(kEqual, slow_path->GetEntryLabel());
5118 if (cls->MustGenerateClinitCheck()) {
5119 GenerateClassInitializationCheck(slow_path, out);
5120 } else {
5121 __ Bind(slow_path->GetExitLabel());
5122 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005123 }
5124}
5125
5126void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
5127 LocationSummary* locations =
5128 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5129 locations->SetInAt(0, Location::RequiresRegister());
5130 if (check->HasUses()) {
5131 locations->SetOut(Location::SameAsFirstInput());
5132 }
5133}
5134
5135void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005136 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005137 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005138 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005139 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005140 GenerateClassInitializationCheck(slow_path,
5141 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005142}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005143
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005144void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005145 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005146 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5147 Immediate(mirror::Class::kStatusInitialized));
5148 __ j(kLess, slow_path->GetEntryLabel());
5149 __ Bind(slow_path->GetExitLabel());
5150 // No need for memory fence, thanks to the X86 memory model.
5151}
5152
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005153void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
5154 LocationSummary* locations =
5155 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005156 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005157 locations->SetOut(Location::RequiresRegister());
5158}
5159
5160void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005161 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005162 codegen_->AddSlowPath(slow_path);
5163
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005164 LocationSummary* locations = load->GetLocations();
5165 Register out = locations->Out().AsRegister<Register>();
5166 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07005167 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08005168 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005169 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005170 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005171 __ testl(out, out);
5172 __ j(kEqual, slow_path->GetEntryLabel());
5173 __ Bind(slow_path->GetExitLabel());
5174}
5175
David Brazdilcb1c0552015-08-04 16:22:25 +01005176static Address GetExceptionTlsAddress() {
5177 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
5178}
5179
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005180void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
5181 LocationSummary* locations =
5182 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5183 locations->SetOut(Location::RequiresRegister());
5184}
5185
5186void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005187 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
5188}
5189
5190void LocationsBuilderX86::VisitClearException(HClearException* clear) {
5191 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5192}
5193
5194void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5195 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005196}
5197
5198void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
5199 LocationSummary* locations =
5200 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5201 InvokeRuntimeCallingConvention calling_convention;
5202 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5203}
5204
5205void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005206 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5207 instruction,
5208 instruction->GetDexPc(),
5209 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005210}
5211
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005212void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005213 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5214 switch (instruction->GetTypeCheckKind()) {
5215 case TypeCheckKind::kExactCheck:
5216 case TypeCheckKind::kAbstractClassCheck:
5217 case TypeCheckKind::kClassHierarchyCheck:
5218 case TypeCheckKind::kArrayObjectCheck:
5219 call_kind = LocationSummary::kNoCall;
5220 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005221 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005222 case TypeCheckKind::kInterfaceCheck:
5223 call_kind = LocationSummary::kCall;
5224 break;
5225 case TypeCheckKind::kArrayCheck:
5226 call_kind = LocationSummary::kCallOnSlowPath;
5227 break;
5228 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005229 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005230 if (call_kind != LocationSummary::kCall) {
5231 locations->SetInAt(0, Location::RequiresRegister());
5232 locations->SetInAt(1, Location::Any());
5233 // Note that TypeCheckSlowPathX86 uses this register too.
5234 locations->SetOut(Location::RequiresRegister());
5235 } else {
5236 InvokeRuntimeCallingConvention calling_convention;
5237 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5238 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5239 locations->SetOut(Location::RegisterLocation(EAX));
5240 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005241}
5242
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005243void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005244 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005245 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005246 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005247 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005248 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005249 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5250 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5251 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005252 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005253 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005254
5255 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005256 // Avoid null check if we know obj is not null.
5257 if (instruction->MustDoNullCheck()) {
5258 __ testl(obj, obj);
5259 __ j(kEqual, &zero);
5260 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005261
Calin Juravle98893e12015-10-02 21:05:03 +01005262 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005263 // This is safe, as the register is caller-save, and the object must be in another
5264 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01005265 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
5266 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005267 ? obj
5268 : out;
5269 __ movl(target, Address(obj, class_offset));
5270 __ MaybeUnpoisonHeapReference(target);
5271
5272 switch (instruction->GetTypeCheckKind()) {
5273 case TypeCheckKind::kExactCheck: {
5274 if (cls.IsRegister()) {
5275 __ cmpl(out, cls.AsRegister<Register>());
5276 } else {
5277 DCHECK(cls.IsStackSlot()) << cls;
5278 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5279 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005280
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005281 // Classes must be equal for the instanceof to succeed.
5282 __ j(kNotEqual, &zero);
5283 __ movl(out, Immediate(1));
5284 __ jmp(&done);
5285 break;
5286 }
5287 case TypeCheckKind::kAbstractClassCheck: {
5288 // If the class is abstract, we eagerly fetch the super class of the
5289 // object to avoid doing a comparison we know will fail.
5290 NearLabel loop;
5291 __ Bind(&loop);
5292 __ movl(out, Address(out, super_offset));
5293 __ MaybeUnpoisonHeapReference(out);
5294 __ testl(out, out);
5295 // If `out` is null, we use it for the result, and jump to `done`.
5296 __ j(kEqual, &done);
5297 if (cls.IsRegister()) {
5298 __ cmpl(out, cls.AsRegister<Register>());
5299 } else {
5300 DCHECK(cls.IsStackSlot()) << cls;
5301 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5302 }
5303 __ j(kNotEqual, &loop);
5304 __ movl(out, Immediate(1));
5305 if (zero.IsLinked()) {
5306 __ jmp(&done);
5307 }
5308 break;
5309 }
5310 case TypeCheckKind::kClassHierarchyCheck: {
5311 // Walk over the class hierarchy to find a match.
5312 NearLabel loop, success;
5313 __ Bind(&loop);
5314 if (cls.IsRegister()) {
5315 __ cmpl(out, cls.AsRegister<Register>());
5316 } else {
5317 DCHECK(cls.IsStackSlot()) << cls;
5318 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5319 }
5320 __ j(kEqual, &success);
5321 __ movl(out, Address(out, super_offset));
5322 __ MaybeUnpoisonHeapReference(out);
5323 __ testl(out, out);
5324 __ j(kNotEqual, &loop);
5325 // If `out` is null, we use it for the result, and jump to `done`.
5326 __ jmp(&done);
5327 __ Bind(&success);
5328 __ movl(out, Immediate(1));
5329 if (zero.IsLinked()) {
5330 __ jmp(&done);
5331 }
5332 break;
5333 }
5334 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005335 // Do an exact check.
5336 NearLabel exact_check;
5337 if (cls.IsRegister()) {
5338 __ cmpl(out, cls.AsRegister<Register>());
5339 } else {
5340 DCHECK(cls.IsStackSlot()) << cls;
5341 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5342 }
5343 __ j(kEqual, &exact_check);
5344 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005345 __ movl(out, Address(out, component_offset));
5346 __ MaybeUnpoisonHeapReference(out);
5347 __ testl(out, out);
5348 // If `out` is null, we use it for the result, and jump to `done`.
5349 __ j(kEqual, &done);
5350 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5351 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005352 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005353 __ movl(out, Immediate(1));
5354 __ jmp(&done);
5355 break;
5356 }
5357 case TypeCheckKind::kArrayCheck: {
5358 if (cls.IsRegister()) {
5359 __ cmpl(out, cls.AsRegister<Register>());
5360 } else {
5361 DCHECK(cls.IsStackSlot()) << cls;
5362 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5363 }
5364 DCHECK(locations->OnlyCallsOnSlowPath());
5365 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5366 instruction, /* is_fatal */ false);
5367 codegen_->AddSlowPath(slow_path);
5368 __ j(kNotEqual, slow_path->GetEntryLabel());
5369 __ movl(out, Immediate(1));
5370 if (zero.IsLinked()) {
5371 __ jmp(&done);
5372 }
5373 break;
5374 }
Calin Juravle98893e12015-10-02 21:05:03 +01005375 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005376 case TypeCheckKind::kInterfaceCheck:
5377 default: {
5378 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5379 instruction,
5380 instruction->GetDexPc(),
5381 nullptr);
5382 if (zero.IsLinked()) {
5383 __ jmp(&done);
5384 }
5385 break;
5386 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005387 }
5388
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005389 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005390 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005391 __ xorl(out, out);
5392 }
5393
5394 if (done.IsLinked()) {
5395 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005396 }
5397
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005398 if (slow_path != nullptr) {
5399 __ Bind(slow_path->GetExitLabel());
5400 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005401}
5402
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005403void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005404 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5405 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5406
5407 switch (instruction->GetTypeCheckKind()) {
5408 case TypeCheckKind::kExactCheck:
5409 case TypeCheckKind::kAbstractClassCheck:
5410 case TypeCheckKind::kClassHierarchyCheck:
5411 case TypeCheckKind::kArrayObjectCheck:
5412 call_kind = throws_into_catch
5413 ? LocationSummary::kCallOnSlowPath
5414 : LocationSummary::kNoCall;
5415 break;
5416 case TypeCheckKind::kInterfaceCheck:
Calin Juravle98893e12015-10-02 21:05:03 +01005417 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005418 call_kind = LocationSummary::kCall;
5419 break;
5420 case TypeCheckKind::kArrayCheck:
5421 call_kind = LocationSummary::kCallOnSlowPath;
5422 break;
5423 }
5424
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005425 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005426 instruction, call_kind);
5427 if (call_kind != LocationSummary::kCall) {
5428 locations->SetInAt(0, Location::RequiresRegister());
5429 locations->SetInAt(1, Location::Any());
5430 // Note that TypeCheckSlowPathX86 uses this register too.
5431 locations->AddTemp(Location::RequiresRegister());
5432 } else {
5433 InvokeRuntimeCallingConvention calling_convention;
5434 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5435 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5436 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005437}
5438
5439void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
5440 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005441 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005442 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005443 Register temp = locations->WillCall()
5444 ? kNoRegister
5445 : locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005446
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005447 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5448 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5449 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5450 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5451 SlowPathCode* slow_path = nullptr;
5452
5453 if (!locations->WillCall()) {
5454 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5455 instruction, !locations->CanCall());
5456 codegen_->AddSlowPath(slow_path);
5457 }
5458
5459 NearLabel done, abstract_entry;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005460 // Avoid null check if we know obj is not null.
5461 if (instruction->MustDoNullCheck()) {
5462 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005463 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005464 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005465
5466 if (locations->WillCall()) {
5467 __ movl(obj, Address(obj, class_offset));
5468 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005469 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005470 __ movl(temp, Address(obj, class_offset));
5471 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005472 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005473
5474 switch (instruction->GetTypeCheckKind()) {
5475 case TypeCheckKind::kExactCheck:
5476 case TypeCheckKind::kArrayCheck: {
5477 if (cls.IsRegister()) {
5478 __ cmpl(temp, cls.AsRegister<Register>());
5479 } else {
5480 DCHECK(cls.IsStackSlot()) << cls;
5481 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5482 }
5483 // Jump to slow path for throwing the exception or doing a
5484 // more involved array check.
5485 __ j(kNotEqual, slow_path->GetEntryLabel());
5486 break;
5487 }
5488 case TypeCheckKind::kAbstractClassCheck: {
5489 // If the class is abstract, we eagerly fetch the super class of the
5490 // object to avoid doing a comparison we know will fail.
5491 NearLabel loop, success;
5492 __ Bind(&loop);
5493 __ movl(temp, Address(temp, super_offset));
5494 __ MaybeUnpoisonHeapReference(temp);
5495 __ testl(temp, temp);
5496 // Jump to the slow path to throw the exception.
5497 __ j(kEqual, slow_path->GetEntryLabel());
5498 if (cls.IsRegister()) {
5499 __ cmpl(temp, cls.AsRegister<Register>());
5500 } else {
5501 DCHECK(cls.IsStackSlot()) << cls;
5502 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5503 }
5504 __ j(kNotEqual, &loop);
5505 break;
5506 }
5507 case TypeCheckKind::kClassHierarchyCheck: {
5508 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005509 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005510 __ Bind(&loop);
5511 if (cls.IsRegister()) {
5512 __ cmpl(temp, cls.AsRegister<Register>());
5513 } else {
5514 DCHECK(cls.IsStackSlot()) << cls;
5515 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5516 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005517 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005518 __ movl(temp, Address(temp, super_offset));
5519 __ MaybeUnpoisonHeapReference(temp);
5520 __ testl(temp, temp);
5521 __ j(kNotEqual, &loop);
5522 // Jump to the slow path to throw the exception.
5523 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005524 break;
5525 }
5526 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005527 // Do an exact check.
5528 if (cls.IsRegister()) {
5529 __ cmpl(temp, cls.AsRegister<Register>());
5530 } else {
5531 DCHECK(cls.IsStackSlot()) << cls;
5532 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5533 }
5534 __ j(kEqual, &done);
5535 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005536 __ movl(temp, Address(temp, component_offset));
5537 __ MaybeUnpoisonHeapReference(temp);
5538 __ testl(temp, temp);
5539 __ j(kEqual, slow_path->GetEntryLabel());
5540 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5541 __ j(kNotEqual, slow_path->GetEntryLabel());
5542 break;
5543 }
Calin Juravle98893e12015-10-02 21:05:03 +01005544 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005545 case TypeCheckKind::kInterfaceCheck:
5546 default:
5547 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5548 instruction,
5549 instruction->GetDexPc(),
5550 nullptr);
5551 break;
5552 }
5553 __ Bind(&done);
5554
5555 if (slow_path != nullptr) {
5556 __ Bind(slow_path->GetExitLabel());
5557 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005558}
5559
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005560void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
5561 LocationSummary* locations =
5562 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5563 InvokeRuntimeCallingConvention calling_convention;
5564 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5565}
5566
5567void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005568 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5569 : QUICK_ENTRY_POINT(pUnlockObject),
5570 instruction,
5571 instruction->GetDexPc(),
5572 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005573}
5574
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005575void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5576void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5577void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5578
5579void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5580 LocationSummary* locations =
5581 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5582 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5583 || instruction->GetResultType() == Primitive::kPrimLong);
5584 locations->SetInAt(0, Location::RequiresRegister());
5585 locations->SetInAt(1, Location::Any());
5586 locations->SetOut(Location::SameAsFirstInput());
5587}
5588
5589void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
5590 HandleBitwiseOperation(instruction);
5591}
5592
5593void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
5594 HandleBitwiseOperation(instruction);
5595}
5596
5597void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
5598 HandleBitwiseOperation(instruction);
5599}
5600
5601void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5602 LocationSummary* locations = instruction->GetLocations();
5603 Location first = locations->InAt(0);
5604 Location second = locations->InAt(1);
5605 DCHECK(first.Equals(locations->Out()));
5606
5607 if (instruction->GetResultType() == Primitive::kPrimInt) {
5608 if (second.IsRegister()) {
5609 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005610 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005611 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005612 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005613 } else {
5614 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005615 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005616 }
5617 } else if (second.IsConstant()) {
5618 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005619 __ andl(first.AsRegister<Register>(),
5620 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005621 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005622 __ orl(first.AsRegister<Register>(),
5623 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005624 } else {
5625 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00005626 __ xorl(first.AsRegister<Register>(),
5627 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005628 }
5629 } else {
5630 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005631 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005632 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005633 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005634 } else {
5635 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005636 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005637 }
5638 }
5639 } else {
5640 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5641 if (second.IsRegisterPair()) {
5642 if (instruction->IsAnd()) {
5643 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5644 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5645 } else if (instruction->IsOr()) {
5646 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5647 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5648 } else {
5649 DCHECK(instruction->IsXor());
5650 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5651 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5652 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005653 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005654 if (instruction->IsAnd()) {
5655 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5656 __ andl(first.AsRegisterPairHigh<Register>(),
5657 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5658 } else if (instruction->IsOr()) {
5659 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5660 __ orl(first.AsRegisterPairHigh<Register>(),
5661 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5662 } else {
5663 DCHECK(instruction->IsXor());
5664 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5665 __ xorl(first.AsRegisterPairHigh<Register>(),
5666 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5667 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005668 } else {
5669 DCHECK(second.IsConstant()) << second;
5670 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005671 int32_t low_value = Low32Bits(value);
5672 int32_t high_value = High32Bits(value);
5673 Immediate low(low_value);
5674 Immediate high(high_value);
5675 Register first_low = first.AsRegisterPairLow<Register>();
5676 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005677 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005678 if (low_value == 0) {
5679 __ xorl(first_low, first_low);
5680 } else if (low_value != -1) {
5681 __ andl(first_low, low);
5682 }
5683 if (high_value == 0) {
5684 __ xorl(first_high, first_high);
5685 } else if (high_value != -1) {
5686 __ andl(first_high, high);
5687 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005688 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005689 if (low_value != 0) {
5690 __ orl(first_low, low);
5691 }
5692 if (high_value != 0) {
5693 __ orl(first_high, high);
5694 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005695 } else {
5696 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005697 if (low_value != 0) {
5698 __ xorl(first_low, low);
5699 }
5700 if (high_value != 0) {
5701 __ xorl(first_high, high);
5702 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005703 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005704 }
5705 }
5706}
5707
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005708void LocationsBuilderX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005709 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005710 LOG(FATAL) << "Unreachable";
5711}
5712
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005713void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005714 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005715 LOG(FATAL) << "Unreachable";
5716}
5717
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005718void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
5719 DCHECK(codegen_->IsBaseline());
5720 LocationSummary* locations =
5721 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5722 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5723}
5724
5725void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5726 DCHECK(codegen_->IsBaseline());
5727 // Will be generated at use site.
5728}
5729
Mark Mendellfe57faa2015-09-18 09:26:15 -04005730// Simple implementation of packed switch - generate cascaded compare/jumps.
5731void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5732 LocationSummary* locations =
5733 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5734 locations->SetInAt(0, Location::RequiresRegister());
5735}
5736
5737void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5738 int32_t lower_bound = switch_instr->GetStartValue();
5739 int32_t num_entries = switch_instr->GetNumEntries();
5740 LocationSummary* locations = switch_instr->GetLocations();
5741 Register value_reg = locations->InAt(0).AsRegister<Register>();
5742 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5743
5744 // Create a series of compare/jumps.
5745 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5746 for (int i = 0; i < num_entries; i++) {
5747 int32_t case_value = lower_bound + i;
5748 if (case_value == 0) {
5749 __ testl(value_reg, value_reg);
5750 } else {
5751 __ cmpl(value_reg, Immediate(case_value));
5752 }
Vladimir Markoec7802a2015-10-01 20:57:57 +01005753 __ j(kEqual, codegen_->GetLabelOf(successors[i]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005754 }
5755
5756 // And the default for any other value.
5757 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5758 __ jmp(codegen_->GetLabelOf(default_block));
5759 }
5760}
5761
Mark Mendell805b3b52015-09-18 14:10:29 -04005762void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5763 LocationSummary* locations =
5764 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5765 locations->SetInAt(0, Location::RequiresRegister());
5766
5767 // Constant area pointer.
5768 locations->SetInAt(1, Location::RequiresRegister());
5769
5770 // And the temporary we need.
5771 locations->AddTemp(Location::RequiresRegister());
5772}
5773
5774void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5775 int32_t lower_bound = switch_instr->GetStartValue();
5776 int32_t num_entries = switch_instr->GetNumEntries();
5777 LocationSummary* locations = switch_instr->GetLocations();
5778 Register value_reg = locations->InAt(0).AsRegister<Register>();
5779 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5780
5781 // Optimizing has a jump area.
5782 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5783 Register constant_area = locations->InAt(1).AsRegister<Register>();
5784
5785 // Remove the bias, if needed.
5786 if (lower_bound != 0) {
5787 __ leal(temp_reg, Address(value_reg, -lower_bound));
5788 value_reg = temp_reg;
5789 }
5790
5791 // Is the value in range?
5792 DCHECK_GE(num_entries, 1);
5793 __ cmpl(value_reg, Immediate(num_entries - 1));
5794 __ j(kAbove, codegen_->GetLabelOf(default_block));
5795
5796 // We are in the range of the table.
5797 // Load (target-constant_area) from the jump table, indexing by the value.
5798 __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
5799
5800 // Compute the actual target address by adding in constant_area.
5801 __ addl(temp_reg, constant_area);
5802
5803 // And jump.
5804 __ jmp(temp_reg);
5805}
5806
Mark Mendell0616ae02015-04-17 12:49:27 -04005807void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
5808 HX86ComputeBaseMethodAddress* insn) {
5809 LocationSummary* locations =
5810 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5811 locations->SetOut(Location::RequiresRegister());
5812}
5813
5814void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
5815 HX86ComputeBaseMethodAddress* insn) {
5816 LocationSummary* locations = insn->GetLocations();
5817 Register reg = locations->Out().AsRegister<Register>();
5818
5819 // Generate call to next instruction.
5820 Label next_instruction;
5821 __ call(&next_instruction);
5822 __ Bind(&next_instruction);
5823
5824 // Remember this offset for later use with constant area.
5825 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
5826
5827 // Grab the return address off the stack.
5828 __ popl(reg);
5829}
5830
5831void LocationsBuilderX86::VisitX86LoadFromConstantTable(
5832 HX86LoadFromConstantTable* insn) {
5833 LocationSummary* locations =
5834 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5835
5836 locations->SetInAt(0, Location::RequiresRegister());
5837 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
5838
5839 // If we don't need to be materialized, we only need the inputs to be set.
5840 if (!insn->NeedsMaterialization()) {
5841 return;
5842 }
5843
5844 switch (insn->GetType()) {
5845 case Primitive::kPrimFloat:
5846 case Primitive::kPrimDouble:
5847 locations->SetOut(Location::RequiresFpuRegister());
5848 break;
5849
5850 case Primitive::kPrimInt:
5851 locations->SetOut(Location::RequiresRegister());
5852 break;
5853
5854 default:
5855 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5856 }
5857}
5858
5859void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
5860 if (!insn->NeedsMaterialization()) {
5861 return;
5862 }
5863
5864 LocationSummary* locations = insn->GetLocations();
5865 Location out = locations->Out();
5866 Register const_area = locations->InAt(0).AsRegister<Register>();
5867 HConstant *value = insn->GetConstant();
5868
5869 switch (insn->GetType()) {
5870 case Primitive::kPrimFloat:
5871 __ movss(out.AsFpuRegister<XmmRegister>(),
5872 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
5873 break;
5874
5875 case Primitive::kPrimDouble:
5876 __ movsd(out.AsFpuRegister<XmmRegister>(),
5877 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
5878 break;
5879
5880 case Primitive::kPrimInt:
5881 __ movl(out.AsRegister<Register>(),
5882 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
5883 break;
5884
5885 default:
5886 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5887 }
5888}
5889
Mark Mendell0616ae02015-04-17 12:49:27 -04005890/**
5891 * Class to handle late fixup of offsets into constant area.
5892 */
Vladimir Marko5233f932015-09-29 19:01:15 +01005893class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendell0616ae02015-04-17 12:49:27 -04005894 public:
Mark Mendell805b3b52015-09-18 14:10:29 -04005895 RIPFixup(CodeGeneratorX86& codegen, size_t offset)
5896 : codegen_(&codegen), offset_into_constant_area_(offset) {}
5897
5898 protected:
5899 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
5900
5901 CodeGeneratorX86* codegen_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005902
5903 private:
5904 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5905 // Patch the correct offset for the instruction. The place to patch is the
5906 // last 4 bytes of the instruction.
5907 // The value to patch is the distance from the offset in the constant area
5908 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
Mark Mendell805b3b52015-09-18 14:10:29 -04005909 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
5910 int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();;
Mark Mendell0616ae02015-04-17 12:49:27 -04005911
5912 // Patch in the right value.
5913 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5914 }
5915
Mark Mendell0616ae02015-04-17 12:49:27 -04005916 // Location in constant area that the fixup refers to.
Mark Mendell805b3b52015-09-18 14:10:29 -04005917 int32_t offset_into_constant_area_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005918};
5919
Mark Mendell805b3b52015-09-18 14:10:29 -04005920/**
5921 * Class to handle late fixup of offsets to a jump table that will be created in the
5922 * constant area.
5923 */
5924class JumpTableRIPFixup : public RIPFixup {
5925 public:
5926 JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
5927 : RIPFixup(codegen, static_cast<size_t>(-1)), switch_instr_(switch_instr) {}
5928
5929 void CreateJumpTable() {
5930 X86Assembler* assembler = codegen_->GetAssembler();
5931
5932 // Ensure that the reference to the jump table has the correct offset.
5933 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
5934 SetOffset(offset_in_constant_table);
5935
5936 // The label values in the jump table are computed relative to the
5937 // instruction addressing the constant area.
5938 const int32_t relative_offset = codegen_->GetMethodAddressOffset();
5939
5940 // Populate the jump table with the correct values for the jump table.
5941 int32_t num_entries = switch_instr_->GetNumEntries();
5942 HBasicBlock* block = switch_instr_->GetBlock();
5943 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
5944 // The value that we want is the target offset - the position of the table.
5945 for (int32_t i = 0; i < num_entries; i++) {
5946 HBasicBlock* b = successors[i];
5947 Label* l = codegen_->GetLabelOf(b);
5948 DCHECK(l->IsBound());
5949 int32_t offset_to_block = l->Position() - relative_offset;
5950 assembler->AppendInt32(offset_to_block);
5951 }
5952 }
5953
5954 private:
5955 const HX86PackedSwitch* switch_instr_;
5956};
5957
5958void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
5959 // Generate the constant area if needed.
5960 X86Assembler* assembler = GetAssembler();
5961 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
5962 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5963 // byte values.
5964 assembler->Align(4, 0);
5965 constant_area_start_ = assembler->CodeSize();
5966
5967 // Populate any jump tables.
5968 for (auto jump_table : fixups_to_jump_tables_) {
5969 jump_table->CreateJumpTable();
5970 }
5971
5972 // And now add the constant area to the generated code.
5973 assembler->AddConstantArea();
5974 }
5975
5976 // And finish up.
5977 CodeGenerator::Finalize(allocator);
5978}
5979
Mark Mendell0616ae02015-04-17 12:49:27 -04005980Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
5981 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5982 return Address(reg, kDummy32BitOffset, fixup);
5983}
5984
5985Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
5986 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5987 return Address(reg, kDummy32BitOffset, fixup);
5988}
5989
5990Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
5991 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5992 return Address(reg, kDummy32BitOffset, fixup);
5993}
5994
5995Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
5996 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5997 return Address(reg, kDummy32BitOffset, fixup);
5998}
5999
Mark Mendell805b3b52015-09-18 14:10:29 -04006000Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
6001 Register reg,
6002 Register value) {
6003 // Create a fixup to be used to create and address the jump table.
6004 JumpTableRIPFixup* table_fixup =
6005 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
6006
6007 // We have to populate the jump tables.
6008 fixups_to_jump_tables_.push_back(table_fixup);
6009
6010 // We want a scaled address, as we are extracting the correct offset from the table.
6011 return Address(reg, value, TIMES_4, kDummy32BitOffset, table_fixup);
6012}
6013
Andreas Gampe85b62f22015-09-09 13:15:38 -07006014// TODO: target as memory.
6015void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
6016 if (!target.IsValid()) {
6017 DCHECK(type == Primitive::kPrimVoid);
6018 return;
6019 }
6020
6021 DCHECK_NE(type, Primitive::kPrimVoid);
6022
6023 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
6024 if (target.Equals(return_loc)) {
6025 return;
6026 }
6027
6028 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6029 // with the else branch.
6030 if (type == Primitive::kPrimLong) {
6031 HParallelMove parallel_move(GetGraph()->GetArena());
6032 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
6033 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
6034 GetMoveResolver()->EmitNativeCode(&parallel_move);
6035 } else {
6036 // Let the parallel move resolver take care of all of this.
6037 HParallelMove parallel_move(GetGraph()->GetArena());
6038 parallel_move.AddMove(return_loc, target, type, nullptr);
6039 GetMoveResolver()->EmitNativeCode(&parallel_move);
6040 }
6041}
6042
Roland Levillain4d027112015-07-01 15:41:14 +01006043#undef __
6044
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006045} // namespace x86
6046} // namespace art